aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2020-01-17 20:45:01 +0000
committerDimitry Andric <dim@FreeBSD.org>2020-01-17 20:45:01 +0000
commit706b4fc47bbc608932d3b491ae19a3b9cde9497b (patch)
tree4adf86a776049cbf7f69a1929c4babcbbef925eb /clang/lib
parent7cc9cf2bf09f069cb2dd947ead05d0b54301fb71 (diff)
Notes
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/ARCMigrate/ObjCMT.cpp4
-rw-r--r--clang/lib/AST/ASTConcept.cpp55
-rw-r--r--clang/lib/AST/ASTContext.cpp357
-rw-r--r--clang/lib/AST/ASTDiagnostic.cpp23
-rw-r--r--clang/lib/AST/ASTImporter.cpp437
-rw-r--r--clang/lib/AST/ASTTypeTraits.cpp1
-rw-r--r--clang/lib/AST/Comment.cpp6
-rw-r--r--clang/lib/AST/CommentSema.cpp53
-rw-r--r--clang/lib/AST/ComparisonCategories.cpp53
-rw-r--r--clang/lib/AST/Decl.cpp170
-rw-r--r--clang/lib/AST/DeclBase.cpp1
-rw-r--r--clang/lib/AST/DeclCXX.cpp173
-rw-r--r--clang/lib/AST/DeclObjC.cpp66
-rw-r--r--clang/lib/AST/DeclPrinter.cpp101
-rw-r--r--clang/lib/AST/DeclTemplate.cpp212
-rw-r--r--clang/lib/AST/DeclarationName.cpp25
-rw-r--r--clang/lib/AST/Expr.cpp117
-rw-r--r--clang/lib/AST/ExprCXX.cpp75
-rw-r--r--clang/lib/AST/ExprConstant.cpp561
-rw-r--r--clang/lib/AST/ExternalASTMerger.cpp4
-rw-r--r--clang/lib/AST/ExternalASTSource.cpp2
-rw-r--r--clang/lib/AST/Interp/ByteCodeStmtGen.cpp4
-rw-r--r--clang/lib/AST/Interp/Context.cpp64
-rw-r--r--clang/lib/AST/Interp/Context.h24
-rw-r--r--clang/lib/AST/Interp/Interp.h7
-rw-r--r--clang/lib/AST/ItaniumMangle.cpp12
-rw-r--r--clang/lib/AST/JSONNodeDumper.cpp29
-rw-r--r--clang/lib/AST/Mangle.cpp4
-rw-r--r--clang/lib/AST/MicrosoftCXXABI.cpp34
-rw-r--r--clang/lib/AST/MicrosoftMangle.cpp77
-rw-r--r--clang/lib/AST/NestedNameSpecifier.cpp6
-rw-r--r--clang/lib/AST/ODRHash.cpp5
-rw-r--r--clang/lib/AST/OpenMPClause.cpp57
-rw-r--r--clang/lib/AST/QualTypeNames.cpp2
-rw-r--r--clang/lib/AST/RecordLayoutBuilder.cpp6
-rw-r--r--clang/lib/AST/Stmt.cpp6
-rw-r--r--clang/lib/AST/StmtOpenMP.cpp150
-rw-r--r--clang/lib/AST/StmtPrinter.cpp18
-rw-r--r--clang/lib/AST/StmtProfile.cpp18
-rw-r--r--clang/lib/AST/TextNodeDumper.cpp33
-rw-r--r--clang/lib/AST/Type.cpp19
-rw-r--r--clang/lib/AST/TypeLoc.cpp20
-rw-r--r--clang/lib/AST/TypePrinter.cpp85
-rw-r--r--clang/lib/AST/VTableBuilder.cpp4
-rw-r--r--clang/lib/ASTMatchers/ASTMatchFinder.cpp104
-rw-r--r--clang/lib/ASTMatchers/ASTMatchersInternal.cpp58
-rw-r--r--clang/lib/ASTMatchers/Dynamic/Parser.cpp78
-rw-r--r--clang/lib/ASTMatchers/Dynamic/Registry.cpp6
-rw-r--r--clang/lib/Analysis/BodyFarm.cpp103
-rw-r--r--clang/lib/Analysis/CFG.cpp51
-rw-r--r--clang/lib/Analysis/CloneDetection.cpp2
-rw-r--r--clang/lib/Analysis/Consumed.cpp2
-rw-r--r--clang/lib/Analysis/ReachableCode.cpp1
-rw-r--r--clang/lib/Analysis/ThreadSafety.cpp3
-rw-r--r--clang/lib/Analysis/ThreadSafetyCommon.cpp3
-rw-r--r--clang/lib/Basic/Builtins.cpp3
-rw-r--r--clang/lib/Basic/Diagnostic.cpp6
-rw-r--r--clang/lib/Basic/FileManager.cpp43
-rw-r--r--clang/lib/Basic/OpenMPKinds.cpp135
-rw-r--r--clang/lib/Basic/SanitizerBlacklist.cpp4
-rw-r--r--clang/lib/Basic/SanitizerSpecialCaseList.cpp8
-rw-r--r--clang/lib/Basic/SourceManager.cpp59
-rw-r--r--clang/lib/Basic/Targets.cpp7
-rw-r--r--clang/lib/Basic/Targets/AArch64.cpp63
-rw-r--r--clang/lib/Basic/Targets/AArch64.h5
-rw-r--r--clang/lib/Basic/Targets/AMDGPU.cpp11
-rw-r--r--clang/lib/Basic/Targets/ARM.cpp12
-rw-r--r--clang/lib/Basic/Targets/ARM.h3
-rw-r--r--clang/lib/Basic/Targets/BPF.h2
-rw-r--r--clang/lib/Basic/Targets/Hexagon.cpp5
-rw-r--r--clang/lib/Basic/Targets/Mips.cpp16
-rw-r--r--clang/lib/Basic/Targets/Mips.h2
-rw-r--r--clang/lib/Basic/Targets/NVPTX.h3
-rw-r--r--clang/lib/Basic/Targets/OSTargets.cpp2
-rw-r--r--clang/lib/Basic/Targets/OSTargets.h2
-rw-r--r--clang/lib/Basic/Targets/PPC.cpp43
-rw-r--r--clang/lib/Basic/Targets/PPC.h19
-rw-r--r--clang/lib/Basic/Targets/SPIR.h5
-rw-r--r--clang/lib/Basic/Targets/TCE.h5
-rw-r--r--clang/lib/Basic/Targets/X86.cpp38
-rw-r--r--clang/lib/Basic/Targets/X86.h44
-rw-r--r--clang/lib/Basic/Version.cpp5
-rw-r--r--clang/lib/Basic/XRayLists.cpp11
-rw-r--r--clang/lib/CodeGen/BackendUtil.cpp166
-rw-r--r--clang/lib/CodeGen/CGAtomic.cpp100
-rw-r--r--clang/lib/CodeGen/CGBlocks.cpp9
-rw-r--r--clang/lib/CodeGen/CGBuilder.h22
-rw-r--r--clang/lib/CodeGen/CGBuiltin.cpp603
-rw-r--r--clang/lib/CodeGen/CGCXX.cpp3
-rw-r--r--clang/lib/CodeGen/CGCXXABI.cpp1
-rw-r--r--clang/lib/CodeGen/CGCall.cpp115
-rw-r--r--clang/lib/CodeGen/CGCall.h548
-rw-r--r--clang/lib/CodeGen/CGClass.cpp34
-rw-r--r--clang/lib/CodeGen/CGDebugInfo.cpp329
-rw-r--r--clang/lib/CodeGen/CGDebugInfo.h39
-rw-r--r--clang/lib/CodeGen/CGDecl.cpp51
-rw-r--r--clang/lib/CodeGen/CGDeclCXX.cpp19
-rw-r--r--clang/lib/CodeGen/CGException.cpp5
-rw-r--r--clang/lib/CodeGen/CGExpr.cpp241
-rw-r--r--clang/lib/CodeGen/CGExprAgg.cpp76
-rw-r--r--clang/lib/CodeGen/CGExprCXX.cpp94
-rw-r--r--clang/lib/CodeGen/CGExprComplex.cpp15
-rw-r--r--clang/lib/CodeGen/CGExprConstant.cpp13
-rw-r--r--clang/lib/CodeGen/CGExprScalar.cpp209
-rw-r--r--clang/lib/CodeGen/CGLoopInfo.cpp29
-rw-r--r--clang/lib/CodeGen/CGNonTrivialStruct.cpp20
-rw-r--r--clang/lib/CodeGen/CGObjC.cpp147
-rw-r--r--clang/lib/CodeGen/CGObjCGNU.cpp33
-rw-r--r--clang/lib/CodeGen/CGObjCMac.cpp270
-rw-r--r--clang/lib/CodeGen/CGObjCRuntime.h21
-rw-r--r--clang/lib/CodeGen/CGOpenCLRuntime.cpp4
-rw-r--r--clang/lib/CodeGen/CGOpenMPRuntime.cpp1018
-rw-r--r--clang/lib/CodeGen/CGOpenMPRuntime.h142
-rw-r--r--clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp74
-rw-r--r--clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h2
-rw-r--r--clang/lib/CodeGen/CGStmt.cpp31
-rw-r--r--clang/lib/CodeGen/CGStmtOpenMP.cpp610
-rw-r--r--clang/lib/CodeGen/CGVTables.cpp10
-rw-r--r--clang/lib/CodeGen/CGValue.h25
-rw-r--r--clang/lib/CodeGen/CodeGenAction.cpp160
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.cpp134
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h40
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp192
-rw-r--r--clang/lib/CodeGen/CodeGenModule.h43
-rw-r--r--clang/lib/CodeGen/CodeGenPGO.cpp3
-rw-r--r--clang/lib/CodeGen/CodeGenTBAA.cpp17
-rw-r--r--clang/lib/CodeGen/ConstantEmitter.h2
-rw-r--r--clang/lib/CodeGen/CoverageMappingGen.cpp29
-rw-r--r--clang/lib/CodeGen/CoverageMappingGen.h8
-rw-r--r--clang/lib/CodeGen/ItaniumCXXABI.cpp30
-rw-r--r--clang/lib/CodeGen/MicrosoftCXXABI.cpp119
-rw-r--r--clang/lib/CodeGen/ModuleBuilder.cpp4
-rw-r--r--clang/lib/CodeGen/SanitizerMetadata.cpp1
-rw-r--r--clang/lib/CodeGen/TargetInfo.cpp300
-rw-r--r--clang/lib/Driver/Distro.cpp23
-rw-r--r--clang/lib/Driver/Driver.cpp149
-rw-r--r--clang/lib/Driver/Job.cpp106
-rw-r--r--clang/lib/Driver/OptionUtils.cpp47
-rw-r--r--clang/lib/Driver/SanitizerArgs.cpp32
-rw-r--r--clang/lib/Driver/ToolChain.cpp26
-rw-r--r--clang/lib/Driver/ToolChains/AIX.cpp159
-rw-r--r--clang/lib/Driver/ToolChains/AIX.h75
-rw-r--r--clang/lib/Driver/ToolChains/AMDGPU.h2
-rw-r--r--clang/lib/Driver/ToolChains/Arch/AArch64.cpp9
-rw-r--r--clang/lib/Driver/ToolChains/Arch/ARM.cpp47
-rw-r--r--clang/lib/Driver/ToolChains/Arch/PPC.cpp6
-rw-r--r--clang/lib/Driver/ToolChains/Arch/RISCV.cpp203
-rw-r--r--clang/lib/Driver/ToolChains/Arch/RISCV.h2
-rw-r--r--clang/lib/Driver/ToolChains/Arch/SystemZ.cpp18
-rw-r--r--clang/lib/Driver/ToolChains/Arch/SystemZ.h3
-rw-r--r--clang/lib/Driver/ToolChains/Arch/X86.cpp3
-rw-r--r--clang/lib/Driver/ToolChains/Clang.cpp866
-rw-r--r--clang/lib/Driver/ToolChains/CommonArgs.cpp141
-rw-r--r--clang/lib/Driver/ToolChains/CommonArgs.h11
-rw-r--r--clang/lib/Driver/ToolChains/Cuda.cpp3
-rw-r--r--clang/lib/Driver/ToolChains/Darwin.cpp105
-rw-r--r--clang/lib/Driver/ToolChains/Darwin.h10
-rw-r--r--clang/lib/Driver/ToolChains/Flang.cpp79
-rw-r--r--clang/lib/Driver/ToolChains/Flang.h46
-rw-r--r--clang/lib/Driver/ToolChains/FreeBSD.cpp38
-rw-r--r--clang/lib/Driver/ToolChains/FreeBSD.h7
-rw-r--r--clang/lib/Driver/ToolChains/Fuchsia.cpp25
-rw-r--r--clang/lib/Driver/ToolChains/Gnu.cpp215
-rw-r--r--clang/lib/Driver/ToolChains/Gnu.h9
-rw-r--r--clang/lib/Driver/ToolChains/HIP.cpp80
-rw-r--r--clang/lib/Driver/ToolChains/HIP.h2
-rw-r--r--clang/lib/Driver/ToolChains/Hexagon.cpp13
-rw-r--r--clang/lib/Driver/ToolChains/Hurd.cpp10
-rw-r--r--clang/lib/Driver/ToolChains/Hurd.h4
-rw-r--r--clang/lib/Driver/ToolChains/InterfaceStubs.cpp38
-rw-r--r--clang/lib/Driver/ToolChains/Linux.cpp76
-rw-r--r--clang/lib/Driver/ToolChains/Linux.h7
-rw-r--r--clang/lib/Driver/ToolChains/MSVC.cpp22
-rw-r--r--clang/lib/Driver/ToolChains/MinGW.cpp14
-rw-r--r--clang/lib/Driver/ToolChains/NetBSD.cpp6
-rw-r--r--clang/lib/Driver/ToolChains/OpenBSD.cpp9
-rw-r--r--clang/lib/Driver/ToolChains/OpenBSD.h5
-rw-r--r--clang/lib/Driver/ToolChains/PS4CPU.h4
-rw-r--r--clang/lib/Driver/ToolChains/RISCVToolchain.cpp92
-rw-r--r--clang/lib/Driver/ToolChains/RISCVToolchain.h4
-rw-r--r--clang/lib/Driver/ToolChains/WebAssembly.cpp64
-rw-r--r--clang/lib/Driver/Types.cpp26
-rw-r--r--clang/lib/Driver/XRayArgs.cpp13
-rw-r--r--clang/lib/Format/BreakableToken.cpp27
-rw-r--r--clang/lib/Format/BreakableToken.h20
-rw-r--r--clang/lib/Format/Format.cpp82
-rw-r--r--clang/lib/Format/FormatToken.h4
-rw-r--r--clang/lib/Format/FormatTokenLexer.cpp12
-rw-r--r--clang/lib/Format/NamespaceEndCommentsFixer.cpp20
-rw-r--r--clang/lib/Format/TokenAnnotator.cpp140
-rw-r--r--clang/lib/Format/UnwrappedLineFormatter.cpp13
-rw-r--r--clang/lib/Format/UnwrappedLineParser.cpp9
-rw-r--r--clang/lib/Frontend/ASTUnit.cpp4
-rw-r--r--clang/lib/Frontend/ChainedIncludesSource.cpp1
-rw-r--r--clang/lib/Frontend/CompilerInstance.cpp625
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp146
-rw-r--r--clang/lib/Frontend/CreateInvocationFromCommandLine.cpp5
-rw-r--r--clang/lib/Frontend/FrontendAction.cpp9
-rw-r--r--clang/lib/Frontend/FrontendActions.cpp8
-rw-r--r--clang/lib/Frontend/InitPreprocessor.cpp23
-rw-r--r--clang/lib/Frontend/InterfaceStubFunctionsConsumer.cpp49
-rw-r--r--clang/lib/Frontend/MultiplexConsumer.cpp5
-rw-r--r--clang/lib/Frontend/PrecompiledPreamble.cpp17
-rw-r--r--clang/lib/Frontend/Rewrite/FrontendActions.cpp8
-rw-r--r--clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp24
-rw-r--r--clang/lib/Frontend/Rewrite/RewriteObjC.cpp24
-rw-r--r--clang/lib/Frontend/TextDiagnostic.cpp23
-rw-r--r--clang/lib/Headers/altivec.h62
-rw-r--r--clang/lib/Headers/arm_acle.h26
-rw-r--r--clang/lib/Headers/arm_cmse.h217
-rw-r--r--clang/lib/Headers/avx512bwintrin.h12
-rw-r--r--clang/lib/Headers/avx512fintrin.h28
-rw-r--r--clang/lib/Headers/avx512vlbwintrin.h24
-rw-r--r--clang/lib/Headers/avx512vlintrin.h112
-rw-r--r--clang/lib/Headers/avxintrin.h10
-rw-r--r--clang/lib/Headers/emmintrin.h28
-rw-r--r--clang/lib/Headers/immintrin.h6
-rw-r--r--clang/lib/Headers/intrin.h26
-rw-r--r--clang/lib/Headers/mwaitxintrin.h4
-rw-r--r--clang/lib/Headers/pmmintrin.h2
-rw-r--r--clang/lib/Headers/xmmintrin.h14
-rw-r--r--clang/lib/Index/CommentToXML.cpp8
-rw-r--r--clang/lib/Index/IndexDecl.cpp29
-rw-r--r--clang/lib/Index/IndexSymbol.cpp1
-rw-r--r--clang/lib/Index/IndexingAction.cpp2
-rw-r--r--clang/lib/Index/IndexingContext.cpp22
-rw-r--r--clang/lib/Index/USRGeneration.cpp1
-rw-r--r--clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp13
-rw-r--r--clang/lib/Lex/Lexer.cpp3
-rw-r--r--clang/lib/Lex/LiteralSupport.cpp6
-rw-r--r--clang/lib/Lex/ModuleMap.cpp2
-rw-r--r--clang/lib/Lex/PPDirectives.cpp4
-rw-r--r--clang/lib/Lex/PPMacroExpansion.cpp52
-rw-r--r--clang/lib/Lex/Pragma.cpp4
-rw-r--r--clang/lib/Lex/Preprocessor.cpp7
-rw-r--r--clang/lib/Parse/ParseAST.cpp2
-rw-r--r--clang/lib/Parse/ParseCXXInlineMethods.cpp46
-rw-r--r--clang/lib/Parse/ParseDecl.cpp151
-rw-r--r--clang/lib/Parse/ParseDeclCXX.cpp78
-rw-r--r--clang/lib/Parse/ParseExpr.cpp302
-rw-r--r--clang/lib/Parse/ParseExprCXX.cpp67
-rw-r--r--clang/lib/Parse/ParseObjc.cpp3
-rw-r--r--clang/lib/Parse/ParseOpenMP.cpp429
-rw-r--r--clang/lib/Parse/ParsePragma.cpp2
-rw-r--r--clang/lib/Parse/ParseStmt.cpp112
-rw-r--r--clang/lib/Parse/ParseStmtAsm.cpp46
-rw-r--r--clang/lib/Parse/ParseTemplate.cpp237
-rw-r--r--clang/lib/Parse/ParseTentative.cpp19
-rw-r--r--clang/lib/Parse/Parser.cpp20
-rw-r--r--clang/lib/Sema/AnalysisBasedWarnings.cpp2
-rw-r--r--clang/lib/Sema/JumpDiagnostics.cpp4
-rw-r--r--clang/lib/Sema/MultiplexExternalSemaSource.cpp2
-rw-r--r--clang/lib/Sema/OpenCLBuiltins.td809
-rw-r--r--clang/lib/Sema/Sema.cpp22
-rw-r--r--clang/lib/Sema/SemaAccess.cpp23
-rw-r--r--clang/lib/Sema/SemaAttr.cpp8
-rw-r--r--clang/lib/Sema/SemaCUDA.cpp2
-rw-r--r--clang/lib/Sema/SemaCast.cpp27
-rw-r--r--clang/lib/Sema/SemaChecking.cpp773
-rw-r--r--clang/lib/Sema/SemaCodeComplete.cpp110
-rw-r--r--clang/lib/Sema/SemaConcept.cpp821
-rw-r--r--clang/lib/Sema/SemaCoroutine.cpp9
-rw-r--r--clang/lib/Sema/SemaDecl.cpp403
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp347
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp1750
-rw-r--r--clang/lib/Sema/SemaDeclObjC.cpp182
-rw-r--r--clang/lib/Sema/SemaExceptionSpec.cpp357
-rw-r--r--clang/lib/Sema/SemaExpr.cpp513
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp559
-rw-r--r--clang/lib/Sema/SemaExprMember.cpp12
-rw-r--r--clang/lib/Sema/SemaExprObjC.cpp129
-rw-r--r--clang/lib/Sema/SemaInit.cpp212
-rw-r--r--clang/lib/Sema/SemaLambda.cpp16
-rw-r--r--clang/lib/Sema/SemaLookup.cpp41
-rw-r--r--clang/lib/Sema/SemaModule.cpp2
-rw-r--r--clang/lib/Sema/SemaObjCProperty.cpp143
-rw-r--r--clang/lib/Sema/SemaOpenMP.cpp1030
-rw-r--r--clang/lib/Sema/SemaOverload.cpp1355
-rw-r--r--clang/lib/Sema/SemaPseudoObject.cpp22
-rw-r--r--clang/lib/Sema/SemaStmt.cpp56
-rw-r--r--clang/lib/Sema/SemaStmtAsm.cpp20
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp581
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp278
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp126
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp430
-rw-r--r--clang/lib/Sema/SemaTemplateVariadic.cpp4
-rw-r--r--clang/lib/Sema/SemaType.cpp314
-rw-r--r--clang/lib/Sema/TreeTransform.h158
-rw-r--r--clang/lib/Serialization/ASTCommon.cpp1
-rw-r--r--clang/lib/Serialization/ASTReader.cpp1496
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp590
-rw-r--r--clang/lib/Serialization/ASTReaderStmt.cpp675
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp731
-rw-r--r--clang/lib/Serialization/ASTWriterDecl.cpp102
-rw-r--r--clang/lib/Serialization/ASTWriterStmt.cpp54
-rw-r--r--clang/lib/Serialization/GlobalModuleIndex.cpp17
-rw-r--r--clang/lib/Serialization/ModuleFile.cpp (renamed from clang/lib/Serialization/Module.cpp)8
-rw-r--r--clang/lib/Serialization/ModuleManager.cpp7
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp10
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp355
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp121
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp68
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp196
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp557
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp234
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/InvalidatedIteratorChecker.cpp95
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/Iterator.cpp227
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/Iterator.h175
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp (renamed from clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp)1211
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp273
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp1
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp24
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp295
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp419
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/Taint.cpp37
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/Taint.h38
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp25
-rw-r--r--clang/lib/StaticAnalyzer/Core/CallEvent.cpp13
-rw-r--r--clang/lib/StaticAnalyzer/Core/CheckerManager.cpp22
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngine.cpp99
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp44
-rw-r--r--clang/lib/StaticAnalyzer/Core/ProgramState.cpp10
-rw-r--r--clang/lib/StaticAnalyzer/Core/RegionStore.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp80
-rw-r--r--clang/lib/StaticAnalyzer/Core/Store.cpp14
-rw-r--r--clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp7
-rw-r--r--clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp1
-rw-r--r--clang/lib/Tooling/ASTDiff/ASTDiff.cpp2
-rw-r--r--clang/lib/Tooling/ArgumentsAdjusters.cpp16
-rw-r--r--clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp42
-rw-r--r--clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp8
-rw-r--r--clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp131
-rw-r--r--clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp30
-rw-r--r--clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp135
-rw-r--r--clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp90
-rw-r--r--clang/lib/Tooling/Inclusions/HeaderIncludes.cpp5
-rw-r--r--clang/lib/Tooling/InterpolatingCompilationDatabase.cpp3
-rw-r--r--clang/lib/Tooling/JSONCompilationDatabase.cpp4
-rw-r--r--clang/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp1
-rw-r--r--clang/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp4
-rw-r--r--clang/lib/Tooling/Syntax/BuildTree.cpp499
-rw-r--r--clang/lib/Tooling/Syntax/ComputeReplacements.cpp126
-rw-r--r--clang/lib/Tooling/Syntax/Mutations.cpp98
-rw-r--r--clang/lib/Tooling/Syntax/Nodes.cpp221
-rw-r--r--clang/lib/Tooling/Syntax/Synthesis.cpp45
-rw-r--r--clang/lib/Tooling/Syntax/Tokens.cpp48
-rw-r--r--clang/lib/Tooling/Syntax/Tree.cpp142
-rw-r--r--clang/lib/Tooling/Tooling.cpp8
-rw-r--r--clang/lib/Tooling/Transformer/RewriteRule.cpp30
-rw-r--r--clang/lib/Tooling/Transformer/Stencil.cpp160
363 files changed, 27110 insertions, 11625 deletions
diff --git a/clang/lib/ARCMigrate/ObjCMT.cpp b/clang/lib/ARCMigrate/ObjCMT.cpp
index 4abb04fef5b8..4c6e9f2432f6 100644
--- a/clang/lib/ARCMigrate/ObjCMT.cpp
+++ b/clang/lib/ARCMigrate/ObjCMT.cpp
@@ -1092,7 +1092,7 @@ static bool AvailabilityAttrsMatch(Attr *At1, Attr *At2) {
const AvailabilityAttr *AA1 = dyn_cast<AvailabilityAttr>(At1);
if (!AA1)
return true;
- const AvailabilityAttr *AA2 = dyn_cast<AvailabilityAttr>(At2);
+ const AvailabilityAttr *AA2 = cast<AvailabilityAttr>(At2);
VersionTuple Introduced1 = AA1->getIntroduced();
VersionTuple Deprecated1 = AA1->getDeprecated();
@@ -1371,7 +1371,7 @@ static bool IsVoidStarType(QualType Ty) {
Ty = TD->getDecl()->getUnderlyingType();
// Is the type void*?
- const PointerType* PT = Ty->getAs<PointerType>();
+ const PointerType* PT = Ty->castAs<PointerType>();
if (PT->getPointeeType().getUnqualifiedType()->isVoidType())
return true;
return IsVoidStarType(PT->getPointeeType());
diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp
new file mode 100644
index 000000000000..fc32e768d92f
--- /dev/null
+++ b/clang/lib/AST/ASTConcept.cpp
@@ -0,0 +1,55 @@
+//===--- ASTConcept.cpp - Concepts Related AST Data Structures --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file defines AST data structures related to concepts.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTConcept.h"
+#include "clang/AST/ASTContext.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)};
+ }
+ }
+}
+
+
+ASTConstraintSatisfaction *
+ASTConstraintSatisfaction::Create(const ASTContext &C,
+ const ConstraintSatisfaction &Satisfaction) {
+ std::size_t size =
+ totalSizeToAlloc<UnsatisfiedConstraintRecord>(
+ Satisfaction.Details.size());
+ void *Mem = C.Allocate(size, alignof(ASTConstraintSatisfaction));
+ return new (Mem) ASTConstraintSatisfaction(C, Satisfaction);
+}
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index cda51ec755a8..a51429264dbe 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -14,6 +14,7 @@
#include "CXXABI.h"
#include "Interp/Context.h"
#include "clang/AST/APValue.h"
+#include "clang/AST/ASTConcept.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/ASTTypeTraits.h"
#include "clang/AST/Attr.h"
@@ -98,6 +99,32 @@ using namespace clang;
enum FloatingRank {
Float16Rank, HalfRank, FloatRank, DoubleRank, LongDoubleRank, Float128Rank
};
+const Expr *ASTContext::traverseIgnored(const Expr *E) const {
+ return traverseIgnored(const_cast<Expr *>(E));
+}
+
+Expr *ASTContext::traverseIgnored(Expr *E) const {
+ if (!E)
+ return nullptr;
+
+ switch (Traversal) {
+ case ast_type_traits::TK_AsIs:
+ return E;
+ case ast_type_traits::TK_IgnoreImplicitCastsAndParentheses:
+ return E->IgnoreParenImpCasts();
+ case ast_type_traits::TK_IgnoreUnlessSpelledInSource:
+ return E->IgnoreUnlessSpelledInSource();
+ }
+ llvm_unreachable("Invalid Traversal type!");
+}
+
+ast_type_traits::DynTypedNode
+ASTContext::traverseIgnored(const ast_type_traits::DynTypedNode &N) const {
+ if (const auto *E = N.get<Expr>()) {
+ return ast_type_traits::DynTypedNode::create(*traverseIgnored(E));
+ }
+ return N;
+}
/// \returns location that is relevant when searching for Doc comments related
/// to \p D.
@@ -163,7 +190,9 @@ static SourceLocation getDeclLocForCommentSearch(const Decl *D,
if (isa<ObjCMethodDecl>(D) || isa<ObjCContainerDecl>(D) ||
isa<ObjCPropertyDecl>(D) ||
isa<RedeclarableTemplateDecl>(D) ||
- isa<ClassTemplateSpecializationDecl>(D))
+ isa<ClassTemplateSpecializationDecl>(D) ||
+ // Allow association with Y across {} in `typedef struct X {} Y`.
+ isa<TypedefDecl>(D))
return D->getBeginLoc();
else {
const SourceLocation DeclLoc = D->getLocation();
@@ -632,8 +661,9 @@ comments::FullComment *ASTContext::getCommentForDecl(
return FC;
}
-void
+void
ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID,
+ const ASTContext &C,
TemplateTemplateParmDecl *Parm) {
ID.AddInteger(Parm->getDepth());
ID.AddInteger(Parm->getPosition());
@@ -647,6 +677,16 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID,
if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) {
ID.AddInteger(0);
ID.AddBoolean(TTP->isParameterPack());
+ const TypeConstraint *TC = TTP->getTypeConstraint();
+ ID.AddBoolean(TC != nullptr);
+ if (TC)
+ TC->getImmediatelyDeclaredConstraint()->Profile(ID, C,
+ /*Canonical=*/true);
+ if (TTP->isExpandedParameterPack()) {
+ ID.AddBoolean(true);
+ ID.AddInteger(TTP->getNumExpansionParameters());
+ } else
+ ID.AddBoolean(false);
continue;
}
@@ -668,8 +708,12 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID,
auto *TTP = cast<TemplateTemplateParmDecl>(*P);
ID.AddInteger(2);
- Profile(ID, TTP);
+ Profile(ID, C, TTP);
}
+ Expr *RequiresClause = Parm->getTemplateParameters()->getRequiresClause();
+ ID.AddBoolean(RequiresClause != nullptr);
+ if (RequiresClause)
+ RequiresClause->Profile(ID, C, /*Canonical=*/true);
}
TemplateTemplateParmDecl *
@@ -677,7 +721,7 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
TemplateTemplateParmDecl *TTP) const {
// Check if we already have a canonical template template parameter.
llvm::FoldingSetNodeID ID;
- CanonicalTemplateTemplateParm::Profile(ID, TTP);
+ CanonicalTemplateTemplateParm::Profile(ID, *this, TTP);
void *InsertPos = nullptr;
CanonicalTemplateTemplateParm *Canonical
= CanonTemplateTemplateParms.FindNodeOrInsertPos(ID, InsertPos);
@@ -691,15 +735,79 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
for (TemplateParameterList::const_iterator P = Params->begin(),
PEnd = Params->end();
P != PEnd; ++P) {
- if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(*P))
- CanonParams.push_back(
- TemplateTypeParmDecl::Create(*this, getTranslationUnitDecl(),
- SourceLocation(),
- SourceLocation(),
- TTP->getDepth(),
- TTP->getIndex(), nullptr, false,
- TTP->isParameterPack()));
- else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
+ if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) {
+ 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);
+ if (const auto *TC = TTP->getTypeConstraint()) {
+ // This is a bit ugly - we need to form a new immediately-declared
+ // constraint that references the new parameter; this would ideally
+ // require semantic analysis (e.g. template<C T> struct S {}; - the
+ // converted arguments of C<T> could be an argument pack if C is
+ // declared as template<typename... T> concept C = ...).
+ // We don't have semantic analysis here so we dig deep into the
+ // ready-made constraint expr and change the thing manually.
+ Expr *IDC = TC->getImmediatelyDeclaredConstraint();
+ ConceptSpecializationExpr *CSE;
+ if (const auto *Fold = dyn_cast<CXXFoldExpr>(IDC))
+ CSE = cast<ConceptSpecializationExpr>(Fold->getLHS());
+ else
+ CSE = cast<ConceptSpecializationExpr>(IDC);
+ ArrayRef<TemplateArgument> OldConverted = CSE->getTemplateArguments();
+ SmallVector<TemplateArgument, 3> NewConverted;
+ NewConverted.reserve(OldConverted.size());
+
+ QualType ParamAsArgument(NewTTP->getTypeForDecl(), 0);
+ if (OldConverted.front().getKind() == TemplateArgument::Pack) {
+ // The case:
+ // template<typename... T> concept C = true;
+ // template<C<int> T> struct S; -> constraint is C<{T, int}>
+ NewConverted.push_back(ParamAsArgument);
+ for (auto &Arg : OldConverted.front().pack_elements().drop_front(1))
+ NewConverted.push_back(Arg);
+ TemplateArgument NewPack(NewConverted);
+
+ NewConverted.clear();
+ NewConverted.push_back(NewPack);
+ assert(OldConverted.size() == 1 &&
+ "Template parameter pack should be the last parameter");
+ } else {
+ assert(OldConverted.front().getKind() == TemplateArgument::Type &&
+ "Unexpected first argument kind for immediately-declared "
+ "constraint");
+ NewConverted.push_back(ParamAsArgument);
+ for (auto &Arg : OldConverted.drop_front(1))
+ NewConverted.push_back(Arg);
+ }
+ Expr *NewIDC = ConceptSpecializationExpr::Create(*this,
+ NestedNameSpecifierLoc(), /*TemplateKWLoc=*/SourceLocation(),
+ CSE->getConceptNameInfo(), /*FoundDecl=*/CSE->getNamedConcept(),
+ CSE->getNamedConcept(),
+ // Actually canonicalizing a TemplateArgumentLoc is difficult so we
+ // simply omit the ArgsAsWritten
+ /*ArgsAsWritten=*/nullptr, NewConverted, nullptr);
+
+ if (auto *OrigFold = dyn_cast<CXXFoldExpr>(IDC))
+ NewIDC = new (*this) CXXFoldExpr(OrigFold->getType(),
+ SourceLocation(), NewIDC,
+ BinaryOperatorKind::BO_LAnd,
+ SourceLocation(), /*RHS=*/nullptr,
+ SourceLocation(),
+ /*NumExpansions=*/None);
+
+ NewTTP->setTypeConstraint(
+ NestedNameSpecifierLoc(),
+ DeclarationNameInfo(TC->getNamedConcept()->getDeclName(),
+ SourceLocation()), /*FoundDecl=*/nullptr,
+ // Actually canonicalizing a TemplateArgumentLoc is difficult so we
+ // simply omit the ArgsAsWritten
+ CSE->getNamedConcept(), /*ArgsAsWritten=*/nullptr, NewIDC);
+ }
+ CanonParams.push_back(NewTTP);
+ } else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
QualType T = getCanonicalType(NTTP->getType());
TypeSourceInfo *TInfo = getTrivialTypeSourceInfo(T);
NonTypeTemplateParmDecl *Param;
@@ -738,9 +846,9 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
cast<TemplateTemplateParmDecl>(*P)));
}
- assert(!TTP->getTemplateParameters()->getRequiresClause() &&
- "Unexpected requires-clause on template template-parameter");
- Expr *const CanonRequiresClause = nullptr;
+ Expr *CanonRequiresClause = nullptr;
+ if (Expr *RequiresClause = TTP->getTemplateParameters()->getRequiresClause())
+ CanonRequiresClause = RequiresClause;
TemplateTemplateParmDecl *CanonTTP
= TemplateTemplateParmDecl::Create(*this, getTranslationUnitDecl(),
@@ -769,6 +877,7 @@ CXXABI *ASTContext::createCXXABI(const TargetInfo &T) {
if (!LangOpts.CPlusPlus) return nullptr;
switch (T.getCXXABI().getKind()) {
+ case TargetCXXABI::Fuchsia:
case TargetCXXABI::GenericARM: // Same as Itanium at this level
case TargetCXXABI::iOS:
case TargetCXXABI::iOS64:
@@ -797,15 +906,18 @@ static const LangASMap *getAddressSpaceMap(const TargetInfo &T,
// 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, // cuda_device
- 6, // cuda_constant
- 7 // cuda_shared
+ 0, // Default
+ 1, // opencl_global
+ 3, // opencl_local
+ 2, // opencl_constant
+ 0, // opencl_private
+ 4, // opencl_generic
+ 5, // cuda_device
+ 6, // cuda_constant
+ 7, // cuda_shared
+ 8, // ptr32_sptr
+ 9, // ptr32_uptr
+ 10 // ptr64
};
return &FakeAddrSpaceMap;
} else {
@@ -832,7 +944,8 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM,
: ConstantArrayTypes(this_()), FunctionProtoTypes(this_()),
TemplateSpecializationTypes(this_()),
DependentTemplateSpecializationTypes(this_()),
- SubstTemplateTemplateParmPacks(this_()), SourceMgr(SM), LangOpts(LOpts),
+ SubstTemplateTemplateParmPacks(this_()),
+ CanonTemplateTemplateParms(this_()), SourceMgr(SM), LangOpts(LOpts),
SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)),
XRayFilter(new XRayFunctionFilter(LangOpts.XRayAlwaysInstrumentFiles,
LangOpts.XRayNeverInstrumentFiles,
@@ -875,10 +988,6 @@ ASTContext::~ASTContext() {
A != AEnd; ++A)
A->second->~AttrVec();
- for (std::pair<const MaterializeTemporaryExpr *, APValue *> &MTVPair :
- MaterializedTemporaryValues)
- MTVPair.second->~APValue();
-
for (const auto &Value : ModuleInitializers)
Value.second->~PerModuleInitializers();
@@ -895,15 +1004,15 @@ class ASTContext::ParentMap {
/// only storing a unique pointer to them.
using ParentMapPointers = llvm::DenseMap<
const void *,
- llvm::PointerUnion4<const Decl *, const Stmt *,
- ast_type_traits::DynTypedNode *, ParentVector *>>;
+ llvm::PointerUnion<const Decl *, const Stmt *,
+ ast_type_traits::DynTypedNode *, ParentVector *>>;
/// Parent map for nodes without pointer identity. We store a full
/// DynTypedNode for all keys.
using ParentMapOtherNodes = llvm::DenseMap<
ast_type_traits::DynTypedNode,
- llvm::PointerUnion4<const Decl *, const Stmt *,
- ast_type_traits::DynTypedNode *, ParentVector *>>;
+ llvm::PointerUnion<const Decl *, const Stmt *,
+ ast_type_traits::DynTypedNode *, ParentVector *>>;
ParentMapPointers PointerParents;
ParentMapOtherNodes OtherParents;
@@ -959,7 +1068,7 @@ public:
void ASTContext::setTraversalScope(const std::vector<Decl *> &TopLevelDecls) {
TraversalScope = TopLevelDecls;
- Parents.reset();
+ Parents.clear();
}
void ASTContext::AddDeallocation(void (*Callback)(void *), void *Data) const {
@@ -2438,7 +2547,7 @@ structHasUniqueObjectRepresentations(const ASTContext &Context,
return llvm::None;
SmallVector<std::pair<QualType, int64_t>, 4> Bases;
- for (const auto Base : ClassDecl->bases()) {
+ for (const auto &Base : ClassDecl->bases()) {
// Empty types can be inherited from, and non-empty types can potentially
// have tail padding, so just make sure there isn't an error.
if (!isStructEmpty(Base.getType())) {
@@ -2456,7 +2565,7 @@ structHasUniqueObjectRepresentations(const ASTContext &Context,
Layout.getBaseClassOffset(R.first->getAsCXXRecordDecl());
});
- for (const auto Base : Bases) {
+ for (const auto &Base : Bases) {
int64_t BaseOffset = Context.toBits(
Layout.getBaseClassOffset(Base.first->getAsCXXRecordDecl()));
int64_t BaseSize = Base.second;
@@ -2654,8 +2763,7 @@ const ObjCInterfaceDecl *ASTContext::getObjContainingInterface(
/// Get the copy initialization expression of VarDecl, or nullptr if
/// none exists.
-ASTContext::BlockVarCopyInit
-ASTContext::getBlockVarCopyInit(const VarDecl*VD) const {
+BlockVarCopyInit ASTContext::getBlockVarCopyInit(const VarDecl *VD) const {
assert(VD && "Passed null params");
assert(VD->hasAttr<BlocksAttr>() &&
"getBlockVarCopyInits - not __block var");
@@ -2809,6 +2917,16 @@ QualType ASTContext::getObjCGCQualType(QualType T,
return getExtQualType(TypeNode, Quals);
}
+QualType ASTContext::removePtrSizeAddrSpace(QualType T) const {
+ if (const PointerType *Ptr = T->getAs<PointerType>()) {
+ QualType Pointee = Ptr->getPointeeType();
+ if (isPtrSizeAddressSpace(Pointee.getAddressSpace())) {
+ return getPointerType(removeAddrSpaceQualType(Pointee));
+ }
+ }
+ return T;
+}
+
const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
FunctionType::ExtInfo Info) {
if (T->getExtInfo() == Info)
@@ -2883,6 +3001,29 @@ bool ASTContext::hasSameFunctionTypeIgnoringExceptionSpec(QualType T,
getFunctionTypeWithExceptionSpec(U, EST_None)));
}
+QualType ASTContext::getFunctionTypeWithoutPtrSizes(QualType T) {
+ if (const auto *Proto = T->getAs<FunctionProtoType>()) {
+ QualType RetTy = removePtrSizeAddrSpace(Proto->getReturnType());
+ SmallVector<QualType, 16> Args(Proto->param_types());
+ for (unsigned i = 0, n = Args.size(); i != n; ++i)
+ Args[i] = removePtrSizeAddrSpace(Args[i]);
+ return getFunctionType(RetTy, Args, Proto->getExtProtoInfo());
+ }
+
+ if (const FunctionNoProtoType *Proto = T->getAs<FunctionNoProtoType>()) {
+ QualType RetTy = removePtrSizeAddrSpace(Proto->getReturnType());
+ return getFunctionNoProtoType(RetTy, Proto->getExtInfo());
+ }
+
+ return T;
+}
+
+bool ASTContext::hasSameFunctionTypeIgnoringPtrSizes(QualType T, QualType U) {
+ return hasSameType(T, U) ||
+ hasSameType(getFunctionTypeWithoutPtrSizes(T),
+ getFunctionTypeWithoutPtrSizes(U));
+}
+
void ASTContext::adjustExceptionSpec(
FunctionDecl *FD, const FunctionProtoType::ExceptionSpecInfo &ESI,
bool AsWritten) {
@@ -3547,10 +3688,10 @@ ASTContext::getDependentVectorType(QualType VecType, Expr *SizeExpr,
(void)CanonCheck;
DependentVectorTypes.InsertNode(New, InsertPos);
} else {
- QualType Canon = getDependentSizedExtVectorType(CanonVecTy, SizeExpr,
- SourceLocation());
+ QualType CanonExtTy = getDependentSizedExtVectorType(CanonVecTy, SizeExpr,
+ SourceLocation());
New = new (*this, TypeAlignment) DependentVectorType(
- *this, VecType, Canon, SizeExpr, AttrLoc, VecKind);
+ *this, VecType, CanonExtTy, SizeExpr, AttrLoc, VecKind);
}
}
@@ -3620,10 +3761,10 @@ ASTContext::getDependentSizedExtVectorType(QualType vecType,
(void)CanonCheck;
DependentSizedExtVectorTypes.InsertNode(New, InsertPos);
} else {
- QualType Canon = getDependentSizedExtVectorType(CanonVecTy, SizeExpr,
- SourceLocation());
- New = new (*this, TypeAlignment)
- DependentSizedExtVectorType(*this, vecType, Canon, SizeExpr, AttrLoc);
+ QualType CanonExtTy = getDependentSizedExtVectorType(CanonVecTy, SizeExpr,
+ SourceLocation());
+ New = new (*this, TypeAlignment) DependentSizedExtVectorType(
+ *this, vecType, CanonExtTy, SizeExpr, AttrLoc);
}
}
@@ -3877,10 +4018,11 @@ QualType ASTContext::getFunctionTypeInternal(
auto ESH = FunctionProtoType::getExceptionSpecSize(
EPI.ExceptionSpec.Type, EPI.ExceptionSpec.Exceptions.size());
size_t Size = FunctionProtoType::totalSizeToAlloc<
- QualType, FunctionType::FunctionTypeExtraBitfields,
+ QualType, SourceLocation, FunctionType::FunctionTypeExtraBitfields,
FunctionType::ExceptionType, Expr *, FunctionDecl *,
FunctionProtoType::ExtParameterInfo, Qualifiers>(
- NumArgs, FunctionProtoType::hasExtraBitfields(EPI.ExceptionSpec.Type),
+ NumArgs, EPI.Variadic,
+ FunctionProtoType::hasExtraBitfields(EPI.ExceptionSpec.Type),
ESH.NumExceptionType, ESH.NumExprPtr, ESH.NumFunctionDeclPtr,
EPI.ExtParameterInfos ? NumArgs : 0,
EPI.TypeQuals.hasNonFastQualifiers() ? 1 : 0);
@@ -6813,21 +6955,19 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
S += ObjCEncodingForEnumType(this, cast<EnumType>(CT));
return;
- case Type::Complex: {
- const auto *CT = T->castAs<ComplexType>();
+ case Type::Complex:
S += 'j';
- getObjCEncodingForTypeImpl(CT->getElementType(), S, ObjCEncOptions(),
+ getObjCEncodingForTypeImpl(T->castAs<ComplexType>()->getElementType(), S,
+ ObjCEncOptions(),
/*Field=*/nullptr);
return;
- }
- case Type::Atomic: {
- const auto *AT = T->castAs<AtomicType>();
+ case Type::Atomic:
S += 'A';
- getObjCEncodingForTypeImpl(AT->getValueType(), S, ObjCEncOptions(),
+ getObjCEncodingForTypeImpl(T->castAs<AtomicType>()->getValueType(), S,
+ ObjCEncOptions(),
/*Field=*/nullptr);
return;
- }
// encoding for pointer or reference types.
case Type::Pointer:
@@ -8645,8 +8785,8 @@ QualType ASTContext::mergeFunctionParameterTypes(QualType lhs, QualType rhs,
QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
bool OfBlockPointer,
bool Unqualified) {
- const auto *lbase = lhs->getAs<FunctionType>();
- const auto *rbase = rhs->getAs<FunctionType>();
+ const auto *lbase = lhs->castAs<FunctionType>();
+ const auto *rbase = rhs->castAs<FunctionType>();
const auto *lproto = dyn_cast<FunctionProtoType>(lbase);
const auto *rproto = dyn_cast<FunctionProtoType>(rbase);
bool allLTypes = true;
@@ -10170,6 +10310,7 @@ MangleContext *ASTContext::createMangleContext(const TargetInfo *T) {
if (!T)
T = Target;
switch (T->getCXXABI().getKind()) {
+ case TargetCXXABI::Fuchsia:
case TargetCXXABI::GenericAArch64:
case TargetCXXABI::GenericItanium:
case TargetCXXABI::GenericARM:
@@ -10324,21 +10465,6 @@ unsigned ASTContext::getParameterIndex(const ParmVarDecl *D) const {
return I->second;
}
-APValue *
-ASTContext::getMaterializedTemporaryValue(const MaterializeTemporaryExpr *E,
- bool MayCreate) {
- assert(E && E->getStorageDuration() == SD_Static &&
- "don't need to cache the computed value for this temporary");
- if (MayCreate) {
- APValue *&MTVI = MaterializedTemporaryValues[E];
- if (!MTVI)
- MTVI = new (*this) APValue;
- return MTVI;
- }
-
- return MaterializedTemporaryValues.lookup(E);
-}
-
QualType ASTContext::getStringLiteralArrayType(QualType EltTy,
unsigned Length) const {
// A C++ string literal has a const-qualified element type (C++ 2.13.4p1).
@@ -10410,7 +10536,8 @@ createDynTypedNode(const NestedNameSpecifierLoc &Node) {
class ASTContext::ParentMap::ASTVisitor
: public RecursiveASTVisitor<ASTVisitor> {
public:
- ASTVisitor(ParentMap &Map) : Map(Map) {}
+ ASTVisitor(ParentMap &Map, ASTContext &Context)
+ : Map(Map), Context(Context) {}
private:
friend class RecursiveASTVisitor<ASTVisitor>;
@@ -10480,9 +10607,12 @@ private:
}
bool TraverseStmt(Stmt *StmtNode) {
- return TraverseNode(
- StmtNode, StmtNode, [&] { return VisitorBase::TraverseStmt(StmtNode); },
- &Map.PointerParents);
+ Stmt *FilteredNode = StmtNode;
+ if (auto *ExprNode = dyn_cast_or_null<Expr>(FilteredNode))
+ FilteredNode = Context.traverseIgnored(ExprNode);
+ return TraverseNode(FilteredNode, FilteredNode,
+ [&] { return VisitorBase::TraverseStmt(FilteredNode); },
+ &Map.PointerParents);
}
bool TraverseTypeLoc(TypeLoc TypeLocNode) {
@@ -10500,20 +10630,22 @@ private:
}
ParentMap &Map;
+ ASTContext &Context;
llvm::SmallVector<ast_type_traits::DynTypedNode, 16> ParentStack;
};
ASTContext::ParentMap::ParentMap(ASTContext &Ctx) {
- ASTVisitor(*this).TraverseAST(Ctx);
+ ASTVisitor(*this, Ctx).TraverseAST(Ctx);
}
ASTContext::DynTypedNodeList
ASTContext::getParents(const ast_type_traits::DynTypedNode &Node) {
- if (!Parents)
+ std::unique_ptr<ParentMap> &P = Parents[Traversal];
+ if (!P)
// We build the parent map for the traversal scope (usually whole TU), as
// hasAncestor can escape any subtree.
- Parents = std::make_unique<ParentMap>(*this);
- return Parents->getParents(Node);
+ P = std::make_unique<ParentMap>(*this);
+ return P->getParents(Node);
}
bool
@@ -10763,3 +10895,66 @@ QualType ASTContext::getCorrespondingSignedFixedPointType(QualType Ty) const {
llvm_unreachable("Unexpected unsigned fixed point type");
}
}
+
+ParsedTargetAttr
+ASTContext::filterFunctionTargetAttrs(const TargetAttr *TD) const {
+ assert(TD != nullptr);
+ ParsedTargetAttr ParsedAttr = TD->parse();
+
+ ParsedAttr.Features.erase(
+ llvm::remove_if(ParsedAttr.Features,
+ [&](const std::string &Feat) {
+ return !Target->isValidFeatureName(
+ StringRef{Feat}.substr(1));
+ }),
+ ParsedAttr.Features.end());
+ return ParsedAttr;
+}
+
+void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
+ const FunctionDecl *FD) const {
+ if (FD)
+ getFunctionFeatureMap(FeatureMap, GlobalDecl().getWithDecl(FD));
+ else
+ Target->initFeatureMap(FeatureMap, getDiagnostics(),
+ Target->getTargetOpts().CPU,
+ Target->getTargetOpts().Features);
+}
+
+// Fills in the supplied string map with the set of target features for the
+// passed in function.
+void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
+ GlobalDecl GD) const {
+ StringRef TargetCPU = Target->getTargetOpts().CPU;
+ const FunctionDecl *FD = GD.getDecl()->getAsFunction();
+ if (const auto *TD = FD->getAttr<TargetAttr>()) {
+ ParsedTargetAttr ParsedAttr = filterFunctionTargetAttrs(TD);
+
+ // Make a copy of the features as passed on the command line into the
+ // beginning of the additional features from the function to override.
+ ParsedAttr.Features.insert(
+ ParsedAttr.Features.begin(),
+ Target->getTargetOpts().FeaturesAsWritten.begin(),
+ Target->getTargetOpts().FeaturesAsWritten.end());
+
+ if (ParsedAttr.Architecture != "" &&
+ Target->isValidCPUName(ParsedAttr.Architecture))
+ TargetCPU = ParsedAttr.Architecture;
+
+ // 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
+ // the passed in features (FeaturesAsWritten) along with the new ones from
+ // the attribute.
+ Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU,
+ ParsedAttr.Features);
+ } else if (const auto *SD = FD->getAttr<CPUSpecificAttr>()) {
+ llvm::SmallVector<StringRef, 32> FeaturesTmp;
+ Target->getCPUSpecificCPUDispatchFeatures(
+ SD->getCPUName(GD.getMultiVersionIndex())->getName(), FeaturesTmp);
+ std::vector<std::string> Features(FeaturesTmp.begin(), FeaturesTmp.end());
+ Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
+ } else {
+ Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU,
+ Target->getTargetOpts().Features);
+ }
+}
diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp
index 30985441031d..ea4d0dea58a3 100644
--- a/clang/lib/AST/ASTDiagnostic.cpp
+++ b/clang/lib/AST/ASTDiagnostic.cpp
@@ -300,8 +300,7 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
// Give some additional info on vector types. These are either not desugared
// or displaying complex __attribute__ expressions so add details of the
// type and element count.
- if (Ty->isVectorType()) {
- const VectorType *VTy = Ty->getAs<VectorType>();
+ if (const auto *VTy = Ty->getAs<VectorType>()) {
std::string DecoratedString;
llvm::raw_string_ostream OS(DecoratedString);
const char *Values = VTy->getNumElements() > 1 ? "values" : "value";
@@ -338,6 +337,21 @@ void clang::FormatASTNodeDiagnosticArgument(
switch (Kind) {
default: llvm_unreachable("unknown ArgumentKind");
+ case DiagnosticsEngine::ak_addrspace: {
+ assert(Modifier.empty() && Argument.empty() &&
+ "Invalid modifier for Qualfiers argument");
+
+ auto S = Qualifiers::getAddrSpaceAsString(static_cast<LangAS>(Val));
+ if (S.empty()) {
+ OS << (Context.getLangOpts().OpenCL ? "default" : "generic");
+ OS << " address space";
+ } else {
+ OS << "address space";
+ OS << " '" << S << "'";
+ }
+ NeedQuotes = false;
+ break;
+ }
case DiagnosticsEngine::ak_qual: {
assert(Modifier.empty() && Argument.empty() &&
"Invalid modifier for Qualfiers argument");
@@ -348,7 +362,7 @@ void clang::FormatASTNodeDiagnosticArgument(
OS << "unqualified";
NeedQuotes = false;
} else {
- OS << Q.getAsString();
+ OS << S;
}
break;
}
@@ -589,8 +603,7 @@ class TemplateDiff {
unsigned ReadNode;
public:
- DiffTree() :
- CurrentNode(0), NextFreeNode(1) {
+ DiffTree() : CurrentNode(0), NextFreeNode(1), ReadNode(0) {
FlatTree.push_back(DiffNode());
}
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 54acca7dc62c..22fb67478c96 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -44,6 +44,7 @@
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeVisitor.h"
#include "clang/AST/UnresolvedSet.h"
+#include "clang/Basic/Builtins.h"
#include "clang/Basic/ExceptionSpecificationType.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/IdentifierTable.h"
@@ -297,6 +298,48 @@ namespace clang {
return nullptr;
}
+ void addDeclToContexts(Decl *FromD, Decl *ToD) {
+ if (Importer.isMinimalImport()) {
+ // In minimal import case the decl must be added even if it is not
+ // contained in original context, for LLDB compatibility.
+ // FIXME: Check if a better solution is possible.
+ if (!FromD->getDescribedTemplate() &&
+ FromD->getFriendObjectKind() == Decl::FOK_None)
+ ToD->getLexicalDeclContext()->addDeclInternal(ToD);
+ return;
+ }
+
+ DeclContext *FromDC = FromD->getDeclContext();
+ DeclContext *FromLexicalDC = FromD->getLexicalDeclContext();
+ DeclContext *ToDC = ToD->getDeclContext();
+ DeclContext *ToLexicalDC = ToD->getLexicalDeclContext();
+
+ bool Visible = false;
+ if (FromDC->containsDeclAndLoad(FromD)) {
+ ToDC->addDeclInternal(ToD);
+ Visible = true;
+ }
+ if (ToDC != ToLexicalDC && FromLexicalDC->containsDeclAndLoad(FromD)) {
+ ToLexicalDC->addDeclInternal(ToD);
+ Visible = true;
+ }
+
+ // If the Decl was added to any context, it was made already visible.
+ // Otherwise it is still possible that it should be visible.
+ if (!Visible) {
+ if (auto *FromNamed = dyn_cast<NamedDecl>(FromD)) {
+ auto *ToNamed = cast<NamedDecl>(ToD);
+ DeclContextLookupResult FromLookup =
+ FromDC->lookup(FromNamed->getDeclName());
+ for (NamedDecl *ND : FromLookup)
+ if (ND == FromNamed) {
+ ToDC->makeDeclVisibleInContext(ToNamed);
+ break;
+ }
+ }
+ }
+ }
+
public:
explicit ASTNodeImporter(ASTImporter &Importer) : Importer(Importer) {}
@@ -483,6 +526,9 @@ namespace clang {
ExpectedDecl VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
ExpectedDecl VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
ExpectedDecl VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
+ ExpectedDecl VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D);
+ ExpectedDecl
+ VisitLifetimeExtendedTemporaryDecl(LifetimeExtendedTemporaryDecl *D);
Expected<ObjCTypeParamList *>
ImportObjCTypeParamList(ObjCTypeParamList *list);
@@ -644,6 +690,11 @@ namespace clang {
Expected<FunctionDecl *> FindFunctionTemplateSpecialization(
FunctionDecl *FromFD);
+
+ // Returns true if the given function has a placeholder return type and
+ // that type is declared inside the body of the function.
+ // E.g. auto f() { struct X{}; return X(); }
+ bool hasAutoReturnTypeDeclaredInside(FunctionDecl *D);
};
template <typename InContainerTy>
@@ -1543,6 +1594,10 @@ Error ASTNodeImporter::ImportDeclParts(
DeclarationName &Name, NamedDecl *&ToD, SourceLocation &Loc) {
// Check if RecordDecl is in FunctionDecl parameters to avoid infinite loop.
// example: int struct_in_proto(struct data_t{int a;int b;} *d);
+ // FIXME: We could support these constructs by importing a different type of
+ // this parameter and by importing the original type of the parameter only
+ // after the FunctionDecl is created. See
+ // VisitFunctionDecl::UsedDifferentProtoType.
DeclContext *OrigDC = D->getDeclContext();
FunctionDecl *FunDecl;
if (isa<RecordDecl>(D) && (FunDecl = dyn_cast<FunctionDecl>(OrigDC)) &&
@@ -1679,7 +1734,34 @@ ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) {
Error ChildErrors = Error::success();
for (auto *From : FromDC->decls()) {
ExpectedDecl ImportedOrErr = import(From);
- if (!ImportedOrErr) {
+
+ // If we are in the process of ImportDefinition(...) for a RecordDecl we
+ // want to make sure that we are also completing each FieldDecl. There
+ // are currently cases where this does not happen and this is correctness
+ // fix since operations such as code generation will expect this to be so.
+ if (ImportedOrErr) {
+ FieldDecl *FieldFrom = dyn_cast_or_null<FieldDecl>(From);
+ Decl *ImportedDecl = (Decl*)*ImportedOrErr;
+ FieldDecl *FieldTo = dyn_cast_or_null<FieldDecl>(ImportedDecl);
+ if (FieldFrom && FieldTo) {
+ const RecordType *RecordFrom = FieldFrom->getType()->getAs<RecordType>();
+ const RecordType *RecordTo = FieldTo->getType()->getAs<RecordType>();
+ if (RecordFrom && RecordTo) {
+ RecordDecl *FromRecordDecl = RecordFrom->getDecl();
+ RecordDecl *ToRecordDecl = RecordTo->getDecl();
+
+ if (FromRecordDecl->isCompleteDefinition() &&
+ !ToRecordDecl->isCompleteDefinition()) {
+ Error Err = ImportDefinition(FromRecordDecl, ToRecordDecl);
+
+ if (Err && AccumulateChildErrors)
+ ChildErrors = joinErrors(std::move(ChildErrors), std::move(Err));
+ else
+ consumeError(std::move(Err));
+ }
+ }
+ }
+ } else {
if (AccumulateChildErrors)
ChildErrors =
joinErrors(std::move(ChildErrors), ImportedOrErr.takeError());
@@ -2224,6 +2306,9 @@ ExpectedDecl ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
ExpectedSLoc BeginLocOrErr = import(D->getBeginLoc());
if (!BeginLocOrErr)
return BeginLocOrErr.takeError();
+ ExpectedSLoc RBraceLocOrErr = import(D->getRBraceLoc());
+ if (!RBraceLocOrErr)
+ return RBraceLocOrErr.takeError();
// Create the "to" namespace, if needed.
NamespaceDecl *ToNamespace = MergeWithNamespace;
@@ -2233,6 +2318,7 @@ ExpectedDecl ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
*BeginLocOrErr, Loc, Name.getAsIdentifierInfo(),
/*PrevDecl=*/nullptr))
return ToNamespace;
+ ToNamespace->setRBraceLoc(*RBraceLocOrErr);
ToNamespace->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(ToNamespace);
@@ -2541,9 +2627,10 @@ ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
SourceLocation ToBeginLoc;
NestedNameSpecifierLoc ToQualifierLoc;
QualType ToIntegerType;
- if (auto Imp = importSeq(
- D->getBeginLoc(), D->getQualifierLoc(), D->getIntegerType()))
- std::tie(ToBeginLoc, ToQualifierLoc, ToIntegerType) = *Imp;
+ SourceRange ToBraceRange;
+ if (auto Imp = importSeq(D->getBeginLoc(), D->getQualifierLoc(),
+ D->getIntegerType(), D->getBraceRange()))
+ std::tie(ToBeginLoc, ToQualifierLoc, ToIntegerType, ToBraceRange) = *Imp;
else
return Imp.takeError();
@@ -2557,6 +2644,7 @@ ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
D2->setQualifierInfo(ToQualifierLoc);
D2->setIntegerType(ToIntegerType);
+ D2->setBraceRange(ToBraceRange);
D2->setAccess(D->getAccess());
D2->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(D2);
@@ -2718,11 +2806,7 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
D2 = D2CXX;
D2->setAccess(D->getAccess());
D2->setLexicalDeclContext(LexicalDC);
- if (!DCXX->getDescribedClassTemplate() || DCXX->isImplicit())
- LexicalDC->addDeclInternal(D2);
-
- if (LexicalDC != DC && D->isInIdentifierNamespace(Decl::IDNS_TagFriend))
- DC->makeDeclVisibleInContext(D2);
+ addDeclToContexts(D, D2);
if (ClassTemplateDecl *FromDescribed =
DCXX->getDescribedClassTemplate()) {
@@ -2788,9 +2872,13 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
Name.getAsIdentifierInfo(), PrevDecl))
return D2;
D2->setLexicalDeclContext(LexicalDC);
- LexicalDC->addDeclInternal(D2);
+ addDeclToContexts(D, D2);
}
+ if (auto BraceRangeOrErr = import(D->getBraceRange()))
+ D2->setBraceRange(*BraceRangeOrErr);
+ else
+ return BraceRangeOrErr.takeError();
if (auto QualifierLocOrErr = import(D->getQualifierLoc()))
D2->setQualifierInfo(*QualifierLocOrErr);
else
@@ -2991,6 +3079,46 @@ Error ASTNodeImporter::ImportFunctionDeclBody(FunctionDecl *FromFD,
return Error::success();
}
+// Returns true if the given D has a DeclContext up to the TranslationUnitDecl
+// which is equal to the given DC.
+static bool isAncestorDeclContextOf(const DeclContext *DC, const Decl *D) {
+ const DeclContext *DCi = D->getDeclContext();
+ while (DCi != D->getTranslationUnitDecl()) {
+ if (DCi == DC)
+ return true;
+ DCi = DCi->getParent();
+ }
+ return false;
+}
+
+bool ASTNodeImporter::hasAutoReturnTypeDeclaredInside(FunctionDecl *D) {
+ QualType FromTy = D->getType();
+ const FunctionProtoType *FromFPT = FromTy->getAs<FunctionProtoType>();
+ assert(FromFPT && "Must be called on FunctionProtoType");
+ if (AutoType *AutoT = FromFPT->getReturnType()->getContainedAutoType()) {
+ QualType DeducedT = AutoT->getDeducedType();
+ if (const RecordType *RecordT =
+ DeducedT.isNull() ? nullptr : dyn_cast<RecordType>(DeducedT)) {
+ RecordDecl *RD = RecordT->getDecl();
+ assert(RD);
+ if (isAncestorDeclContextOf(D, RD)) {
+ assert(RD->getLexicalDeclContext() == RD->getDeclContext());
+ return true;
+ }
+ }
+ }
+ if (const TypedefType *TypedefT =
+ dyn_cast<TypedefType>(FromFPT->getReturnType())) {
+ TypedefNameDecl *TD = TypedefT->getDecl();
+ assert(TD);
+ if (isAncestorDeclContextOf(D, TD)) {
+ assert(TD->getLexicalDeclContext() == TD->getDeclContext());
+ return true;
+ }
+ }
+ return false;
+}
+
ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
SmallVector<Decl *, 2> Redecls = getCanonicalForwardRedeclChain(D);
@@ -3114,32 +3242,49 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
return std::move(Err);
QualType FromTy = D->getType();
- bool usedDifferentExceptionSpec = false;
-
- if (const auto *FromFPT = D->getType()->getAs<FunctionProtoType>()) {
+ // Set to true if we do not import the type of the function as is. There are
+ // cases when the original type would result in an infinite recursion during
+ // the import. To avoid an infinite recursion when importing, we create the
+ // FunctionDecl with a simplified function type and update it only after the
+ // relevant AST nodes are already imported.
+ bool UsedDifferentProtoType = false;
+ if (const auto *FromFPT = FromTy->getAs<FunctionProtoType>()) {
+ QualType FromReturnTy = FromFPT->getReturnType();
+ // Functions with auto return type may define a struct inside their body
+ // and the return type could refer to that struct.
+ // E.g.: auto foo() { struct X{}; return X(); }
+ // To avoid an infinite recursion when importing, create the FunctionDecl
+ // with a simplified return type.
+ if (hasAutoReturnTypeDeclaredInside(D)) {
+ FromReturnTy = Importer.getFromContext().VoidTy;
+ UsedDifferentProtoType = true;
+ }
FunctionProtoType::ExtProtoInfo FromEPI = FromFPT->getExtProtoInfo();
// FunctionProtoType::ExtProtoInfo's ExceptionSpecDecl can point to the
// FunctionDecl that we are importing the FunctionProtoType for.
// To avoid an infinite recursion when importing, create the FunctionDecl
- // with a simplified function type and update it afterwards.
+ // with a simplified function type.
if (FromEPI.ExceptionSpec.SourceDecl ||
FromEPI.ExceptionSpec.SourceTemplate ||
FromEPI.ExceptionSpec.NoexceptExpr) {
FunctionProtoType::ExtProtoInfo DefaultEPI;
- FromTy = Importer.getFromContext().getFunctionType(
- FromFPT->getReturnType(), FromFPT->getParamTypes(), DefaultEPI);
- usedDifferentExceptionSpec = true;
+ FromEPI = DefaultEPI;
+ UsedDifferentProtoType = true;
}
+ FromTy = Importer.getFromContext().getFunctionType(
+ FromReturnTy, FromFPT->getParamTypes(), FromEPI);
}
QualType T;
TypeSourceInfo *TInfo;
SourceLocation ToInnerLocStart, ToEndLoc;
NestedNameSpecifierLoc ToQualifierLoc;
+ Expr *TrailingRequiresClause;
if (auto Imp = importSeq(
FromTy, D->getTypeSourceInfo(), D->getInnerLocStart(),
- D->getQualifierLoc(), D->getEndLoc()))
- std::tie(T, TInfo, ToInnerLocStart, ToQualifierLoc, ToEndLoc) = *Imp;
+ D->getQualifierLoc(), D->getEndLoc(), D->getTrailingRequiresClause()))
+ std::tie(T, TInfo, ToInnerLocStart, ToQualifierLoc, ToEndLoc,
+ TrailingRequiresClause) = *Imp;
else
return Imp.takeError();
@@ -3168,7 +3313,10 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
ExplicitSpecifier(
ExplicitExpr,
FromConstructor->getExplicitSpecifier().getKind()),
- D->isInlineSpecified(), D->isImplicit(), D->getConstexprKind()))
+ D->isInlineSpecified(), D->isImplicit(), D->getConstexprKind(),
+ InheritedConstructor(), // FIXME: Properly import inherited
+ // constructor info
+ TrailingRequiresClause))
return ToFunction;
} else if (CXXDestructorDecl *FromDtor = dyn_cast<CXXDestructorDecl>(D)) {
@@ -3186,7 +3334,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
if (GetImportedOrCreateDecl<CXXDestructorDecl>(
ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
ToInnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(),
- D->isImplicit(), D->getConstexprKind()))
+ D->isImplicit(), D->getConstexprKind(), TrailingRequiresClause))
return ToFunction;
CXXDestructorDecl *ToDtor = cast<CXXDestructorDecl>(ToFunction);
@@ -3206,20 +3354,21 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
ToInnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(),
ExplicitSpecifier(ExplicitExpr,
FromConversion->getExplicitSpecifier().getKind()),
- D->getConstexprKind(), SourceLocation()))
+ D->getConstexprKind(), SourceLocation(), TrailingRequiresClause))
return ToFunction;
} else if (auto *Method = dyn_cast<CXXMethodDecl>(D)) {
if (GetImportedOrCreateDecl<CXXMethodDecl>(
ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
ToInnerLocStart, NameInfo, T, TInfo, Method->getStorageClass(),
Method->isInlineSpecified(), D->getConstexprKind(),
- SourceLocation()))
+ SourceLocation(), TrailingRequiresClause))
return ToFunction;
} else {
if (GetImportedOrCreateDecl(
ToFunction, D, Importer.getToContext(), DC, ToInnerLocStart,
NameInfo, T, TInfo, D->getStorageClass(), D->isInlineSpecified(),
- D->hasWrittenPrototype(), D->getConstexprKind()))
+ D->hasWrittenPrototype(), D->getConstexprKind(),
+ TrailingRequiresClause))
return ToFunction;
}
@@ -3263,14 +3412,6 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
}
}
- if (usedDifferentExceptionSpec) {
- // Update FunctionProtoType::ExtProtoInfo.
- if (ExpectedType TyOrErr = import(D->getType()))
- ToFunction->setType(*TyOrErr);
- else
- return TyOrErr.takeError();
- }
-
// Import the describing template function, if any.
if (FromFT) {
auto ToFTOrErr = import(FromFT);
@@ -3302,29 +3443,21 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
return std::move(Err);
}
+ // Import and set the original type in case we used another type.
+ if (UsedDifferentProtoType) {
+ if (ExpectedType TyOrErr = import(D->getType()))
+ ToFunction->setType(*TyOrErr);
+ else
+ return TyOrErr.takeError();
+ }
+
// FIXME: Other bits to merge?
// If it is a template, import all related things.
if (Error Err = ImportTemplateInformation(D, ToFunction))
return std::move(Err);
- bool IsFriend = D->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend);
-
- // TODO Can we generalize this approach to other AST nodes as well?
- if (D->getDeclContext()->containsDeclAndLoad(D))
- DC->addDeclInternal(ToFunction);
- if (DC != LexicalDC && D->getLexicalDeclContext()->containsDeclAndLoad(D))
- LexicalDC->addDeclInternal(ToFunction);
-
- // Friend declaration's lexical context is the befriending class, but the
- // semantic context is the enclosing scope of the befriending class.
- // We want the friend functions to be found in the semantic context by lookup.
- // FIXME should we handle this generically in VisitFriendDecl?
- // In Other cases when LexicalDC != DC we don't want it to be added,
- // e.g out-of-class definitions like void B::f() {} .
- if (LexicalDC != DC && IsFriend) {
- DC->makeDeclVisibleInContext(ToFunction);
- }
+ addDeclToContexts(D, ToFunction);
if (auto *FromCXXMethod = dyn_cast<CXXMethodDecl>(D))
if (Error Err = ImportOverriddenMethods(cast<CXXMethodDecl>(ToFunction),
@@ -3772,10 +3905,7 @@ ExpectedDecl ASTNodeImporter::VisitVarDecl(VarDecl *D) {
if (D->isConstexpr())
ToVar->setConstexpr(true);
- if (D->getDeclContext()->containsDeclAndLoad(D))
- DC->addDeclInternal(ToVar);
- if (DC != LexicalDC && D->getLexicalDeclContext()->containsDeclAndLoad(D))
- LexicalDC->addDeclInternal(ToVar);
+ addDeclToContexts(D, ToVar);
// Import the rest of the chain. I.e. import all subsequent declarations.
for (++RedeclIt; RedeclIt != Redecls.end(); ++RedeclIt) {
@@ -3961,10 +4091,10 @@ ExpectedDecl ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
ObjCMethodDecl *ToMethod;
if (GetImportedOrCreateDecl(
- ToMethod, D, Importer.getToContext(), Loc,
- ToEndLoc, Name.getObjCSelector(), ToReturnType,
- ToReturnTypeSourceInfo, DC, D->isInstanceMethod(), D->isVariadic(),
- D->isPropertyAccessor(), D->isImplicit(), D->isDefined(),
+ ToMethod, D, Importer.getToContext(), Loc, ToEndLoc,
+ Name.getObjCSelector(), ToReturnType, ToReturnTypeSourceInfo, DC,
+ D->isInstanceMethod(), D->isVariadic(), D->isPropertyAccessor(),
+ D->isSynthesizedAccessorStub(), D->isImplicit(), D->isDefined(),
D->getImplementationControl(), D->hasRelatedResultType()))
return ToMethod;
@@ -3996,6 +4126,14 @@ ExpectedDecl ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
ToMethod->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(ToMethod);
+
+ // Implicit params are declared when Sema encounters the definition but this
+ // never happens when the method is imported. Manually declare the implicit
+ // params now that the MethodDecl knows its class interface.
+ if (D->getSelfDecl())
+ ToMethod->createImplicitParams(Importer.getToContext(),
+ ToMethod->getClassInterface());
+
return ToMethod;
}
@@ -4464,6 +4602,20 @@ ExpectedDecl ASTNodeImporter::VisitUnresolvedUsingTypenameDecl(
return ToUsing;
}
+ExpectedDecl ASTNodeImporter::VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D) {
+ Decl* ToD = nullptr;
+ switch (D->getBuiltinTemplateKind()) {
+ case BuiltinTemplateKind::BTK__make_integer_seq:
+ ToD = Importer.getToContext().getMakeIntegerSeqDecl();
+ break;
+ case BuiltinTemplateKind::BTK__type_pack_element:
+ ToD = Importer.getToContext().getTypePackElementDecl();
+ break;
+ }
+ assert(ToD && "BuiltinTemplateDecl of unsupported kind!");
+ Importer.MapImported(D, ToD);
+ return ToD;
+}
Error ASTNodeImporter::ImportDefinition(
ObjCInterfaceDecl *From, ObjCInterfaceDecl *To, ImportDefinitionKind Kind) {
@@ -4945,7 +5097,7 @@ ASTNodeImporter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
// context. This context will be fixed when the actual template declaration
// is created.
- // FIXME: Import default argument.
+ // FIXME: Import default argument and constraint expression.
ExpectedSLoc BeginLocOrErr = import(D->getBeginLoc());
if (!BeginLocOrErr)
@@ -4956,12 +5108,47 @@ ASTNodeImporter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
return LocationOrErr.takeError();
TemplateTypeParmDecl *ToD = nullptr;
- (void)GetImportedOrCreateDecl(
+ if (GetImportedOrCreateDecl(
ToD, D, Importer.getToContext(),
Importer.getToContext().getTranslationUnitDecl(),
*BeginLocOrErr, *LocationOrErr,
D->getDepth(), D->getIndex(), Importer.Import(D->getIdentifier()),
- D->wasDeclaredWithTypename(), D->isParameterPack());
+ D->wasDeclaredWithTypename(), D->isParameterPack(),
+ D->hasTypeConstraint()))
+ return ToD;
+
+ // Import the type-constraint
+ if (const TypeConstraint *TC = D->getTypeConstraint()) {
+ NestedNameSpecifierLoc ToNNS;
+ DeclarationName ToName;
+ SourceLocation ToNameLoc;
+ NamedDecl *ToFoundDecl;
+ ConceptDecl *ToNamedConcept;
+ Expr *ToIDC;
+ if (auto Imp = importSeq(TC->getNestedNameSpecifierLoc(),
+ TC->getConceptNameInfo().getName(), TC->getConceptNameInfo().getLoc(),
+ TC->getFoundDecl(), TC->getNamedConcept(),
+ TC->getImmediatelyDeclaredConstraint()))
+ std::tie(ToNNS, ToName, ToNameLoc, ToFoundDecl, ToNamedConcept,
+ ToIDC) = *Imp;
+ else
+ return Imp.takeError();
+
+ TemplateArgumentListInfo ToTAInfo;
+ const auto *ASTTemplateArgs = TC->getTemplateArgsAsWritten();
+ if (ASTTemplateArgs)
+ if (Error Err = ImportTemplateArgumentListInfo(*ASTTemplateArgs,
+ ToTAInfo))
+ return std::move(Err);
+
+ ToD->setTypeConstraint(ToNNS, DeclarationNameInfo(ToName, ToNameLoc),
+ ToFoundDecl, ToNamedConcept,
+ ASTTemplateArgs ?
+ ASTTemplateArgumentListInfo::Create(Importer.getToContext(),
+ ToTAInfo) : nullptr,
+ ToIDC);
+ }
+
return ToD;
}
@@ -5033,7 +5220,6 @@ template <typename T> static auto getTemplateDefinition(T *D) -> T * {
}
ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
- bool IsFriend = D->getFriendObjectKind() != Decl::FOK_None;
// Import the major distinguishing characteristics of this class template.
DeclContext *DC, *LexicalDC;
@@ -5059,6 +5245,8 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
Decl *Found = FoundDecl;
auto *FoundTemplate = dyn_cast<ClassTemplateDecl>(Found);
if (FoundTemplate) {
+ if (!hasSameVisibilityContext(FoundTemplate, D))
+ continue;
if (IsStructuralMatch(D, FoundTemplate)) {
ClassTemplateDecl *TemplateWithDef =
@@ -5108,10 +5296,7 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
D2->setAccess(D->getAccess());
D2->setLexicalDeclContext(LexicalDC);
- if (D->getDeclContext()->containsDeclAndLoad(D))
- DC->addDeclInternal(D2);
- if (DC != LexicalDC && D->getLexicalDeclContext()->containsDeclAndLoad(D))
- LexicalDC->addDeclInternal(D2);
+ addDeclToContexts(D, D2);
if (FoundByLookup) {
auto *Recent =
@@ -5137,9 +5322,6 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
D2->setPreviousDecl(Recent);
}
- if (LexicalDC != DC && IsFriend)
- DC->makeDeclVisibleInContext(D2);
-
if (FromTemplated->isCompleteDefinition() &&
!ToTemplated->isCompleteDefinition()) {
// FIXME: Import definition!
@@ -5164,16 +5346,25 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
if (Error Err = ImportTemplateArguments(
D->getTemplateArgs().data(), D->getTemplateArgs().size(), TemplateArgs))
return std::move(Err);
-
- // Try to find an existing specialization with these template arguments.
+ // Try to find an existing specialization with these template arguments and
+ // template parameter list.
void *InsertPos = nullptr;
ClassTemplateSpecializationDecl *PrevDecl = nullptr;
ClassTemplatePartialSpecializationDecl *PartialSpec =
dyn_cast<ClassTemplatePartialSpecializationDecl>(D);
- if (PartialSpec)
- PrevDecl =
- ClassTemplate->findPartialSpecialization(TemplateArgs, InsertPos);
- else
+
+ // Import template parameters.
+ TemplateParameterList *ToTPList = nullptr;
+
+ if (PartialSpec) {
+ auto ToTPListOrErr = import(PartialSpec->getTemplateParameters());
+ if (!ToTPListOrErr)
+ return ToTPListOrErr.takeError();
+ ToTPList = *ToTPListOrErr;
+ PrevDecl = ClassTemplate->findPartialSpecialization(TemplateArgs,
+ *ToTPListOrErr,
+ InsertPos);
+ } else
PrevDecl = ClassTemplate->findSpecialization(TemplateArgs, InsertPos);
if (PrevDecl) {
@@ -5232,13 +5423,9 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
return std::move(Err);
CanonInjType = CanonInjType.getCanonicalType();
- auto ToTPListOrErr = import(PartialSpec->getTemplateParameters());
- if (!ToTPListOrErr)
- return ToTPListOrErr.takeError();
-
if (GetImportedOrCreateDecl<ClassTemplatePartialSpecializationDecl>(
D2, D, Importer.getToContext(), D->getTagKind(), DC,
- *BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr, ClassTemplate,
+ *BeginLocOrErr, *IdLocOrErr, ToTPList, ClassTemplate,
llvm::makeArrayRef(TemplateArgs.data(), TemplateArgs.size()),
ToTAInfo, CanonInjType,
cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl)))
@@ -5246,10 +5433,11 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
// Update InsertPos, because preceding import calls may have invalidated
// it by adding new specializations.
- if (!ClassTemplate->findPartialSpecialization(TemplateArgs, InsertPos))
+ auto *PartSpec2 = cast<ClassTemplatePartialSpecializationDecl>(D2);
+ if (!ClassTemplate->findPartialSpecialization(TemplateArgs, ToTPList,
+ InsertPos))
// Add this partial specialization to the class template.
- ClassTemplate->AddPartialSpecialization(
- cast<ClassTemplatePartialSpecializationDecl>(D2), InsertPos);
+ ClassTemplate->AddPartialSpecialization(PartSpec2, InsertPos);
} else { // Not a partial specialization.
if (GetImportedOrCreateDecl(
@@ -5275,6 +5463,11 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
LexicalDC->addDeclInternal(D2);
}
+ if (auto BraceRangeOrErr = import(D->getBraceRange()))
+ D2->setBraceRange(*BraceRangeOrErr);
+ else
+ return BraceRangeOrErr.takeError();
+
// Import the qualifier, if any.
if (auto LocOrErr = import(D->getQualifierLoc()))
D2->setQualifierInfo(*LocOrErr);
@@ -6273,7 +6466,8 @@ ExpectedStmt ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) {
TemplateArgumentListInfo *ToResInfo = nullptr;
if (E->hasExplicitTemplateArgs()) {
if (Error Err =
- ImportTemplateArgumentListInfo(E->template_arguments(), ToTAInfo))
+ ImportTemplateArgumentListInfo(E->getLAngleLoc(), E->getRAngleLoc(),
+ E->template_arguments(), ToTAInfo))
return std::move(Err);
ToResInfo = &ToTAInfo;
}
@@ -6989,23 +7183,52 @@ ASTNodeImporter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) {
E->requiresZeroInitialization());
}
+ExpectedDecl ASTNodeImporter::VisitLifetimeExtendedTemporaryDecl(
+ LifetimeExtendedTemporaryDecl *D) {
+ DeclContext *DC, *LexicalDC;
+ if (Error Err = ImportDeclContext(D, DC, LexicalDC))
+ return std::move(Err);
+
+ auto Imp = importSeq(D->getTemporaryExpr(), D->getExtendingDecl());
+ // FIXME: the APValue should be imported as well if present.
+ if (!Imp)
+ return Imp.takeError();
+
+ Expr *Temporary;
+ ValueDecl *ExtendingDecl;
+ std::tie(Temporary, ExtendingDecl) = *Imp;
+ // FIXME: Should ManglingNumber get numbers associated with 'to' context?
+
+ LifetimeExtendedTemporaryDecl *To;
+ if (GetImportedOrCreateDecl(To, D, Temporary, ExtendingDecl,
+ D->getManglingNumber()))
+ return To;
+
+ To->setLexicalDeclContext(LexicalDC);
+ LexicalDC->addDeclInternal(To);
+ return To;
+}
+
ExpectedStmt
ASTNodeImporter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
- auto Imp = importSeq(
- E->getType(), E->GetTemporaryExpr(), E->getExtendingDecl());
+ auto Imp = importSeq(E->getType(),
+ E->getLifetimeExtendedTemporaryDecl() ? nullptr
+ : E->getSubExpr(),
+ E->getLifetimeExtendedTemporaryDecl());
if (!Imp)
return Imp.takeError();
QualType ToType;
Expr *ToTemporaryExpr;
- const ValueDecl *ToExtendingDecl;
- std::tie(ToType, ToTemporaryExpr, ToExtendingDecl) = *Imp;
+ LifetimeExtendedTemporaryDecl *ToMaterializedDecl;
+ std::tie(ToType, ToTemporaryExpr, ToMaterializedDecl) = *Imp;
+ if (!ToTemporaryExpr)
+ ToTemporaryExpr = cast<Expr>(ToMaterializedDecl->getTemporaryExpr());
- auto *ToMTE = new (Importer.getToContext()) MaterializeTemporaryExpr(
- ToType, ToTemporaryExpr, E->isBoundToLvalueReference());
+ auto *ToMTE = new (Importer.getToContext()) MaterializeTemporaryExpr(
+ ToType, ToTemporaryExpr, E->isBoundToLvalueReference(),
+ ToMaterializedDecl);
- // FIXME: Should ManglingNumber get numbers associated with 'to' context?
- ToMTE->setExtendingDecl(ToExtendingDecl, E->getManglingNumber());
return ToMTE;
}
@@ -7320,20 +7543,19 @@ ExpectedStmt ASTNodeImporter::VisitCXXDependentScopeMemberExpr(
ExpectedStmt
ASTNodeImporter::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
- auto Imp = importSeq(
- E->getQualifierLoc(), E->getTemplateKeywordLoc(), E->getDeclName(),
- E->getExprLoc(), E->getLAngleLoc(), E->getRAngleLoc());
+ auto Imp = importSeq(E->getQualifierLoc(), E->getTemplateKeywordLoc(),
+ E->getDeclName(), E->getNameInfo().getLoc(),
+ E->getLAngleLoc(), E->getRAngleLoc());
if (!Imp)
return Imp.takeError();
NestedNameSpecifierLoc ToQualifierLoc;
- SourceLocation ToTemplateKeywordLoc, ToExprLoc, ToLAngleLoc, ToRAngleLoc;
+ SourceLocation ToTemplateKeywordLoc, ToNameLoc, ToLAngleLoc, ToRAngleLoc;
DeclarationName ToDeclName;
- std::tie(
- ToQualifierLoc, ToTemplateKeywordLoc, ToDeclName, ToExprLoc,
- ToLAngleLoc, ToRAngleLoc) = *Imp;
+ std::tie(ToQualifierLoc, ToTemplateKeywordLoc, ToDeclName, ToNameLoc,
+ ToLAngleLoc, ToRAngleLoc) = *Imp;
- DeclarationNameInfo ToNameInfo(ToDeclName, ToExprLoc);
+ DeclarationNameInfo ToNameInfo(ToDeclName, ToNameLoc);
if (Error Err = ImportDeclarationNameLoc(E->getNameInfo(), ToNameInfo))
return std::move(Err);
@@ -7398,7 +7620,7 @@ ASTNodeImporter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
else
return ToDOrErr.takeError();
- if (E->hasExplicitTemplateArgs() && E->getTemplateKeywordLoc().isValid()) {
+ if (E->hasExplicitTemplateArgs()) {
TemplateArgumentListInfo ToTAInfo;
if (Error Err = ImportTemplateArgumentListInfo(
E->getLAngleLoc(), E->getRAngleLoc(), E->template_arguments(),
@@ -7452,8 +7674,9 @@ ASTNodeImporter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
TemplateArgumentListInfo ToTAInfo;
TemplateArgumentListInfo *ResInfo = nullptr;
if (E->hasExplicitTemplateArgs()) {
- if (Error Err =
- ImportTemplateArgumentListInfo(E->template_arguments(), ToTAInfo))
+ TemplateArgumentListInfo FromTAInfo;
+ E->copyTemplateArgumentsInto(FromTAInfo);
+ if (Error Err = ImportTemplateArgumentListInfo(FromTAInfo, ToTAInfo))
return std::move(Err);
ResInfo = &ToTAInfo;
}
@@ -8266,8 +8489,14 @@ ASTImporter::Import(NestedNameSpecifierLoc FromNNS) {
return std::move(Err);
TypeSourceInfo *TSI = getToContext().getTrivialTypeSourceInfo(
QualType(Spec->getAsType(), 0), ToTLoc);
- Builder.Extend(getToContext(), ToLocalBeginLoc, TSI->getTypeLoc(),
- ToLocalEndLoc);
+ if (Kind == NestedNameSpecifier::TypeSpecWithTemplate)
+ // ToLocalBeginLoc is here the location of the 'template' keyword.
+ Builder.Extend(getToContext(), ToLocalBeginLoc, TSI->getTypeLoc(),
+ ToLocalEndLoc);
+ else
+ // No location for 'template' keyword here.
+ Builder.Extend(getToContext(), SourceLocation{}, TSI->getTypeLoc(),
+ ToLocalEndLoc);
break;
}
diff --git a/clang/lib/AST/ASTTypeTraits.cpp b/clang/lib/AST/ASTTypeTraits.cpp
index 6b7f6ec51086..a5570c329ae8 100644
--- a/clang/lib/AST/ASTTypeTraits.cpp
+++ b/clang/lib/AST/ASTTypeTraits.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/OpenMPClause.h"
namespace clang {
namespace ast_type_traits {
diff --git a/clang/lib/AST/Comment.cpp b/clang/lib/AST/Comment.cpp
index 23dc7ba93591..a02cc9d119fe 100644
--- a/clang/lib/AST/Comment.cpp
+++ b/clang/lib/AST/Comment.cpp
@@ -379,11 +379,11 @@ StringRef TParamCommandComment::getParamName(const FullComment *FC) const {
assert(isPositionValid());
const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters;
for (unsigned i = 0, e = getDepth(); i != e; ++i) {
- if (i == e-1)
+ assert(TPL && "Unknown TemplateParameterList");
+ if (i == e - 1)
return TPL->getParam(getIndex(i))->getName();
const NamedDecl *Param = TPL->getParam(getIndex(i));
- if (const TemplateTemplateParmDecl *TTP =
- dyn_cast<TemplateTemplateParmDecl>(Param))
+ if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param))
TPL = TTP->getTemplateParameters();
}
return "";
diff --git a/clang/lib/AST/CommentSema.cpp b/clang/lib/AST/CommentSema.cpp
index 69d61dc55162..53c1832d1dd2 100644
--- a/clang/lib/AST/CommentSema.cpp
+++ b/clang/lib/AST/CommentSema.cpp
@@ -676,9 +676,8 @@ void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) {
D->hasAttr<UnavailableAttr>())
return;
- Diag(Command->getLocation(),
- diag::warn_doc_deprecated_not_sync)
- << Command->getSourceRange();
+ Diag(Command->getLocation(), diag::warn_doc_deprecated_not_sync)
+ << Command->getSourceRange() << Command->getCommandMarker();
// Try to emit a fixit with a deprecation attribute.
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
@@ -689,24 +688,41 @@ void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) {
FD->doesThisDeclarationHaveABody())
return;
- StringRef AttributeSpelling = "__attribute__((deprecated))";
+ const LangOptions &LO = FD->getASTContext().getLangOpts();
+ const bool DoubleSquareBracket = LO.CPlusPlus14 || LO.C2x;
+ StringRef AttributeSpelling =
+ DoubleSquareBracket ? "[[deprecated]]" : "__attribute__((deprecated))";
if (PP) {
- TokenValue Tokens[] = {
- tok::kw___attribute, tok::l_paren, tok::l_paren,
- PP->getIdentifierInfo("deprecated"),
- tok::r_paren, tok::r_paren
- };
- StringRef MacroName = PP->getLastMacroWithSpelling(FD->getLocation(),
- Tokens);
- if (!MacroName.empty())
- AttributeSpelling = MacroName;
+ // Try to find a replacement macro:
+ // - In C2x/C++14 we prefer [[deprecated]].
+ // - If not found or an older C/C++ look for __attribute__((deprecated)).
+ StringRef MacroName;
+ if (DoubleSquareBracket) {
+ TokenValue Tokens[] = {tok::l_square, tok::l_square,
+ PP->getIdentifierInfo("deprecated"),
+ tok::r_square, tok::r_square};
+ MacroName = PP->getLastMacroWithSpelling(FD->getLocation(), Tokens);
+ if (!MacroName.empty())
+ AttributeSpelling = MacroName;
+ }
+
+ if (MacroName.empty()) {
+ TokenValue Tokens[] = {
+ tok::kw___attribute, tok::l_paren,
+ tok::l_paren, PP->getIdentifierInfo("deprecated"),
+ tok::r_paren, tok::r_paren};
+ StringRef MacroName =
+ PP->getLastMacroWithSpelling(FD->getLocation(), Tokens);
+ if (!MacroName.empty())
+ AttributeSpelling = MacroName;
+ }
}
- SmallString<64> TextToInsert(" ");
- TextToInsert += AttributeSpelling;
- Diag(FD->getEndLoc(), diag::note_add_deprecation_attr)
- << FixItHint::CreateInsertion(FD->getEndLoc().getLocWithOffset(1),
- TextToInsert);
+ SmallString<64> TextToInsert = AttributeSpelling;
+ TextToInsert += " ";
+ SourceLocation Loc = FD->getSourceRange().getBegin();
+ Diag(Loc, diag::note_add_deprecation_attr)
+ << FixItHint::CreateInsertion(Loc, TextToInsert);
}
}
@@ -1127,6 +1143,7 @@ Sema::getInlineCommandRenderKind(StringRef Name) const {
.Case("b", InlineCommandComment::RenderBold)
.Cases("c", "p", InlineCommandComment::RenderMonospaced)
.Cases("a", "e", "em", InlineCommandComment::RenderEmphasized)
+ .Case("anchor", InlineCommandComment::RenderAnchor)
.Default(InlineCommandComment::RenderNormal);
}
diff --git a/clang/lib/AST/ComparisonCategories.cpp b/clang/lib/AST/ComparisonCategories.cpp
index ee4c1b0443a3..07673230357f 100644
--- a/clang/lib/AST/ComparisonCategories.cpp
+++ b/clang/lib/AST/ComparisonCategories.cpp
@@ -19,6 +19,26 @@
using namespace clang;
+Optional<ComparisonCategoryType>
+clang::getComparisonCategoryForBuiltinCmp(QualType T) {
+ using CCT = ComparisonCategoryType;
+
+ if (T->isIntegralOrEnumerationType())
+ return CCT::StrongOrdering;
+
+ if (T->isRealFloatingType())
+ return CCT::PartialOrdering;
+
+ // C++2a [expr.spaceship]p8: If the composite pointer type is an object
+ // pointer type, p <=> q is of type std::strong_ordering.
+ // Note: this assumes neither operand is a null pointer constant.
+ if (T->isObjectPointerType())
+ return CCT::StrongOrdering;
+
+ // TODO: Extend support for operator<=> to ObjC types.
+ return llvm::None;
+}
+
bool ComparisonCategoryInfo::ValueInfo::hasValidIntValue() const {
assert(VD && "must have var decl");
if (!VD->checkInitIsICE())
@@ -59,7 +79,7 @@ ComparisonCategoryInfo::ValueInfo *ComparisonCategoryInfo::lookupValueInfo(
// a new entry representing it.
DeclContextLookupResult Lookup = Record->getCanonicalDecl()->lookup(
&Ctx.Idents.get(ComparisonCategories::getResultString(ValueKind)));
- if (Lookup.size() != 1 || !isa<VarDecl>(Lookup.front()))
+ if (Lookup.empty() || !isa<VarDecl>(Lookup.front()))
return nullptr;
Objects.emplace_back(ValueKind, cast<VarDecl>(Lookup.front()));
return &Objects.back();
@@ -70,7 +90,7 @@ static const NamespaceDecl *lookupStdNamespace(const ASTContext &Ctx,
if (!StdNS) {
DeclContextLookupResult Lookup =
Ctx.getTranslationUnitDecl()->lookup(&Ctx.Idents.get("std"));
- if (Lookup.size() == 1)
+ if (!Lookup.empty())
StdNS = dyn_cast<NamespaceDecl>(Lookup.front());
}
return StdNS;
@@ -81,7 +101,7 @@ static CXXRecordDecl *lookupCXXRecordDecl(const ASTContext &Ctx,
ComparisonCategoryType Kind) {
StringRef Name = ComparisonCategories::getCategoryString(Kind);
DeclContextLookupResult Lookup = StdNS->lookup(&Ctx.Idents.get(Name));
- if (Lookup.size() == 1)
+ if (!Lookup.empty())
if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Lookup.front()))
return RD;
return nullptr;
@@ -150,10 +170,6 @@ QualType ComparisonCategoryInfo::getType() const {
StringRef ComparisonCategories::getCategoryString(ComparisonCategoryType Kind) {
using CCKT = ComparisonCategoryType;
switch (Kind) {
- case CCKT::WeakEquality:
- return "weak_equality";
- case CCKT::StrongEquality:
- return "strong_equality";
case CCKT::PartialOrdering:
return "partial_ordering";
case CCKT::WeakOrdering:
@@ -169,12 +185,8 @@ StringRef ComparisonCategories::getResultString(ComparisonCategoryResult Kind) {
switch (Kind) {
case CCVT::Equal:
return "equal";
- case CCVT::Nonequal:
- return "nonequal";
case CCVT::Equivalent:
return "equivalent";
- case CCVT::Nonequivalent:
- return "nonequivalent";
case CCVT::Less:
return "less";
case CCVT::Greater:
@@ -190,20 +202,11 @@ ComparisonCategories::getPossibleResultsForType(ComparisonCategoryType Type) {
using CCT = ComparisonCategoryType;
using CCR = ComparisonCategoryResult;
std::vector<CCR> Values;
- Values.reserve(6);
- Values.push_back(CCR::Equivalent);
- bool IsStrong = (Type == CCT::StrongEquality || Type == CCT::StrongOrdering);
- if (IsStrong)
- Values.push_back(CCR::Equal);
- if (Type == CCT::StrongOrdering || Type == CCT::WeakOrdering ||
- Type == CCT::PartialOrdering) {
- Values.push_back(CCR::Less);
- Values.push_back(CCR::Greater);
- } else {
- Values.push_back(CCR::Nonequivalent);
- if (IsStrong)
- Values.push_back(CCR::Nonequal);
- }
+ Values.reserve(4);
+ bool IsStrong = Type == CCT::StrongOrdering;
+ Values.push_back(IsStrong ? CCR::Equal : CCR::Equivalent);
+ Values.push_back(CCR::Less);
+ Values.push_back(CCR::Greater);
if (Type == CCT::PartialOrdering)
Values.push_back(CCR::Unordered);
return Values;
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 80235d8496d2..0d30f64b992e 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/CanonicalType.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
@@ -55,8 +56,8 @@
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
@@ -901,6 +902,10 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
if (!isExternallyVisible(LV.getLinkage()))
return LinkageInfo(LV.getLinkage(), DefaultVisibility, false);
+ // Mark the symbols as hidden when compiling for the device.
+ if (Context.getLangOpts().OpenMP && Context.getLangOpts().OpenMPIsDevice)
+ LV.mergeVisibility(HiddenVisibility, /*newExplicit=*/false);
+
return LV;
}
@@ -1815,6 +1820,12 @@ SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const {
return SourceLocation();
}
+SourceLocation DeclaratorDecl::getTypeSpecEndLoc() const {
+ TypeSourceInfo *TSI = getTypeSourceInfo();
+ if (TSI) return TSI->getTypeLoc().getEndLoc();
+ return SourceLocation();
+}
+
void DeclaratorDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
if (QualifierLoc) {
// Make sure the extended decl info is allocated.
@@ -1828,23 +1839,27 @@ void DeclaratorDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
}
// Set qualifier info.
getExtInfo()->QualifierLoc = QualifierLoc;
- } else {
+ } else if (hasExtInfo()) {
// Here Qualifier == 0, i.e., we are removing the qualifier (if any).
- if (hasExtInfo()) {
- if (getExtInfo()->NumTemplParamLists == 0) {
- // Save type source info pointer.
- TypeSourceInfo *savedTInfo = getExtInfo()->TInfo;
- // Deallocate the extended decl info.
- getASTContext().Deallocate(getExtInfo());
- // Restore savedTInfo into (non-extended) decl info.
- DeclInfo = savedTInfo;
- }
- else
- getExtInfo()->QualifierLoc = QualifierLoc;
- }
+ getExtInfo()->QualifierLoc = QualifierLoc;
}
}
+void DeclaratorDecl::setTrailingRequiresClause(Expr *TrailingRequiresClause) {
+ assert(TrailingRequiresClause);
+ // Make sure the extended decl info is allocated.
+ if (!hasExtInfo()) {
+ // Save (non-extended) type source info pointer.
+ auto *savedTInfo = DeclInfo.get<TypeSourceInfo*>();
+ // Allocate external info struct.
+ DeclInfo = new (getASTContext()) ExtInfo;
+ // Restore savedTInfo into (extended) decl info.
+ getExtInfo()->TInfo = savedTInfo;
+ }
+ // Set requires clause info.
+ getExtInfo()->TrailingRequiresClause = TrailingRequiresClause;
+}
+
void DeclaratorDecl::setTemplateParameterListsInfo(
ASTContext &Context, ArrayRef<TemplateParameterList *> TPLists) {
assert(!TPLists.empty());
@@ -2766,10 +2781,11 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
const DeclarationNameInfo &NameInfo, QualType T,
TypeSourceInfo *TInfo, StorageClass S,
bool isInlineSpecified,
- ConstexprSpecKind ConstexprKind)
+ ConstexprSpecKind ConstexprKind,
+ Expr *TrailingRequiresClause)
: DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo,
StartLoc),
- DeclContext(DK), redeclarable_base(C), ODRHash(0),
+ DeclContext(DK), redeclarable_base(C), Body(), ODRHash(0),
EndRangeLoc(NameInfo.getEndLoc()), DNLoc(NameInfo.getInfo()) {
assert(T.isNull() || T->isFunctionType());
FunctionDeclBits.SClass = S;
@@ -2784,16 +2800,20 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
FunctionDeclBits.IsTrivialForCall = false;
FunctionDeclBits.IsDefaulted = false;
FunctionDeclBits.IsExplicitlyDefaulted = false;
+ FunctionDeclBits.HasDefaultedFunctionInfo = false;
FunctionDeclBits.HasImplicitReturnZero = false;
FunctionDeclBits.IsLateTemplateParsed = false;
FunctionDeclBits.ConstexprKind = ConstexprKind;
FunctionDeclBits.InstantiationIsPending = false;
FunctionDeclBits.UsesSEHTry = false;
+ FunctionDeclBits.UsesFPIntrin = false;
FunctionDeclBits.HasSkippedBody = false;
FunctionDeclBits.WillHaveBody = false;
FunctionDeclBits.IsMultiVersion = false;
FunctionDeclBits.IsCopyDeductionCandidate = false;
FunctionDeclBits.HasODRHash = false;
+ if (TrailingRequiresClause)
+ setTrailingRequiresClause(TrailingRequiresClause);
}
void FunctionDecl::getNameForDiagnostic(
@@ -2810,6 +2830,32 @@ bool FunctionDecl::isVariadic() const {
return false;
}
+FunctionDecl::DefaultedFunctionInfo *
+FunctionDecl::DefaultedFunctionInfo::Create(ASTContext &Context,
+ ArrayRef<DeclAccessPair> Lookups) {
+ DefaultedFunctionInfo *Info = new (Context.Allocate(
+ totalSizeToAlloc<DeclAccessPair>(Lookups.size()),
+ std::max(alignof(DefaultedFunctionInfo), alignof(DeclAccessPair))))
+ DefaultedFunctionInfo;
+ Info->NumLookups = Lookups.size();
+ std::uninitialized_copy(Lookups.begin(), Lookups.end(),
+ Info->getTrailingObjects<DeclAccessPair>());
+ return Info;
+}
+
+void FunctionDecl::setDefaultedFunctionInfo(DefaultedFunctionInfo *Info) {
+ assert(!FunctionDeclBits.HasDefaultedFunctionInfo && "already have this");
+ assert(!Body && "can't replace function body with defaulted function info");
+
+ FunctionDeclBits.HasDefaultedFunctionInfo = true;
+ DefaultedInfo = Info;
+}
+
+FunctionDecl::DefaultedFunctionInfo *
+FunctionDecl::getDefaultedFunctionInfo() const {
+ return FunctionDeclBits.HasDefaultedFunctionInfo ? DefaultedInfo : nullptr;
+}
+
bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const {
for (auto I : redecls()) {
if (I->doesThisDeclarationHaveABody()) {
@@ -2821,8 +2867,7 @@ bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const {
return false;
}
-bool FunctionDecl::hasTrivialBody() const
-{
+bool FunctionDecl::hasTrivialBody() const {
Stmt *S = getBody();
if (!S) {
// Since we don't have a body for this function, we don't know if it's
@@ -2850,6 +2895,8 @@ Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
if (!hasBody(Definition))
return nullptr;
+ assert(!Definition->FunctionDeclBits.HasDefaultedFunctionInfo &&
+ "definition should not have a body");
if (Definition->Body)
return Definition->Body.get(getASTContext().getExternalSource());
@@ -2857,7 +2904,8 @@ Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
}
void FunctionDecl::setBody(Stmt *B) {
- Body = B;
+ FunctionDeclBits.HasDefaultedFunctionInfo = false;
+ Body = LazyDeclStmtPtr(B);
if (B)
EndRangeLoc = B->getEndLoc();
}
@@ -2998,6 +3046,14 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction(bool *IsAligned) const
return Params == FPT->getNumParams();
}
+bool FunctionDecl::isInlineBuiltinDeclaration() const {
+ if (!getBuiltinID())
+ return false;
+
+ const FunctionDecl *Definition;
+ return hasBody(Definition) && Definition->isInlineSpecified();
+}
+
bool FunctionDecl::isDestroyingOperatorDelete() const {
// C++ P0722:
// Within a class C, a single object deallocation function with signature
@@ -3115,10 +3171,17 @@ FunctionDecl *FunctionDecl::getCanonicalDecl() { return getFirstDecl(); }
/// functions as their wrapped builtins. This shouldn't be done in general, but
/// it's useful in Sema to diagnose calls to wrappers based on their semantics.
unsigned FunctionDecl::getBuiltinID(bool ConsiderWrapperFunctions) const {
- if (!getIdentifier())
- return 0;
+ unsigned BuiltinID;
+
+ if (const auto *AMAA = getAttr<ArmMveAliasAttr>()) {
+ BuiltinID = AMAA->getBuiltinName()->getBuiltinID();
+ } else {
+ if (!getIdentifier())
+ return 0;
+
+ BuiltinID = getIdentifier()->getBuiltinID();
+ }
- unsigned BuiltinID = getIdentifier()->getBuiltinID();
if (!BuiltinID)
return 0;
@@ -3142,7 +3205,8 @@ unsigned FunctionDecl::getBuiltinID(bool ConsiderWrapperFunctions) const {
// If the function is marked "overloadable", it has a different mangled name
// and is not the C library function.
- if (!ConsiderWrapperFunctions && hasAttr<OverloadableAttr>())
+ if (!ConsiderWrapperFunctions && hasAttr<OverloadableAttr>() &&
+ !hasAttr<ArmMveAliasAttr>())
return 0;
if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
@@ -3290,9 +3354,9 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
const FunctionDecl *Prev = this;
bool FoundBody = false;
while ((Prev = Prev->getPreviousDecl())) {
- FoundBody |= Prev->Body.isValid();
+ FoundBody |= Prev->doesThisDeclarationHaveABody();
- if (Prev->Body) {
+ if (Prev->doesThisDeclarationHaveABody()) {
// If it's not the case that both 'inline' and 'extern' are
// specified on the definition, then it is always externally visible.
if (!Prev->isInlineSpecified() ||
@@ -3315,19 +3379,21 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
const FunctionDecl *Prev = this;
bool FoundBody = false;
while ((Prev = Prev->getPreviousDecl())) {
- FoundBody |= Prev->Body.isValid();
+ FoundBody |= Prev->doesThisDeclarationHaveABody();
if (RedeclForcesDefC99(Prev))
return false;
}
return FoundBody;
}
-SourceRange FunctionDecl::getReturnTypeSourceRange() const {
+FunctionTypeLoc FunctionDecl::getFunctionTypeLoc() const {
const TypeSourceInfo *TSI = getTypeSourceInfo();
- if (!TSI)
- return SourceRange();
- FunctionTypeLoc FTL =
- TSI->getTypeLoc().IgnoreParens().getAs<FunctionTypeLoc>();
+ return TSI ? TSI->getTypeLoc().IgnoreParens().getAs<FunctionTypeLoc>()
+ : FunctionTypeLoc();
+}
+
+SourceRange FunctionDecl::getReturnTypeSourceRange() const {
+ FunctionTypeLoc FTL = getFunctionTypeLoc();
if (!FTL)
return SourceRange();
@@ -3342,16 +3408,25 @@ SourceRange FunctionDecl::getReturnTypeSourceRange() const {
return RTRange;
}
-SourceRange FunctionDecl::getExceptionSpecSourceRange() const {
- const TypeSourceInfo *TSI = getTypeSourceInfo();
- if (!TSI)
- return SourceRange();
- FunctionTypeLoc FTL =
- TSI->getTypeLoc().IgnoreParens().getAs<FunctionTypeLoc>();
- if (!FTL)
+SourceRange FunctionDecl::getParametersSourceRange() const {
+ unsigned NP = getNumParams();
+ SourceLocation EllipsisLoc = getEllipsisLoc();
+
+ if (NP == 0 && EllipsisLoc.isInvalid())
return SourceRange();
- return FTL.getExceptionSpecRange();
+ SourceLocation Begin =
+ NP > 0 ? ParamInfo[0]->getSourceRange().getBegin() : EllipsisLoc;
+ SourceLocation End = EllipsisLoc.isValid()
+ ? EllipsisLoc
+ : ParamInfo[NP - 1]->getSourceRange().getEnd();
+
+ return SourceRange(Begin, End);
+}
+
+SourceRange FunctionDecl::getExceptionSpecSourceRange() const {
+ FunctionTypeLoc FTL = getFunctionTypeLoc();
+ return FTL ? FTL.getExceptionSpecRange() : SourceRange();
}
/// For an inline function definition in C, or for a gnu_inline function
@@ -3812,6 +3887,11 @@ unsigned FunctionDecl::getMemoryFunctionKind() const {
case Builtin::BImemcpy:
return Builtin::BImemcpy;
+ case Builtin::BI__builtin_mempcpy:
+ case Builtin::BI__builtin___mempcpy_chk:
+ case Builtin::BImempcpy:
+ return Builtin::BImempcpy;
+
case Builtin::BI__builtin_memmove:
case Builtin::BI__builtin___memmove_chk:
case Builtin::BImemmove:
@@ -3869,6 +3949,8 @@ unsigned FunctionDecl::getMemoryFunctionKind() const {
return Builtin::BImemset;
else if (FnInfo->isStr("memcpy"))
return Builtin::BImemcpy;
+ else if (FnInfo->isStr("mempcpy"))
+ return Builtin::BImempcpy;
else if (FnInfo->isStr("memmove"))
return Builtin::BImemmove;
else if (FnInfo->isStr("memcmp"))
@@ -4582,7 +4664,7 @@ LabelDecl *LabelDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
}
void LabelDecl::setMSAsmLabel(StringRef Name) {
- char *Buffer = new (getASTContext(), 1) char[Name.size() + 1];
+char *Buffer = new (getASTContext(), 1) char[Name.size() + 1];
memcpy(Buffer, Name.data(), Name.size());
Buffer[Name.size()] = '\0';
MSAsmName = Buffer;
@@ -4623,10 +4705,12 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
QualType T, TypeSourceInfo *TInfo,
StorageClass SC, bool isInlineSpecified,
bool hasWrittenPrototype,
- ConstexprSpecKind ConstexprKind) {
+ ConstexprSpecKind ConstexprKind,
+ Expr *TrailingRequiresClause) {
FunctionDecl *New =
new (C, DC) FunctionDecl(Function, C, DC, StartLoc, NameInfo, T, TInfo,
- SC, isInlineSpecified, ConstexprKind);
+ SC, isInlineSpecified, ConstexprKind,
+ TrailingRequiresClause);
New->setHasWrittenPrototype(hasWrittenPrototype);
return New;
}
@@ -4634,7 +4718,7 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
FunctionDecl *FunctionDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) FunctionDecl(Function, C, nullptr, SourceLocation(),
DeclarationNameInfo(), QualType(), nullptr,
- SC_None, false, CSK_unspecified);
+ SC_None, false, CSK_unspecified, nullptr);
}
BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index 77a3a4c679a1..6ee767ccecf7 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -803,6 +803,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case OMPRequires:
case OMPCapturedExpr:
case Empty:
+ case LifetimeExtendedTemporary:
// Never looked up by name.
return 0;
}
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 12ec44fa0279..2ead1e70ea0d 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/ASTUnresolvedSet.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclTemplate.h"
@@ -413,7 +414,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
data().HasIrrelevantDestructor = false;
// C++11 [class.copy]p18:
- // The implicitly-declared copy assignment oeprator for a class X will
+ // The implicitly-declared copy assignment operator for a class X will
// have the form 'X& X::operator=(const X&)' if each direct base class B
// of X has a copy assignment operator whose parameter is of type 'const
// B&', 'const volatile B&', or 'B' [...]
@@ -737,49 +738,55 @@ void CXXRecordDecl::addedMember(Decl *D) {
// Handle constructors.
if (const auto *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
- if (!Constructor->isImplicit()) {
- // Note that we have a user-declared constructor.
- data().UserDeclaredConstructor = true;
+ if (Constructor->isInheritingConstructor()) {
+ // Ignore constructor shadow declarations. They are lazily created and
+ // so shouldn't affect any properties of the class.
+ } else {
+ if (!Constructor->isImplicit()) {
+ // 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;
- }
+ // 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()) {
- SMKind |= SMF_DefaultConstructor;
+ if (Constructor->isDefaultConstructor()) {
+ SMKind |= SMF_DefaultConstructor;
- if (Constructor->isUserProvided())
- data().UserProvidedDefaultConstructor = true;
- if (Constructor->isConstexpr())
- data().HasConstexprDefaultConstructor = true;
- if (Constructor->isDefaulted())
- data().HasDefaultedDefaultConstructor = true;
- }
+ if (Constructor->isUserProvided())
+ data().UserProvidedDefaultConstructor = true;
+ if (Constructor->isConstexpr())
+ data().HasConstexprDefaultConstructor = true;
+ if (Constructor->isDefaulted())
+ data().HasDefaultedDefaultConstructor = true;
+ }
- if (!FunTmpl) {
- unsigned Quals;
- if (Constructor->isCopyConstructor(Quals)) {
- SMKind |= SMF_CopyConstructor;
+ if (!FunTmpl) {
+ unsigned Quals;
+ if (Constructor->isCopyConstructor(Quals)) {
+ SMKind |= SMF_CopyConstructor;
- if (Quals & Qualifiers::Const)
- data().HasDeclaredCopyConstructorWithConstParam = true;
- } else if (Constructor->isMoveConstructor())
- SMKind |= SMF_MoveConstructor;
- }
+ if (Quals & Qualifiers::Const)
+ data().HasDeclaredCopyConstructorWithConstParam = true;
+ } else if (Constructor->isMoveConstructor())
+ SMKind |= SMF_MoveConstructor;
+ }
- // C++11 [dcl.init.aggr]p1: DR1518
- // An aggregate is an array or a class with no user-provided [or]
- // explicit [...] constructors
- // C++20 [dcl.init.aggr]p1:
- // An aggregate is an array or a class with no user-declared [...]
- // constructors
- if (getASTContext().getLangOpts().CPlusPlus2a
- ? !Constructor->isImplicit()
- : (Constructor->isUserProvided() || Constructor->isExplicit()))
- data().Aggregate = false;
+ // C++11 [dcl.init.aggr]p1: DR1518
+ // An aggregate is an array or a class with no user-provided [or]
+ // explicit [...] constructors
+ // C++20 [dcl.init.aggr]p1:
+ // An aggregate is an array or a class with no user-declared [...]
+ // constructors
+ if (getASTContext().getLangOpts().CPlusPlus2a
+ ? !Constructor->isImplicit()
+ : (Constructor->isUserProvided() || Constructor->isExplicit()))
+ data().Aggregate = false;
+ }
}
// Handle constructors, including those inherited from base classes.
@@ -1511,14 +1518,12 @@ static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) {
/// \param VOutput the set to which to add conversions from virtual bases
/// \param HiddenVBaseCs the set of conversions which were hidden in a
/// virtual base along some inheritance path
-static void CollectVisibleConversions(ASTContext &Context,
- CXXRecordDecl *Record,
- bool InVirtual,
- AccessSpecifier Access,
- const llvm::SmallPtrSet<CanQualType, 8> &ParentHiddenTypes,
- ASTUnresolvedSet &Output,
- UnresolvedSetImpl &VOutput,
- llvm::SmallPtrSet<NamedDecl*, 8> &HiddenVBaseCs) {
+static void CollectVisibleConversions(
+ ASTContext &Context, const CXXRecordDecl *Record, bool InVirtual,
+ AccessSpecifier Access,
+ const llvm::SmallPtrSet<CanQualType, 8> &ParentHiddenTypes,
+ ASTUnresolvedSet &Output, UnresolvedSetImpl &VOutput,
+ llvm::SmallPtrSet<NamedDecl *, 8> &HiddenVBaseCs) {
// The set of types which have conversions in this class or its
// subclasses. As an optimization, we don't copy the derived set
// unless it might change.
@@ -1559,7 +1564,7 @@ static void CollectVisibleConversions(ASTContext &Context,
// Collect information recursively from any base classes.
for (const auto &I : Record->bases()) {
- const RecordType *RT = I.getType()->getAs<RecordType>();
+ const auto *RT = I.getType()->getAs<RecordType>();
if (!RT) continue;
AccessSpecifier BaseAccess
@@ -1577,7 +1582,7 @@ static void CollectVisibleConversions(ASTContext &Context,
/// This would be extremely straightforward if it weren't for virtual
/// bases. It might be worth special-casing that, really.
static void CollectVisibleConversions(ASTContext &Context,
- CXXRecordDecl *Record,
+ const CXXRecordDecl *Record,
ASTUnresolvedSet &Output) {
// The collection of all conversions in virtual bases that we've
// found. These will be added to the output as long as they don't
@@ -1601,7 +1606,7 @@ static void CollectVisibleConversions(ASTContext &Context,
// Recursively collect conversions from base classes.
for (const auto &I : Record->bases()) {
- const RecordType *RT = I.getType()->getAs<RecordType>();
+ const auto *RT = I.getType()->getAs<RecordType>();
if (!RT) continue;
CollectVisibleConversions(Context, cast<CXXRecordDecl>(RT->getDecl()),
@@ -1620,7 +1625,7 @@ static void CollectVisibleConversions(ASTContext &Context,
/// getVisibleConversionFunctions - get all conversion functions visible
/// in current class; including conversion function templates.
llvm::iterator_range<CXXRecordDecl::conversion_iterator>
-CXXRecordDecl::getVisibleConversionFunctions() {
+CXXRecordDecl::getVisibleConversionFunctions() const {
ASTContext &Ctx = getASTContext();
ASTUnresolvedSet *Set;
@@ -2042,16 +2047,19 @@ CXXMethodDecl *CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
QualType T, TypeSourceInfo *TInfo,
StorageClass SC, bool isInline,
ConstexprSpecKind ConstexprKind,
- SourceLocation EndLocation) {
+ SourceLocation EndLocation,
+ Expr *TrailingRequiresClause) {
return new (C, RD)
CXXMethodDecl(CXXMethod, C, RD, StartLoc, NameInfo, T, TInfo, SC,
- isInline, ConstexprKind, EndLocation);
+ isInline, ConstexprKind, EndLocation,
+ TrailingRequiresClause);
}
CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) CXXMethodDecl(
CXXMethod, C, nullptr, SourceLocation(), DeclarationNameInfo(),
- QualType(), nullptr, SC_None, false, CSK_unspecified, SourceLocation());
+ QualType(), nullptr, SC_None, false, CSK_unspecified, SourceLocation(),
+ nullptr);
}
CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base,
@@ -2432,9 +2440,11 @@ CXXConstructorDecl::CXXConstructorDecl(
ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared,
- ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited)
+ ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited,
+ Expr *TrailingRequiresClause)
: CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo,
- SC_None, isInline, ConstexprKind, SourceLocation()) {
+ SC_None, isInline, ConstexprKind, SourceLocation(),
+ TrailingRequiresClause) {
setNumCtorInitializers(0);
setInheritingConstructor(static_cast<bool>(Inherited));
setImplicit(isImplicitlyDeclared);
@@ -2458,7 +2468,7 @@ CXXConstructorDecl *CXXConstructorDecl::CreateDeserialized(ASTContext &C,
auto *Result = new (C, ID, Extra)
CXXConstructorDecl(C, nullptr, SourceLocation(), DeclarationNameInfo(),
QualType(), nullptr, ExplicitSpecifier(), false, false,
- CSK_unspecified, InheritedConstructor());
+ CSK_unspecified, InheritedConstructor(), nullptr);
Result->setInheritingConstructor(isInheritingConstructor);
Result->CXXConstructorDeclBits.HasTrailingExplicitSpecifier =
hasTraillingExplicit;
@@ -2470,7 +2480,8 @@ CXXConstructorDecl *CXXConstructorDecl::Create(
ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared,
- ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited) {
+ ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited,
+ Expr *TrailingRequiresClause) {
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXConstructorName &&
"Name must refer to a constructor");
@@ -2479,7 +2490,8 @@ CXXConstructorDecl *CXXConstructorDecl::Create(
Inherited ? 1 : 0, ES.getExpr() ? 1 : 0);
return new (C, RD, Extra)
CXXConstructorDecl(C, RD, StartLoc, NameInfo, T, TInfo, ES, isInline,
- isImplicitlyDeclared, ConstexprKind, Inherited);
+ isImplicitlyDeclared, ConstexprKind, Inherited,
+ TrailingRequiresClause);
}
CXXConstructorDecl::init_const_iterator CXXConstructorDecl::init_begin() const {
@@ -2600,19 +2612,22 @@ CXXDestructorDecl *
CXXDestructorDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID)
CXXDestructorDecl(C, nullptr, SourceLocation(), DeclarationNameInfo(),
- QualType(), nullptr, false, false, CSK_unspecified);
+ QualType(), nullptr, false, false, CSK_unspecified,
+ nullptr);
}
CXXDestructorDecl *CXXDestructorDecl::Create(
ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
- bool isInline, bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind) {
+ bool isInline, bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind,
+ Expr *TrailingRequiresClause) {
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXDestructorName &&
"Name must refer to a destructor");
return new (C, RD)
CXXDestructorDecl(C, RD, StartLoc, NameInfo, T, TInfo, isInline,
- isImplicitlyDeclared, ConstexprKind);
+ isImplicitlyDeclared, ConstexprKind,
+ TrailingRequiresClause);
}
void CXXDestructorDecl::setOperatorDelete(FunctionDecl *OD, Expr *ThisArg) {
@@ -2631,20 +2646,20 @@ CXXConversionDecl *
CXXConversionDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) CXXConversionDecl(
C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr,
- false, ExplicitSpecifier(), CSK_unspecified, SourceLocation());
+ false, ExplicitSpecifier(), CSK_unspecified, SourceLocation(), nullptr);
}
CXXConversionDecl *CXXConversionDecl::Create(
ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
bool isInline, ExplicitSpecifier ES, ConstexprSpecKind ConstexprKind,
- SourceLocation EndLocation) {
+ SourceLocation EndLocation, Expr *TrailingRequiresClause) {
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXConversionFunctionName &&
"Name must refer to a conversion function");
return new (C, RD)
CXXConversionDecl(C, RD, StartLoc, NameInfo, T, TInfo, isInline, ES,
- ConstexprKind, EndLocation);
+ ConstexprKind, EndLocation, TrailingRequiresClause);
}
bool CXXConversionDecl::isLambdaToBlockPointerConversion() const {
@@ -2796,6 +2811,36 @@ NamespaceAliasDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
SourceLocation(), nullptr);
}
+void LifetimeExtendedTemporaryDecl::anchor() {}
+
+/// Retrieve the storage duration for the materialized temporary.
+StorageDuration LifetimeExtendedTemporaryDecl::getStorageDuration() const {
+ const ValueDecl *ExtendingDecl = getExtendingDecl();
+ if (!ExtendingDecl)
+ return SD_FullExpression;
+ // FIXME: This is not necessarily correct for a temporary materialized
+ // within a default initializer.
+ if (isa<FieldDecl>(ExtendingDecl))
+ return SD_Automatic;
+ // FIXME: This only works because storage class specifiers are not allowed
+ // on decomposition declarations.
+ if (isa<BindingDecl>(ExtendingDecl))
+ return ExtendingDecl->getDeclContext()->isFunctionOrMethod() ? SD_Automatic
+ : SD_Static;
+ return cast<VarDecl>(ExtendingDecl)->getStorageDuration();
+}
+
+APValue *LifetimeExtendedTemporaryDecl::getOrCreateValue(bool MayCreate) const {
+ assert(getStorageDuration() == SD_Static &&
+ "don't need to cache the computed value for this temporary");
+ if (MayCreate && !Value) {
+ Value = (new (getASTContext()) APValue);
+ getASTContext().addDestruction(Value);
+ }
+ assert(Value && "may not be null");
+ return Value;
+}
+
void UsingShadowDecl::anchor() {}
UsingShadowDecl::UsingShadowDecl(Kind K, ASTContext &C, DeclContext *DC,
diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp
index bf748fbab8e9..9a84e3c4a510 100644
--- a/clang/lib/AST/DeclObjC.cpp
+++ b/clang/lib/AST/DeclObjC.cpp
@@ -775,14 +775,12 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupPrivateMethod(
// ObjCMethodDecl
//===----------------------------------------------------------------------===//
-ObjCMethodDecl::ObjCMethodDecl(SourceLocation beginLoc, SourceLocation endLoc,
- Selector SelInfo, QualType T,
- TypeSourceInfo *ReturnTInfo,
- DeclContext *contextDecl, bool isInstance,
- bool isVariadic, bool isPropertyAccessor,
- bool isImplicitlyDeclared, bool isDefined,
- ImplementationControl impControl,
- bool HasRelatedResultType)
+ObjCMethodDecl::ObjCMethodDecl(
+ SourceLocation beginLoc, SourceLocation endLoc, Selector SelInfo,
+ QualType T, TypeSourceInfo *ReturnTInfo, DeclContext *contextDecl,
+ bool isInstance, bool isVariadic, bool isPropertyAccessor,
+ bool isSynthesizedAccessorStub, bool isImplicitlyDeclared, bool isDefined,
+ ImplementationControl impControl, bool HasRelatedResultType)
: NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo),
DeclContext(ObjCMethod), MethodDeclType(T), ReturnTInfo(ReturnTInfo),
DeclEndLoc(endLoc) {
@@ -793,6 +791,7 @@ ObjCMethodDecl::ObjCMethodDecl(SourceLocation beginLoc, SourceLocation endLoc,
setInstanceMethod(isInstance);
setVariadic(isVariadic);
setPropertyAccessor(isPropertyAccessor);
+ setSynthesizedAccessorStub(isSynthesizedAccessorStub);
setDefined(isDefined);
setIsRedeclaration(false);
setHasRedeclaration(false);
@@ -810,12 +809,13 @@ ObjCMethodDecl *ObjCMethodDecl::Create(
ASTContext &C, SourceLocation beginLoc, SourceLocation endLoc,
Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo,
DeclContext *contextDecl, bool isInstance, bool isVariadic,
- bool isPropertyAccessor, bool isImplicitlyDeclared, bool isDefined,
- ImplementationControl impControl, bool HasRelatedResultType) {
+ bool isPropertyAccessor, bool isSynthesizedAccessorStub,
+ bool isImplicitlyDeclared, bool isDefined, ImplementationControl impControl,
+ bool HasRelatedResultType) {
return new (C, contextDecl) ObjCMethodDecl(
beginLoc, endLoc, SelInfo, T, ReturnTInfo, contextDecl, isInstance,
- isVariadic, isPropertyAccessor, isImplicitlyDeclared, isDefined,
- impControl, HasRelatedResultType);
+ isVariadic, isPropertyAccessor, isSynthesizedAccessorStub,
+ isImplicitlyDeclared, isDefined, impControl, HasRelatedResultType);
}
ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
@@ -823,6 +823,10 @@ ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
Selector(), QualType(), nullptr, nullptr);
}
+bool ObjCMethodDecl::isDirectMethod() const {
+ return hasAttr<ObjCDirectAttr>();
+}
+
bool ObjCMethodDecl::isThisDeclarationADesignatedInitializer() const {
return getMethodFamily() == OMF_init &&
hasAttr<ObjCDesignatedInitializerAttr>();
@@ -952,24 +956,32 @@ ObjCMethodDecl *ObjCMethodDecl::getNextRedeclarationImpl() {
ObjCMethodDecl *ObjCMethodDecl::getCanonicalDecl() {
auto *CtxD = cast<Decl>(getDeclContext());
+ const auto &Sel = getSelector();
if (auto *ImplD = dyn_cast<ObjCImplementationDecl>(CtxD)) {
- if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface())
- if (ObjCMethodDecl *MD = IFD->getMethod(getSelector(),
- isInstanceMethod()))
+ if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface()) {
+ // When the container is the ObjCImplementationDecl (the primary
+ // @implementation), then the canonical Decl is either in
+ // the class Interface, or in any of its extension.
+ //
+ // So when we don't find it in the ObjCInterfaceDecl,
+ // sift through extensions too.
+ if (ObjCMethodDecl *MD = IFD->getMethod(Sel, isInstanceMethod()))
return MD;
+ for (auto *Ext : IFD->known_extensions())
+ if (ObjCMethodDecl *MD = Ext->getMethod(Sel, isInstanceMethod()))
+ return MD;
+ }
} else if (auto *CImplD = dyn_cast<ObjCCategoryImplDecl>(CtxD)) {
if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl())
- if (ObjCMethodDecl *MD = CatD->getMethod(getSelector(),
- isInstanceMethod()))
+ if (ObjCMethodDecl *MD = CatD->getMethod(Sel, isInstanceMethod()))
return MD;
}
if (isRedeclaration()) {
// It is possible that we have not done deserializing the ObjCMethod yet.
ObjCMethodDecl *MD =
- cast<ObjCContainerDecl>(CtxD)->getMethod(getSelector(),
- isInstanceMethod());
+ cast<ObjCContainerDecl>(CtxD)->getMethod(Sel, isInstanceMethod());
return MD ? MD : this;
}
@@ -1077,7 +1089,7 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const {
QualType ObjCMethodDecl::getSelfType(ASTContext &Context,
const ObjCInterfaceDecl *OID,
bool &selfIsPseudoStrong,
- bool &selfIsConsumed) {
+ bool &selfIsConsumed) const {
QualType selfTy;
selfIsPseudoStrong = false;
selfIsConsumed = false;
@@ -1306,6 +1318,11 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const {
if (isPropertyAccessor()) {
const auto *Container = cast<ObjCContainerDecl>(getParent());
+ // For accessor stubs, go back to the interface.
+ if (auto *ImplDecl = dyn_cast<ObjCImplDecl>(Container))
+ if (isSynthesizedAccessorStub())
+ Container = ImplDecl->getClassInterface();
+
bool IsGetter = (NumArgs == 0);
bool IsInstance = isInstanceMethod();
@@ -1358,6 +1375,15 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const {
}
}
+ assert(isSynthesizedAccessorStub() && "expected an accessor stub");
+ for (const auto *Cat : ClassDecl->known_categories()) {
+ if (Cat == Container)
+ continue;
+
+ if (const auto *Found = findMatchingProperty(Cat))
+ return Found;
+ }
+
llvm_unreachable("Marked as a property accessor but no property found!");
}
diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index 608b0b44072b..4cedcbed0644 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -108,8 +108,8 @@ namespace {
void printTemplateParameters(const TemplateParameterList *Params,
bool OmitTemplateKW = false);
- void printTemplateArguments(const TemplateArgumentList &Args,
- const TemplateParameterList *Params = nullptr);
+ void printTemplateArguments(llvm::ArrayRef<TemplateArgument> Args);
+ void printTemplateArguments(llvm::ArrayRef<TemplateArgumentLoc> Args);
void prettyPrintAttributes(Decl *D);
void prettyPrintPragmas(Decl *D);
void printDeclType(QualType T, StringRef DeclName, bool Pack = false);
@@ -625,21 +625,26 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (Policy.FullyQualifiedName) {
Proto += D->getQualifiedNameAsString();
} else {
+ llvm::raw_string_ostream OS(Proto);
if (!Policy.SuppressScope) {
if (const NestedNameSpecifier *NS = D->getQualifier()) {
- llvm::raw_string_ostream OS(Proto);
NS->print(OS, Policy);
}
}
- Proto += D->getNameInfo().getAsString();
+ D->getNameInfo().printName(OS, Policy);
}
if (GuideDecl)
Proto = GuideDecl->getDeducedTemplate()->getDeclName().getAsString();
- if (const TemplateArgumentList *TArgs = D->getTemplateSpecializationArgs()) {
+ if (D->isFunctionTemplateSpecialization()) {
llvm::raw_string_ostream POut(Proto);
DeclPrinter TArgPrinter(POut, SubPolicy, Context, Indentation);
- TArgPrinter.printTemplateArguments(*TArgs);
+ const auto *TArgAsWritten = D->getTemplateSpecializationArgsAsWritten();
+ if (TArgAsWritten && !Policy.PrintCanonicalTypes)
+ TArgPrinter.printTemplateArguments(TArgAsWritten->arguments());
+ else if (const TemplateArgumentList *TArgs =
+ D->getTemplateSpecializationArgs())
+ TArgPrinter.printTemplateArguments(TArgs->asArray());
}
QualType Ty = D->getType();
@@ -735,6 +740,11 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
Proto.clear();
}
Out << Proto;
+
+ if (Expr *TrailingRequiresClause = D->getTrailingRequiresClause()) {
+ Out << " requires ";
+ TrailingRequiresClause->printPretty(Out, nullptr, SubPolicy, Indentation);
+ }
} else {
Ty.print(Out, Policy, Proto);
}
@@ -957,10 +967,15 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
if (D->getIdentifier()) {
Out << ' ' << *D;
- if (auto S = dyn_cast<ClassTemplatePartialSpecializationDecl>(D))
- printTemplateArguments(S->getTemplateArgs(), S->getTemplateParameters());
- else if (auto S = dyn_cast<ClassTemplateSpecializationDecl>(D))
- printTemplateArguments(S->getTemplateArgs());
+ if (auto S = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
+ ArrayRef<TemplateArgument> Args = S->getTemplateArgs().asArray();
+ if (!Policy.PrintCanonicalTypes)
+ if (const auto* TSI = S->getTypeAsWritten())
+ if (const auto *TST =
+ dyn_cast<TemplateSpecializationType>(TSI->getType()))
+ Args = TST->template_arguments();
+ printTemplateArguments(Args);
+ }
}
if (D->isCompleteDefinition()) {
@@ -1001,19 +1016,12 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
const char *l;
- switch (D->getLanguage()) {
- case LinkageSpecDecl::lang_c:
+ if (D->getLanguage() == LinkageSpecDecl::lang_c)
l = "C";
- break;
- case LinkageSpecDecl::lang_cxx_14:
- l = "C++14";
- break;
- case LinkageSpecDecl::lang_cxx_11:
- l = "C++11";
- break;
- case LinkageSpecDecl::lang_cxx:
+ else {
+ assert(D->getLanguage() == LinkageSpecDecl::lang_cxx &&
+ "unknown language in linkage specification");
l = "C++";
- break;
}
Out << "extern \"" << l << "\" ";
@@ -1045,7 +1053,9 @@ void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params,
if (auto TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
- if (TTP->wasDeclaredWithTypename())
+ if (const TypeConstraint *TC = TTP->getTypeConstraint())
+ TC->print(Out, Policy);
+ else if (TTP->wasDeclaredWithTypename())
Out << "typename";
else
Out << "class";
@@ -1083,40 +1093,22 @@ void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params,
Out << ' ';
}
-void DeclPrinter::printTemplateArguments(const TemplateArgumentList &Args,
- const TemplateParameterList *Params) {
+void DeclPrinter::printTemplateArguments(ArrayRef<TemplateArgument> Args) {
Out << "<";
for (size_t I = 0, E = Args.size(); I < E; ++I) {
- const TemplateArgument &A = Args[I];
if (I)
Out << ", ";
- if (Params) {
- if (A.getKind() == TemplateArgument::Type)
- if (auto T = A.getAsType()->getAs<TemplateTypeParmType>()) {
- auto P = cast<TemplateTypeParmDecl>(Params->getParam(T->getIndex()));
- Out << *P;
- continue;
- }
- if (A.getKind() == TemplateArgument::Template) {
- if (auto T = A.getAsTemplate().getAsTemplateDecl())
- if (auto TD = dyn_cast<TemplateTemplateParmDecl>(T)) {
- auto P = cast<TemplateTemplateParmDecl>(
- Params->getParam(TD->getIndex()));
- Out << *P;
- continue;
- }
- }
- if (A.getKind() == TemplateArgument::Expression) {
- if (auto E = dyn_cast<DeclRefExpr>(A.getAsExpr()))
- if (auto N = dyn_cast<NonTypeTemplateParmDecl>(E->getDecl())) {
- auto P = cast<NonTypeTemplateParmDecl>(
- Params->getParam(N->getIndex()));
- Out << *P;
- continue;
- }
- }
- }
- A.print(Policy, Out);
+ Args[I].print(Policy, Out);
+ }
+ Out << ">";
+}
+
+void DeclPrinter::printTemplateArguments(ArrayRef<TemplateArgumentLoc> Args) {
+ Out << "<";
+ for (size_t I = 0, E = Args.size(); I < E; ++I) {
+ if (I)
+ Out << ", ";
+ Args[I].getArgument().print(Policy, Out);
}
Out << ">";
}
@@ -1469,6 +1461,11 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
first = false;
}
+ if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_direct) {
+ Out << (first ? "" : ", ") << "direct";
+ first = false;
+ }
+
if (PDecl->getPropertyAttributes() &
ObjCPropertyDecl::OBJC_PR_nonatomic) {
Out << (first ? "" : ", ") << "nonatomic";
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 7e013c6c54d8..95a2e26e0df8 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -43,35 +43,46 @@ using namespace clang;
// TemplateParameterList Implementation
//===----------------------------------------------------------------------===//
-TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc,
+
+TemplateParameterList::TemplateParameterList(const ASTContext& C,
+ SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
ArrayRef<NamedDecl *> Params,
SourceLocation RAngleLoc,
Expr *RequiresClause)
: TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc),
NumParams(Params.size()), ContainsUnexpandedParameterPack(false),
- HasRequiresClause(static_cast<bool>(RequiresClause)) {
+ HasRequiresClause(RequiresClause != nullptr),
+ HasConstrainedParameters(false) {
for (unsigned Idx = 0; Idx < NumParams; ++Idx) {
NamedDecl *P = Params[Idx];
begin()[Idx] = P;
- if (!P->isTemplateParameterPack()) {
- if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P))
- if (NTTP->getType()->containsUnexpandedParameterPack())
- ContainsUnexpandedParameterPack = true;
-
- if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(P))
- if (TTP->getTemplateParameters()->containsUnexpandedParameterPack())
- ContainsUnexpandedParameterPack = true;
-
- // FIXME: If a default argument contains an unexpanded parameter pack, the
- // template parameter list does too.
+ bool IsPack = P->isTemplateParameterPack();
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) {
+ if (!IsPack && NTTP->getType()->containsUnexpandedParameterPack())
+ ContainsUnexpandedParameterPack = true;
+ if (NTTP->hasPlaceholderTypeConstraint())
+ HasConstrainedParameters = true;
+ } else if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(P)) {
+ if (!IsPack &&
+ TTP->getTemplateParameters()->containsUnexpandedParameterPack())
+ ContainsUnexpandedParameterPack = true;
+ } else if (const TypeConstraint *TC =
+ cast<TemplateTypeParmDecl>(P)->getTypeConstraint()) {
+ if (TC->getImmediatelyDeclaredConstraint()
+ ->containsUnexpandedParameterPack())
+ ContainsUnexpandedParameterPack = true;
+ HasConstrainedParameters = true;
}
+ // FIXME: If a default argument contains an unexpanded parameter pack, the
+ // template parameter list does too.
}
- if (RequiresClause) {
- *getTrailingObjects<Expr *>() = RequiresClause;
+
+ if (HasRequiresClause) {
if (RequiresClause->containsUnexpandedParameterPack())
ContainsUnexpandedParameterPack = true;
+ *getTrailingObjects<Expr *>() = RequiresClause;
}
}
@@ -83,7 +94,7 @@ TemplateParameterList::Create(const ASTContext &C, SourceLocation TemplateLoc,
void *Mem = C.Allocate(totalSizeToAlloc<NamedDecl *, Expr *>(
Params.size(), RequiresClause ? 1u : 0u),
alignof(TemplateParameterList));
- return new (Mem) TemplateParameterList(TemplateLoc, LAngleLoc, Params,
+ return new (Mem) TemplateParameterList(C, TemplateLoc, LAngleLoc, Params,
RAngleLoc, RequiresClause);
}
@@ -91,11 +102,23 @@ unsigned TemplateParameterList::getMinRequiredArguments() const {
unsigned NumRequiredArgs = 0;
for (const NamedDecl *P : asArray()) {
if (P->isTemplateParameterPack()) {
- if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P))
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) {
if (NTTP->isExpandedParameterPack()) {
NumRequiredArgs += NTTP->getNumExpansionTypes();
continue;
}
+ } else if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(P)) {
+ if (TTP->isExpandedParameterPack()) {
+ NumRequiredArgs += TTP->getNumExpansionParameters();
+ continue;
+ }
+ } else {
+ const auto *TP = cast<TemplateTemplateParmDecl>(P);
+ if (TP->isExpandedParameterPack()) {
+ NumRequiredArgs += TP->getNumExpansionTemplateParameters();
+ continue;
+ }
+ }
break;
}
@@ -140,14 +163,17 @@ static void AdoptTemplateParameterList(TemplateParameterList *Params,
void TemplateParameterList::
getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
- // TODO: Concepts: Collect immediately-introduced constraints.
+ if (HasConstrainedParameters)
+ for (const NamedDecl *Param : *this)
+ if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
+ if (const auto *TC = TTP->getTypeConstraint())
+ AC.push_back(TC->getImmediatelyDeclaredConstraint());
if (HasRequiresClause)
AC.push_back(getRequiresClause());
}
bool TemplateParameterList::hasAssociatedConstraints() const {
- // TODO: Concepts: Regard immediately-introduced constraints.
- return HasRequiresClause;
+ return HasRequiresClause || HasConstrainedParameters;
}
namespace clang {
@@ -171,13 +197,18 @@ void TemplateDecl::anchor() {}
void TemplateDecl::
getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
- // TODO: Concepts: Append function trailing requires clause.
TemplateParams->getAssociatedConstraints(AC);
+ if (auto *FD = dyn_cast_or_null<FunctionDecl>(getTemplatedDecl()))
+ if (const Expr *TRC = FD->getTrailingRequiresClause())
+ AC.push_back(TRC);
}
bool TemplateDecl::hasAssociatedConstraints() const {
- // TODO: Concepts: Regard function trailing requires clause.
- return TemplateParams->hasAssociatedConstraints();
+ if (TemplateParams->hasAssociatedConstraints())
+ return true;
+ if (auto *FD = dyn_cast_or_null<FunctionDecl>(getTemplatedDecl()))
+ return FD->getTrailingRequiresClause();
+ return false;
}
//===----------------------------------------------------------------------===//
@@ -231,15 +262,16 @@ void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const {
}
}
-template<class EntryType>
+template<class EntryType, typename... ProfileArguments>
typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType *
RedeclarableTemplateDecl::findSpecializationImpl(
- llvm::FoldingSetVector<EntryType> &Specs, ArrayRef<TemplateArgument> Args,
- void *&InsertPos) {
+ llvm::FoldingSetVector<EntryType> &Specs, void *&InsertPos,
+ ProfileArguments&&... ProfileArgs) {
using SETraits = SpecEntryTraits<EntryType>;
llvm::FoldingSetNodeID ID;
- EntryType::Profile(ID, Args, getASTContext());
+ EntryType::Profile(ID, std::forward<ProfileArguments>(ProfileArgs)...,
+ getASTContext());
EntryType *Entry = Specs.FindNodeOrInsertPos(ID, InsertPos);
return Entry ? SETraits::getDecl(Entry)->getMostRecentDecl() : nullptr;
}
@@ -254,8 +286,8 @@ void RedeclarableTemplateDecl::addSpecializationImpl(
#ifndef NDEBUG
void *CorrectInsertPos;
assert(!findSpecializationImpl(Specializations,
- SETraits::getTemplateArgs(Entry),
- CorrectInsertPos) &&
+ CorrectInsertPos,
+ SETraits::getTemplateArgs(Entry)) &&
InsertPos == CorrectInsertPos &&
"given incorrect InsertPos for specialization");
#endif
@@ -312,7 +344,7 @@ FunctionTemplateDecl::getSpecializations() const {
FunctionDecl *
FunctionTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
void *&InsertPos) {
- return findSpecializationImpl(getSpecializations(), Args, InsertPos);
+ return findSpecializationImpl(getSpecializations(), InsertPos, Args);
}
void FunctionTemplateDecl::addSpecialization(
@@ -418,7 +450,7 @@ ClassTemplateDecl::newCommon(ASTContext &C) const {
ClassTemplateSpecializationDecl *
ClassTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
void *&InsertPos) {
- return findSpecializationImpl(getSpecializations(), Args, InsertPos);
+ return findSpecializationImpl(getSpecializations(), InsertPos, Args);
}
void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D,
@@ -427,9 +459,48 @@ void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D,
}
ClassTemplatePartialSpecializationDecl *
-ClassTemplateDecl::findPartialSpecialization(ArrayRef<TemplateArgument> Args,
- void *&InsertPos) {
- return findSpecializationImpl(getPartialSpecializations(), Args, InsertPos);
+ClassTemplateDecl::findPartialSpecialization(
+ ArrayRef<TemplateArgument> Args,
+ TemplateParameterList *TPL, void *&InsertPos) {
+ return findSpecializationImpl(getPartialSpecializations(), InsertPos, Args,
+ TPL);
+}
+
+static void ProfileTemplateParameterList(ASTContext &C,
+ llvm::FoldingSetNodeID &ID, const TemplateParameterList *TPL) {
+ const Expr *RC = TPL->getRequiresClause();
+ ID.AddBoolean(RC != nullptr);
+ if (RC)
+ RC->Profile(ID, C, /*Canonical=*/true);
+ ID.AddInteger(TPL->size());
+ for (NamedDecl *D : *TPL) {
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {
+ ID.AddInteger(0);
+ ID.AddBoolean(NTTP->isParameterPack());
+ NTTP->getType().getCanonicalType().Profile(ID);
+ continue;
+ }
+ if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(D)) {
+ ID.AddInteger(1);
+ ID.AddBoolean(TTP->isParameterPack());
+ // TODO: Concepts: profile type-constraints.
+ continue;
+ }
+ const auto *TTP = cast<TemplateTemplateParmDecl>(D);
+ ID.AddInteger(2);
+ ID.AddBoolean(TTP->isParameterPack());
+ ProfileTemplateParameterList(C, ID, TTP->getTemplateParameters());
+ }
+}
+
+void
+ClassTemplatePartialSpecializationDecl::Profile(llvm::FoldingSetNodeID &ID,
+ ArrayRef<TemplateArgument> TemplateArgs, TemplateParameterList *TPL,
+ ASTContext &Context) {
+ ID.AddInteger(TemplateArgs.size());
+ for (const TemplateArgument &TemplateArg : TemplateArgs)
+ TemplateArg.Profile(ID, Context);
+ ProfileTemplateParameterList(Context, ID, TPL);
}
void ClassTemplateDecl::AddPartialSpecialization(
@@ -513,9 +584,14 @@ TemplateTypeParmDecl *
TemplateTypeParmDecl::Create(const ASTContext &C, DeclContext *DC,
SourceLocation KeyLoc, SourceLocation NameLoc,
unsigned D, unsigned P, IdentifierInfo *Id,
- bool Typename, bool ParameterPack) {
+ bool Typename, bool ParameterPack,
+ bool HasTypeConstraint,
+ Optional<unsigned> NumExpanded) {
auto *TTPDecl =
- new (C, DC) TemplateTypeParmDecl(DC, KeyLoc, NameLoc, Id, Typename);
+ new (C, DC,
+ additionalSizeToAlloc<TypeConstraint>(HasTypeConstraint ? 1 : 0))
+ TemplateTypeParmDecl(DC, KeyLoc, NameLoc, Id, Typename,
+ HasTypeConstraint, NumExpanded);
QualType TTPType = C.getTemplateTypeParmType(D, P, ParameterPack, TTPDecl);
TTPDecl->setTypeForDecl(TTPType.getTypePtr());
return TTPDecl;
@@ -524,7 +600,17 @@ 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);
+ SourceLocation(), nullptr, false,
+ false, None);
+}
+
+TemplateTypeParmDecl *
+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);
}
SourceLocation TemplateTypeParmDecl::getDefaultArgumentLoc() const {
@@ -557,6 +643,20 @@ bool TemplateTypeParmDecl::isParameterPack() const {
return getTypeForDecl()->castAs<TemplateTypeParmType>()->isParameterPack();
}
+void TemplateTypeParmDecl::setTypeConstraint(NestedNameSpecifierLoc NNS,
+ DeclarationNameInfo NameInfo, NamedDecl *FoundDecl, ConceptDecl *CD,
+ const ASTTemplateArgumentListInfo *ArgsAsWritten,
+ Expr *ImmediatelyDeclaredConstraint) {
+ assert(HasTypeConstraint &&
+ "HasTypeConstraint=true must be passed at construction in order to "
+ "call setTypeConstraint");
+ assert(!TypeConstraintInitialized &&
+ "TypeConstraint was already initialized!");
+ new (getTrailingObjects<TypeConstraint>()) TypeConstraint(NNS, NameInfo,
+ FoundDecl, CD, ArgsAsWritten, ImmediatelyDeclaredConstraint);
+ TypeConstraintInitialized = true;
+}
+
//===----------------------------------------------------------------------===//
// NonTypeTemplateParmDecl Method Implementations
//===----------------------------------------------------------------------===//
@@ -1035,7 +1135,7 @@ VarTemplateDecl::newCommon(ASTContext &C) const {
VarTemplateSpecializationDecl *
VarTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
void *&InsertPos) {
- return findSpecializationImpl(getSpecializations(), Args, InsertPos);
+ return findSpecializationImpl(getSpecializations(), InsertPos, Args);
}
void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D,
@@ -1045,8 +1145,19 @@ void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D,
VarTemplatePartialSpecializationDecl *
VarTemplateDecl::findPartialSpecialization(ArrayRef<TemplateArgument> Args,
- void *&InsertPos) {
- return findSpecializationImpl(getPartialSpecializations(), Args, InsertPos);
+ TemplateParameterList *TPL, void *&InsertPos) {
+ return findSpecializationImpl(getPartialSpecializations(), InsertPos, Args,
+ TPL);
+}
+
+void
+VarTemplatePartialSpecializationDecl::Profile(llvm::FoldingSetNodeID &ID,
+ ArrayRef<TemplateArgument> TemplateArgs, TemplateParameterList *TPL,
+ ASTContext &Context) {
+ ID.AddInteger(TemplateArgs.size());
+ for (const TemplateArgument &TemplateArg : TemplateArgs)
+ TemplateArg.Profile(ID, Context);
+ ProfileTemplateParameterList(Context, ID, TPL);
}
void VarTemplateDecl::AddPartialSpecialization(
@@ -1200,7 +1311,8 @@ createMakeIntegerSeqParameterList(const ASTContext &C, DeclContext *DC) {
// typename T
auto *T = TemplateTypeParmDecl::Create(
C, DC, SourceLocation(), SourceLocation(), /*Depth=*/1, /*Position=*/0,
- /*Id=*/nullptr, /*Typename=*/true, /*ParameterPack=*/false);
+ /*Id=*/nullptr, /*Typename=*/true, /*ParameterPack=*/false,
+ /*HasTypeConstraint=*/false);
T->setImplicit(true);
// T ...Ints
@@ -1225,7 +1337,8 @@ createMakeIntegerSeqParameterList(const ASTContext &C, DeclContext *DC) {
// typename T
auto *TemplateTypeParm = TemplateTypeParmDecl::Create(
C, DC, SourceLocation(), SourceLocation(), /*Depth=*/0, /*Position=*/1,
- /*Id=*/nullptr, /*Typename=*/true, /*ParameterPack=*/false);
+ /*Id=*/nullptr, /*Typename=*/true, /*ParameterPack=*/false,
+ /*HasTypeConstraint=*/false);
TemplateTypeParm->setImplicit(true);
// T N
@@ -1253,7 +1366,8 @@ createTypePackElementParameterList(const ASTContext &C, DeclContext *DC) {
// typename ...T
auto *Ts = TemplateTypeParmDecl::Create(
C, DC, SourceLocation(), SourceLocation(), /*Depth=*/0, /*Position=*/1,
- /*Id=*/nullptr, /*Typename=*/true, /*ParameterPack=*/true);
+ /*Id=*/nullptr, /*Typename=*/true, /*ParameterPack=*/true,
+ /*HasTypeConstraint=*/false);
Ts->setImplicit(true);
// template <std::size_t Index, typename ...T>
@@ -1283,3 +1397,15 @@ BuiltinTemplateDecl::BuiltinTemplateDecl(const ASTContext &C, DeclContext *DC,
: TemplateDecl(BuiltinTemplate, DC, SourceLocation(), Name,
createBuiltinTemplateParameterList(C, DC, BTK)),
BTK(BTK) {}
+
+void TypeConstraint::print(llvm::raw_ostream &OS, PrintingPolicy Policy) const {
+ if (NestedNameSpec)
+ NestedNameSpec.getNestedNameSpecifier()->print(OS, Policy);
+ ConceptName.printName(OS, Policy);
+ if (hasExplicitTemplateArgs()) {
+ OS << "<";
+ for (auto &ArgLoc : ArgsAsWritten->arguments())
+ ArgLoc.getArgument().print(Policy, OS);
+ OS << ">";
+ }
+} \ No newline at end of file
diff --git a/clang/lib/AST/DeclarationName.cpp b/clang/lib/AST/DeclarationName.cpp
index fe69c71aa3dd..4eb11bc57e52 100644
--- a/clang/lib/AST/DeclarationName.cpp
+++ b/clang/lib/AST/DeclarationName.cpp
@@ -134,7 +134,8 @@ static void printCXXConstructorDestructorName(QualType ClassType,
ClassType.print(OS, Policy);
}
-void DeclarationName::print(raw_ostream &OS, const PrintingPolicy &Policy) {
+void DeclarationName::print(raw_ostream &OS,
+ const PrintingPolicy &Policy) const {
switch (getNameKind()) {
case DeclarationName::Identifier:
if (const IdentifierInfo *II = getAsIdentifierInfo())
@@ -447,11 +448,17 @@ bool DeclarationNameInfo::isInstantiationDependent() const {
std::string DeclarationNameInfo::getAsString() const {
std::string Result;
llvm::raw_string_ostream OS(Result);
- printName(OS);
+ OS << *this;
return OS.str();
}
-void DeclarationNameInfo::printName(raw_ostream &OS) const {
+raw_ostream &clang::operator<<(raw_ostream &OS, DeclarationNameInfo DNInfo) {
+ LangOptions LO;
+ DNInfo.printName(OS, PrintingPolicy(LangOptions()));
+ return OS;
+}
+
+void DeclarationNameInfo::printName(raw_ostream &OS, PrintingPolicy Policy) const {
switch (Name.getNameKind()) {
case DeclarationName::Identifier:
case DeclarationName::ObjCZeroArgSelector:
@@ -461,7 +468,7 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const {
case DeclarationName::CXXLiteralOperatorName:
case DeclarationName::CXXUsingDirective:
case DeclarationName::CXXDeductionGuideName:
- OS << Name;
+ Name.print(OS, Policy);
return;
case DeclarationName::CXXConstructorName:
@@ -473,13 +480,11 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const {
else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName)
OS << "operator ";
LangOptions LO;
- LO.CPlusPlus = true;
- LO.Bool = true;
- PrintingPolicy PP(LO);
- PP.SuppressScope = true;
- OS << TInfo->getType().getAsString(PP);
+ Policy.adjustForCPlusPlus();
+ Policy.SuppressScope = true;
+ OS << TInfo->getType().getAsString(Policy);
} else
- OS << Name;
+ Name.print(OS, Policy);
return;
}
llvm_unreachable("Unexpected declaration name kind");
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 3438c3aadc6b..73ddbc62482d 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -49,7 +49,7 @@ const Expr *Expr::getBestDynamicClassTypeExpr() const {
// Step into initializer for materialized temporaries.
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) {
- E = MTE->GetTemporaryExpr();
+ E = MTE->getSubExpr();
continue;
}
@@ -127,11 +127,7 @@ const Expr *Expr::skipRValueSubobjectAdjustments(
return E;
}
-/// isKnownToHaveBooleanValue - Return true if this is an integer expression
-/// that is known to return 0 or 1. This happens for _Bool/bool expressions
-/// but also int expressions which are produced by things like comparisons in
-/// C.
-bool Expr::isKnownToHaveBooleanValue() const {
+bool Expr::isKnownToHaveBooleanValue(bool Semantic) const {
const Expr *E = IgnoreParens();
// If this value has _Bool type, it is obvious 0/1.
@@ -142,7 +138,7 @@ bool Expr::isKnownToHaveBooleanValue() const {
if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
switch (UO->getOpcode()) {
case UO_Plus:
- return UO->getSubExpr()->isKnownToHaveBooleanValue();
+ return UO->getSubExpr()->isKnownToHaveBooleanValue(Semantic);
case UO_LNot:
return true;
default:
@@ -152,8 +148,9 @@ bool Expr::isKnownToHaveBooleanValue() const {
// Only look through implicit casts. If the user writes
// '(int) (a && b)' treat it as an arbitrary int.
+ // FIXME: Should we look through any cast expression in !Semantic mode?
if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E))
- return CE->getSubExpr()->isKnownToHaveBooleanValue();
+ return CE->getSubExpr()->isKnownToHaveBooleanValue(Semantic);
if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
switch (BO->getOpcode()) {
@@ -172,24 +169,30 @@ bool Expr::isKnownToHaveBooleanValue() const {
case BO_Xor: // Bitwise XOR operator.
case BO_Or: // Bitwise OR operator.
// Handle things like (x==2)|(y==12).
- return BO->getLHS()->isKnownToHaveBooleanValue() &&
- BO->getRHS()->isKnownToHaveBooleanValue();
+ return BO->getLHS()->isKnownToHaveBooleanValue(Semantic) &&
+ BO->getRHS()->isKnownToHaveBooleanValue(Semantic);
case BO_Comma:
case BO_Assign:
- return BO->getRHS()->isKnownToHaveBooleanValue();
+ return BO->getRHS()->isKnownToHaveBooleanValue(Semantic);
}
}
if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E))
- return CO->getTrueExpr()->isKnownToHaveBooleanValue() &&
- CO->getFalseExpr()->isKnownToHaveBooleanValue();
+ return CO->getTrueExpr()->isKnownToHaveBooleanValue(Semantic) &&
+ CO->getFalseExpr()->isKnownToHaveBooleanValue(Semantic);
if (isa<ObjCBoolLiteralExpr>(E))
return true;
if (const auto *OVE = dyn_cast<OpaqueValueExpr>(E))
- return OVE->getSourceExpr()->isKnownToHaveBooleanValue();
+ return OVE->getSourceExpr()->isKnownToHaveBooleanValue(Semantic);
+
+ if (const FieldDecl *FD = E->getSourceBitField())
+ if (!Semantic && FD->getType()->isUnsignedIntegerType() &&
+ !FD->getBitWidth()->isValueDependent() &&
+ FD->getBitWidthValue(FD->getASTContext()) == 1)
+ return true;
return false;
}
@@ -1675,6 +1678,15 @@ MemberExpr *MemberExpr::Create(
MemberExpr *E = new (Mem) MemberExpr(Base, IsArrow, OperatorLoc, MemberDecl,
NameInfo, T, VK, OK, NOUR);
+ if (isa<FieldDecl>(MemberDecl)) {
+ DeclContext *DC = MemberDecl->getDeclContext();
+ // dyn_cast_or_null is used to handle objC variables which do not
+ // have a declaration context.
+ CXXRecordDecl *RD = dyn_cast_or_null<CXXRecordDecl>(DC);
+ if (RD && RD->isDependentContext() && RD->isCurrentInstantiation(DC))
+ E->setTypeDependent(T->isDependentType());
+ }
+
if (HasQualOrFound) {
// FIXME: Wrong. We should be looking at the member declaration we found.
if (QualifierLoc && QualifierLoc.getNestedNameSpecifier()->isDependent()) {
@@ -1811,7 +1823,7 @@ bool CastExpr::CastConsistency() const {
auto Ty = getType();
auto SETy = getSubExpr()->getType();
assert(getValueKindForType(Ty) == Expr::getValueKindForType(SETy));
- if (/*isRValue()*/ !Ty->getPointeeType().isNull()) {
+ if (isRValue()) {
Ty = Ty->getPointeeType();
SETy = SETy->getPointeeType();
}
@@ -1891,7 +1903,7 @@ namespace {
const Expr *skipImplicitTemporary(const Expr *E) {
// Skip through reference binding to temporary.
if (auto *Materialize = dyn_cast<MaterializeTemporaryExpr>(E))
- E = Materialize->GetTemporaryExpr();
+ E = Materialize->getSubExpr();
// Skip any temporary bindings; they're implicit.
if (auto *Binder = dyn_cast<CXXBindTemporaryExpr>(E))
@@ -2721,8 +2733,9 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
case CXXDeleteExprClass:
return false;
case MaterializeTemporaryExprClass:
- return cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr()
- ->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
+ return cast<MaterializeTemporaryExpr>(this)
+ ->getSubExpr()
+ ->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
case CXXBindTemporaryExprClass:
return cast<CXXBindTemporaryExpr>(this)->getSubExpr()
->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
@@ -2746,8 +2759,8 @@ bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const {
case ImplicitCastExprClass:
return cast<ImplicitCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
case MaterializeTemporaryExprClass:
- return cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr()
- ->isOBJCGCCandidate(Ctx);
+ return cast<MaterializeTemporaryExpr>(E)->getSubExpr()->isOBJCGCCandidate(
+ Ctx);
case CStyleCastExprClass:
return cast<CStyleCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
case DeclRefExprClass: {
@@ -2822,7 +2835,7 @@ static Expr *IgnoreImpCastsExtraSingleStep(Expr *E) {
return SubE;
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
- return MTE->GetTemporaryExpr();
+ return MTE->getSubExpr();
if (auto *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(E))
return NTTP->getReplacement();
@@ -2838,7 +2851,7 @@ static Expr *IgnoreCastsSingleStep(Expr *E) {
return FE->getSubExpr();
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
- return MTE->GetTemporaryExpr();
+ return MTE->getSubExpr();
if (auto *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(E))
return NTTP->getReplacement();
@@ -2872,7 +2885,7 @@ static Expr *IgnoreImplicitSingleStep(Expr *E) {
return SubE;
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
- return MTE->GetTemporaryExpr();
+ return MTE->getSubExpr();
if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E))
return BTE->getSubExpr();
@@ -2880,6 +2893,13 @@ static Expr *IgnoreImplicitSingleStep(Expr *E) {
return E;
}
+static Expr *IgnoreImplicitAsWrittenSingleStep(Expr *E) {
+ if (auto *ICE = dyn_cast<ImplicitCastExpr>(E))
+ return ICE->getSubExprAsWritten();
+
+ return IgnoreImplicitSingleStep(E);
+}
+
static Expr *IgnoreParensSingleStep(Expr *E) {
if (auto *PE = dyn_cast<ParenExpr>(E))
return PE->getSubExpr();
@@ -2959,6 +2979,10 @@ Expr *Expr::IgnoreImplicit() {
return IgnoreExprNodes(this, IgnoreImplicitSingleStep);
}
+Expr *Expr::IgnoreImplicitAsWritten() {
+ return IgnoreExprNodes(this, IgnoreImplicitAsWrittenSingleStep);
+}
+
Expr *Expr::IgnoreParens() {
return IgnoreExprNodes(this, IgnoreParensSingleStep);
}
@@ -2996,10 +3020,38 @@ Expr *Expr::IgnoreParenNoopCasts(const ASTContext &Ctx) {
});
}
+Expr *Expr::IgnoreUnlessSpelledInSource() {
+ Expr *E = this;
+
+ Expr *LastE = nullptr;
+ while (E != LastE) {
+ LastE = E;
+ E = E->IgnoreParenImpCasts();
+
+ auto SR = E->getSourceRange();
+
+ if (auto *C = dyn_cast<CXXConstructExpr>(E)) {
+ if (C->getNumArgs() == 1) {
+ Expr *A = C->getArg(0);
+ if (A->getSourceRange() == SR || !isa<CXXTemporaryObjectExpr>(C))
+ E = A;
+ }
+ }
+
+ if (auto *C = dyn_cast<CXXMemberCallExpr>(E)) {
+ Expr *ExprNode = C->getImplicitObjectArgument()->IgnoreParenImpCasts();
+ if (ExprNode->getSourceRange() == SR)
+ E = ExprNode;
+ }
+ }
+
+ return E;
+}
+
bool Expr::isDefaultArgument() const {
const Expr *E = this;
if (const MaterializeTemporaryExpr *M = dyn_cast<MaterializeTemporaryExpr>(E))
- E = M->GetTemporaryExpr();
+ E = M->getSubExpr();
while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
E = ICE->getSubExprAsWritten();
@@ -3011,7 +3063,7 @@ bool Expr::isDefaultArgument() const {
/// expressions.
static const Expr *skipTemporaryBindingsNoOpCastsAndParens(const Expr *E) {
if (const MaterializeTemporaryExpr *M = dyn_cast<MaterializeTemporaryExpr>(E))
- E = M->GetTemporaryExpr();
+ E = M->getSubExpr();
while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
if (ICE->getCastKind() == CK_NoOp)
@@ -3106,7 +3158,7 @@ bool Expr::isImplicitCXXThis() const {
if (const MaterializeTemporaryExpr *M
= dyn_cast<MaterializeTemporaryExpr>(E)) {
- E = M->GetTemporaryExpr();
+ E = M->getSubExpr();
continue;
}
@@ -3283,8 +3335,9 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
break;
}
case MaterializeTemporaryExprClass:
- return cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr()
- ->isConstantInitializer(Ctx, false, Culprit);
+ return cast<MaterializeTemporaryExpr>(this)
+ ->getSubExpr()
+ ->isConstantInitializer(Ctx, false, Culprit);
case SubstNonTypeTemplateParmExprClass:
return cast<SubstNonTypeTemplateParmExpr>(this)->getReplacement()
@@ -3751,7 +3804,7 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
return NPCK_GNUNull;
} else if (const MaterializeTemporaryExpr *M
= dyn_cast<MaterializeTemporaryExpr>(this)) {
- return M->GetTemporaryExpr()->isNullPointerConstant(Ctx, NPC);
+ return M->getSubExpr()->isNullPointerConstant(Ctx, NPC);
} else if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(this)) {
if (const Expr *Source = OVE->getSourceExpr())
return Source->isNullPointerConstant(Ctx, NPC);
@@ -4460,7 +4513,7 @@ const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) {
if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(e))
e = ewc->getSubExpr();
if (const MaterializeTemporaryExpr *m = dyn_cast<MaterializeTemporaryExpr>(e))
- e = m->GetTemporaryExpr();
+ e = m->getSubExpr();
e = cast<CXXConstructExpr>(e)->getArg(0);
while (const ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e))
e = ice->getSubExpr();
@@ -4598,6 +4651,8 @@ unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) {
case AO__c11_atomic_fetch_and:
case AO__c11_atomic_fetch_or:
case AO__c11_atomic_fetch_xor:
+ case AO__c11_atomic_fetch_max:
+ case AO__c11_atomic_fetch_min:
case AO__atomic_fetch_add:
case AO__atomic_fetch_sub:
case AO__atomic_fetch_and:
@@ -4610,6 +4665,8 @@ unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) {
case AO__atomic_or_fetch:
case AO__atomic_xor_fetch:
case AO__atomic_nand_fetch:
+ case AO__atomic_min_fetch:
+ case AO__atomic_max_fetch:
case AO__atomic_fetch_min:
case AO__atomic_fetch_max:
return 3;
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 904928bdf286..422227d787b1 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -107,7 +107,7 @@ CXXRewrittenBinaryOperator::getDecomposedForm() const {
return Result;
// Otherwise, we expect a <=> to now be on the LHS.
- E = Result.LHS->IgnoreImplicit();
+ E = Result.LHS->IgnoreImplicitAsWritten();
if (auto *BO = dyn_cast<BinaryOperator>(E)) {
assert(BO->getOpcode() == BO_Cmp);
Result.LHS = BO->getLHS();
@@ -1653,7 +1653,23 @@ FunctionParmPackExpr::CreateEmpty(const ASTContext &Context,
FunctionParmPackExpr(QualType(), nullptr, SourceLocation(), 0, nullptr);
}
-void MaterializeTemporaryExpr::setExtendingDecl(const ValueDecl *ExtendedBy,
+MaterializeTemporaryExpr::MaterializeTemporaryExpr(
+ QualType T, Expr *Temporary, bool BoundToLvalueReference,
+ LifetimeExtendedTemporaryDecl *MTD)
+ : Expr(MaterializeTemporaryExprClass, T,
+ BoundToLvalueReference ? VK_LValue : VK_XValue, OK_Ordinary,
+ Temporary->isTypeDependent(), Temporary->isValueDependent(),
+ Temporary->isInstantiationDependent(),
+ Temporary->containsUnexpandedParameterPack()) {
+ if (MTD) {
+ State = MTD;
+ MTD->ExprWithTemporary = Temporary;
+ return;
+ }
+ State = Temporary;
+}
+
+void MaterializeTemporaryExpr::setExtendingDecl(ValueDecl *ExtendedBy,
unsigned ManglingNumber) {
// We only need extra state if we have to remember more than just the Stmt.
if (!ExtendedBy)
@@ -1661,13 +1677,11 @@ void MaterializeTemporaryExpr::setExtendingDecl(const ValueDecl *ExtendedBy,
// We may need to allocate extra storage for the mangling number and the
// extended-by ValueDecl.
- if (!State.is<ExtraState *>()) {
- auto *ES = new (ExtendedBy->getASTContext()) ExtraState;
- ES->Temporary = State.get<Stmt *>();
- State = ES;
- }
+ if (!State.is<LifetimeExtendedTemporaryDecl *>())
+ State = LifetimeExtendedTemporaryDecl::Create(
+ cast<Expr>(State.get<Stmt *>()), ExtendedBy, ManglingNumber);
- auto ES = State.get<ExtraState *>();
+ auto ES = State.get<LifetimeExtendedTemporaryDecl *>();
ES->ExtendingDecl = ExtendedBy;
ES->ManglingNumber = ManglingNumber;
}
@@ -1751,44 +1765,42 @@ CUDAKernelCallExpr *CUDAKernelCallExpr::CreateEmpty(const ASTContext &Ctx,
return new (Mem) CUDAKernelCallExpr(NumArgs, Empty);
}
-ConceptSpecializationExpr::ConceptSpecializationExpr(ASTContext &C,
+ConceptSpecializationExpr::ConceptSpecializationExpr(const ASTContext &C,
NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc,
- SourceLocation ConceptNameLoc, NamedDecl *FoundDecl,
+ DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl,
ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten,
- ArrayRef<TemplateArgument> ConvertedArgs, Optional<bool> IsSatisfied)
+ ArrayRef<TemplateArgument> ConvertedArgs,
+ const ConstraintSatisfaction *Satisfaction)
: Expr(ConceptSpecializationExprClass, C.BoolTy, VK_RValue, OK_Ordinary,
/*TypeDependent=*/false,
// All the flags below are set in setTemplateArguments.
- /*ValueDependent=*/!IsSatisfied.hasValue(),
- /*InstantiationDependent=*/false,
+ /*ValueDependent=*/!Satisfaction, /*InstantiationDependent=*/false,
/*ContainsUnexpandedParameterPacks=*/false),
- NestedNameSpec(NNS), TemplateKWLoc(TemplateKWLoc),
- ConceptNameLoc(ConceptNameLoc), FoundDecl(FoundDecl),
- NamedConcept(NamedConcept, IsSatisfied ? *IsSatisfied : true),
- NumTemplateArgs(ConvertedArgs.size()) {
-
- setTemplateArguments(ArgsAsWritten, ConvertedArgs);
+ ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl,
+ NamedConcept, ArgsAsWritten),
+ NumTemplateArgs(ConvertedArgs.size()),
+ Satisfaction(Satisfaction ?
+ ASTConstraintSatisfaction::Create(C, *Satisfaction) :
+ nullptr) {
+ setTemplateArguments(ConvertedArgs);
}
ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty,
unsigned NumTemplateArgs)
- : Expr(ConceptSpecializationExprClass, Empty),
+ : Expr(ConceptSpecializationExprClass, Empty), ConceptReference(),
NumTemplateArgs(NumTemplateArgs) { }
void ConceptSpecializationExpr::setTemplateArguments(
- const ASTTemplateArgumentListInfo *ArgsAsWritten,
ArrayRef<TemplateArgument> Converted) {
assert(Converted.size() == NumTemplateArgs);
- assert(!this->ArgsAsWritten && "setTemplateArguments can only be used once");
- this->ArgsAsWritten = ArgsAsWritten;
std::uninitialized_copy(Converted.begin(), Converted.end(),
getTrailingObjects<TemplateArgument>());
bool IsInstantiationDependent = false;
bool ContainsUnexpandedParameterPack = false;
- for (const TemplateArgumentLoc& LocInfo : ArgsAsWritten->arguments()) {
- if (LocInfo.getArgument().isInstantiationDependent())
+ for (const TemplateArgument& Arg : Converted) {
+ if (Arg.isInstantiationDependent())
IsInstantiationDependent = true;
- if (LocInfo.getArgument().containsUnexpandedParameterPack())
+ if (Arg.containsUnexpandedParameterPack())
ContainsUnexpandedParameterPack = true;
if (ContainsUnexpandedParameterPack && IsInstantiationDependent)
break;
@@ -1806,20 +1818,21 @@ void ConceptSpecializationExpr::setTemplateArguments(
}
ConceptSpecializationExpr *
-ConceptSpecializationExpr::Create(ASTContext &C, NestedNameSpecifierLoc NNS,
+ConceptSpecializationExpr::Create(const ASTContext &C,
+ NestedNameSpecifierLoc NNS,
SourceLocation TemplateKWLoc,
- SourceLocation ConceptNameLoc,
+ DeclarationNameInfo ConceptNameInfo,
NamedDecl *FoundDecl,
ConceptDecl *NamedConcept,
const ASTTemplateArgumentListInfo *ArgsAsWritten,
ArrayRef<TemplateArgument> ConvertedArgs,
- Optional<bool> IsSatisfied) {
+ const ConstraintSatisfaction *Satisfaction) {
void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
ConvertedArgs.size()));
return new (Buffer) ConceptSpecializationExpr(C, NNS, TemplateKWLoc,
- ConceptNameLoc, FoundDecl,
+ ConceptNameInfo, FoundDecl,
NamedConcept, ArgsAsWritten,
- ConvertedArgs, IsSatisfied);
+ ConvertedArgs, Satisfaction);
}
ConceptSpecializationExpr *
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 42c746e60285..c4b27b5d1daa 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -32,8 +32,6 @@
//
//===----------------------------------------------------------------------===//
-#include <cstring>
-#include <functional>
#include "Interp/Context.h"
#include "Interp/Frame.h"
#include "Interp/State.h"
@@ -41,6 +39,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/ASTLambda.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/CurrentSourceLocExprScope.h"
@@ -57,6 +56,8 @@
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/raw_ostream.h"
+#include <cstring>
+#include <functional>
#define DEBUG_TYPE "exprconstant"
@@ -107,7 +108,7 @@ namespace {
dyn_cast<MaterializeTemporaryExpr>(Base)) {
SmallVector<const Expr *, 2> CommaLHSs;
SmallVector<SubobjectAdjustment, 2> Adjustments;
- const Expr *Temp = MTE->GetTemporaryExpr();
+ const Expr *Temp = MTE->getSubExpr();
const Expr *Inner = Temp->skipRValueSubobjectAdjustments(CommaLHSs,
Adjustments);
// Keep any cv-qualifiers from the reference if we generated a temporary
@@ -763,11 +764,8 @@ namespace {
/// we will evaluate.
unsigned StepsLeft;
- /// Force the use of the experimental new constant interpreter, bailing out
- /// with an error if a feature is not supported.
- bool ForceNewConstInterp;
-
- /// Enable the experimental new constant interpreter.
+ /// Enable the experimental new constant interpreter. If an expression is
+ /// not supported by the interpreter, an error is triggered.
bool EnableNewConstInterp;
/// BottomFrame - The frame in which evaluation started. This must be
@@ -921,10 +919,8 @@ namespace {
EvalInfo(const ASTContext &C, Expr::EvalStatus &S, EvaluationMode Mode)
: Ctx(const_cast<ASTContext &>(C)), EvalStatus(S), CurrentCall(nullptr),
CallStackDepth(0), NextCallIndex(1),
- StepsLeft(getLangOpts().ConstexprStepLimit),
- ForceNewConstInterp(getLangOpts().ForceNewConstInterp),
- EnableNewConstInterp(ForceNewConstInterp ||
- getLangOpts().EnableNewConstInterp),
+ StepsLeft(C.getLangOpts().ConstexprStepLimit),
+ EnableNewConstInterp(C.getLangOpts().EnableNewConstInterp),
BottomFrame(*this, SourceLocation(), nullptr, nullptr, nullptr),
EvaluatingDecl((const ValueDecl *)nullptr),
EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
@@ -1039,10 +1035,13 @@ namespace {
/// cleanups would have had a side-effect, note that as an unmodeled
/// side-effect and return false. Otherwise, return true.
bool discardCleanups() {
- for (Cleanup &C : CleanupStack)
- if (C.hasSideEffect())
- if (!noteSideEffect())
- return false;
+ for (Cleanup &C : CleanupStack) {
+ if (C.hasSideEffect() && !noteSideEffect()) {
+ CleanupStack.clear();
+ return false;
+ }
+ }
+ CleanupStack.clear();
return true;
}
@@ -2072,7 +2071,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
return false;
}
- APValue *V = Info.Ctx.getMaterializedTemporaryValue(MTE, false);
+ APValue *V = MTE->getOrCreateValue(false);
assert(V && "evasluation result refers to uninitialised temporary");
if (!CheckEvaluationResult(CheckEvaluationResultKind::ConstantExpression,
Info, MTE->getExprLoc(), TempType, *V,
@@ -3676,7 +3675,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
return CompleteObject();
}
- BaseVal = Info.Ctx.getMaterializedTemporaryValue(MTE, false);
+ BaseVal = MTE->getOrCreateValue(false);
assert(BaseVal && "got reference to unevaluated temporary");
} else {
if (!IsAccess)
@@ -5333,9 +5332,16 @@ static bool HandleUnionActiveMemberChange(EvalInfo &Info, const Expr *LHSExpr,
if (!FD || FD->getType()->isReferenceType())
break;
- // ... and also contains A.B if B names a union member
- if (FD->getParent()->isUnion())
- UnionPathLengths.push_back({PathLength - 1, FD});
+ // ... and also contains A.B if B names a union member ...
+ if (FD->getParent()->isUnion()) {
+ // ... of a non-class, non-array type, or of a class type with a
+ // trivial default constructor that is not deleted, or an array of
+ // such types.
+ auto *RD =
+ FD->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
+ if (!RD || RD->hasTrivialDefaultConstructor())
+ UnionPathLengths.push_back({PathLength - 1, FD});
+ }
E = ME->getBase();
--PathLength;
@@ -6824,6 +6830,36 @@ public:
return StmtVisitorTy::Visit(Source);
}
+ bool VisitPseudoObjectExpr(const PseudoObjectExpr *E) {
+ for (const Expr *SemE : E->semantics()) {
+ if (auto *OVE = dyn_cast<OpaqueValueExpr>(SemE)) {
+ // FIXME: We can't handle the case where an OpaqueValueExpr is also the
+ // result expression: there could be two different LValues that would
+ // refer to the same object in that case, and we can't model that.
+ if (SemE == E->getResultExpr())
+ return Error(E);
+
+ // Unique OVEs get evaluated if and when we encounter them when
+ // emitting the rest of the semantic form, rather than eagerly.
+ if (OVE->isUnique())
+ continue;
+
+ LValue LV;
+ if (!Evaluate(Info.CurrentCall->createTemporary(
+ OVE, getStorageType(Info.Ctx, OVE), false, LV),
+ Info, OVE->getSourceExpr()))
+ return false;
+ } else if (SemE == E->getResultExpr()) {
+ if (!StmtVisitorTy::Visit(SemE))
+ return false;
+ } else {
+ if (!EvaluateIgnoredValue(Info, SemE))
+ return false;
+ }
+ }
+ return true;
+ }
+
bool VisitCallExpr(const CallExpr *E) {
APValue Result;
if (!handleCallExpr(E, Result, nullptr))
@@ -7044,6 +7080,31 @@ public:
DerivedSuccess(Result, E);
}
+ bool VisitExtVectorElementExpr(const ExtVectorElementExpr *E) {
+ APValue Val;
+ if (!Evaluate(Val, Info, E->getBase()))
+ return false;
+
+ if (Val.isVector()) {
+ SmallVector<uint32_t, 4> Indices;
+ E->getEncodedElementAccess(Indices);
+ if (Indices.size() == 1) {
+ // Return scalar.
+ return DerivedSuccess(Val.getVectorElt(Indices[0]), E);
+ } else {
+ // Construct new APValue vector.
+ SmallVector<APValue, 4> Elts;
+ for (unsigned I = 0; I < Indices.size(); ++I) {
+ Elts.push_back(Val.getVectorElt(Indices[I]));
+ }
+ APValue VecResult(Elts.data(), Indices.size());
+ return DerivedSuccess(VecResult, E);
+ }
+ }
+
+ return false;
+ }
+
bool VisitCastExpr(const CastExpr *E) {
switch (E->getCastKind()) {
default:
@@ -7082,6 +7143,13 @@ public:
return false;
return DerivedSuccess(DestValue, E);
}
+
+ case CK_AddressSpaceConversion: {
+ APValue Value;
+ if (!Evaluate(Value, Info, E->getSubExpr()))
+ return false;
+ return DerivedSuccess(Value, E);
+ }
}
return Error(E);
@@ -7460,8 +7528,8 @@ bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
// Walk through the expression to find the materialized temporary itself.
SmallVector<const Expr *, 2> CommaLHSs;
SmallVector<SubobjectAdjustment, 2> Adjustments;
- const Expr *Inner = E->GetTemporaryExpr()->
- skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
+ const Expr *Inner =
+ E->getSubExpr()->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
// If we passed any comma operators, evaluate their LHSs.
for (unsigned I = 0, N = CommaLHSs.size(); I != N; ++I)
@@ -7473,7 +7541,7 @@ bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
// value for use outside this evaluation.
APValue *Value;
if (E->getStorageDuration() == SD_Static) {
- Value = Info.Ctx.getMaterializedTemporaryValue(E, true);
+ Value = E->getOrCreateValue(true);
*Value = APValue();
Result.set(E);
} else {
@@ -7856,6 +7924,11 @@ public:
// either copied into the closure object's field that represents the '*this'
// or refers to '*this'.
if (isLambdaCallOperator(Info.CurrentCall->Callee)) {
+ // Ensure we actually have captured 'this'. (an error will have
+ // been previously reported if not).
+ if (!Info.CurrentCall->LambdaThisCaptureField)
+ return false;
+
// Update 'Result' to refer to the data member/field of the closure object
// that represents the '*this' capture.
if (!HandleLValueMember(Info, E, Result,
@@ -8102,6 +8175,42 @@ static CharUnits GetAlignOfExpr(EvalInfo &Info, const Expr *E,
return GetAlignOfType(Info, E->getType(), ExprKind);
}
+static CharUnits getBaseAlignment(EvalInfo &Info, const LValue &Value) {
+ if (const auto *VD = Value.Base.dyn_cast<const ValueDecl *>())
+ return Info.Ctx.getDeclAlign(VD);
+ if (const auto *E = Value.Base.dyn_cast<const Expr *>())
+ return GetAlignOfExpr(Info, E, UETT_AlignOf);
+ return GetAlignOfType(Info, Value.Base.getTypeInfoType(), UETT_AlignOf);
+}
+
+/// Evaluate the value of the alignment argument to __builtin_align_{up,down},
+/// __builtin_is_aligned and __builtin_assume_aligned.
+static bool getAlignmentArgument(const Expr *E, QualType ForType,
+ EvalInfo &Info, APSInt &Alignment) {
+ if (!EvaluateInteger(E, Alignment, Info))
+ return false;
+ if (Alignment < 0 || !Alignment.isPowerOf2()) {
+ Info.FFDiag(E, diag::note_constexpr_invalid_alignment) << Alignment;
+ return false;
+ }
+ unsigned SrcWidth = Info.Ctx.getIntWidth(ForType);
+ APSInt MaxValue(APInt::getOneBitSet(SrcWidth, SrcWidth - 1));
+ if (APSInt::compareValues(Alignment, MaxValue) > 0) {
+ Info.FFDiag(E, diag::note_constexpr_alignment_too_big)
+ << MaxValue << ForType << Alignment;
+ return false;
+ }
+ // Ensure both alignment and source value have the same bit width so that we
+ // don't assert when computing the resulting value.
+ APSInt ExtAlignment =
+ APSInt(Alignment.zextOrTrunc(SrcWidth), /*isUnsigned=*/true);
+ assert(APSInt::compareValues(Alignment, ExtAlignment) == 0 &&
+ "Alignment should not be changed by ext/trunc");
+ Alignment = ExtAlignment;
+ assert(Alignment.getBitWidth() == SrcWidth);
+ return true;
+}
+
// To be clear: this happily visits unsupported builtins. Better name welcomed.
bool PointerExprEvaluator::visitNonBuiltinCallExpr(const CallExpr *E) {
if (ExprEvaluatorBaseTy::VisitCallExpr(E))
@@ -8140,7 +8249,8 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
LValue OffsetResult(Result);
APSInt Alignment;
- if (!EvaluateInteger(E->getArg(1), Alignment, Info))
+ if (!getAlignmentArgument(E->getArg(1), E->getArg(0)->getType(), Info,
+ Alignment))
return false;
CharUnits Align = CharUnits::fromQuantity(Alignment.getZExtValue());
@@ -8155,16 +8265,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
// If there is a base object, then it must have the correct alignment.
if (OffsetResult.Base) {
- CharUnits BaseAlignment;
- if (const ValueDecl *VD =
- OffsetResult.Base.dyn_cast<const ValueDecl*>()) {
- BaseAlignment = Info.Ctx.getDeclAlign(VD);
- } else if (const Expr *E = OffsetResult.Base.dyn_cast<const Expr *>()) {
- BaseAlignment = GetAlignOfExpr(Info, E, UETT_AlignOf);
- } else {
- BaseAlignment = GetAlignOfType(
- Info, OffsetResult.Base.getTypeInfoType(), UETT_AlignOf);
- }
+ CharUnits BaseAlignment = getBaseAlignment(Info, OffsetResult);
if (BaseAlignment < Align) {
Result.Designator.setInvalid();
@@ -8193,6 +8294,43 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return true;
}
+ case Builtin::BI__builtin_align_up:
+ case Builtin::BI__builtin_align_down: {
+ if (!evaluatePointer(E->getArg(0), Result))
+ return false;
+ APSInt Alignment;
+ if (!getAlignmentArgument(E->getArg(1), E->getArg(0)->getType(), Info,
+ Alignment))
+ return false;
+ CharUnits BaseAlignment = getBaseAlignment(Info, Result);
+ CharUnits PtrAlign = BaseAlignment.alignmentAtOffset(Result.Offset);
+ // For align_up/align_down, we can return the same value if the alignment
+ // is known to be greater or equal to the requested value.
+ if (PtrAlign.getQuantity() >= Alignment)
+ return true;
+
+ // The alignment could be greater than the minimum at run-time, so we cannot
+ // infer much about the resulting pointer value. One case is possible:
+ // For `_Alignas(32) char buf[N]; __builtin_align_down(&buf[idx], 32)` we
+ // can infer the correct index if the requested alignment is smaller than
+ // the base alignment so we can perform the computation on the offset.
+ if (BaseAlignment.getQuantity() >= Alignment) {
+ assert(Alignment.getBitWidth() <= 64 &&
+ "Cannot handle > 64-bit address-space");
+ uint64_t Alignment64 = Alignment.getZExtValue();
+ CharUnits NewOffset = CharUnits::fromQuantity(
+ BuiltinOp == Builtin::BI__builtin_align_down
+ ? llvm::alignDown(Result.Offset.getQuantity(), Alignment64)
+ : llvm::alignTo(Result.Offset.getQuantity(), Alignment64));
+ Result.adjustOffset(NewOffset - Result.Offset);
+ // TODO: diagnose out-of-bounds values/only allow for arrays?
+ return true;
+ }
+ // Otherwise, we cannot constant-evaluate the result.
+ Info.FFDiag(E->getArg(0), diag::note_constexpr_alignment_adjust)
+ << Alignment;
+ return false;
+ }
case Builtin::BI__builtin_operator_new:
return HandleOperatorNewCall(Info, E, Result);
case Builtin::BI__builtin_launder:
@@ -9021,7 +9159,7 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
if (E->isElidable() && !ZeroInit)
if (const MaterializeTemporaryExpr *ME
= dyn_cast<MaterializeTemporaryExpr>(E->getArg(0)))
- return Visit(ME->GetTemporaryExpr());
+ return Visit(ME->getSubExpr());
if (ZeroInit && !ZeroInitialization(E, T))
return false;
@@ -9240,6 +9378,7 @@ namespace {
bool VisitUnaryImag(const UnaryOperator *E);
// FIXME: Missing: unary -, unary ~, binary add/sub/mul/div,
// binary comparisons, binary and/or/xor,
+ // conditional operator (for GNU conditional select),
// shufflevector, ExtVectorElementExpr
};
} // end anonymous namespace
@@ -10170,7 +10309,7 @@ static QualType getObjectType(APValue::LValueBase B) {
if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D))
return VD->getType();
- } else if (const Expr *E = B.get<const Expr*>()) {
+ } else if (const Expr *E = B.dyn_cast<const Expr*>()) {
if (isa<CompoundLiteralExpr>(E))
return E->getType();
} else if (B.is<TypeInfoLValue>()) {
@@ -10491,6 +10630,33 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
return ExprEvaluatorBaseTy::VisitCallExpr(E);
}
+static bool getBuiltinAlignArguments(const CallExpr *E, EvalInfo &Info,
+ APValue &Val, APSInt &Alignment) {
+ QualType SrcTy = E->getArg(0)->getType();
+ if (!getAlignmentArgument(E->getArg(1), SrcTy, Info, Alignment))
+ return false;
+ // Even though we are evaluating integer expressions we could get a pointer
+ // argument for the __builtin_is_aligned() case.
+ if (SrcTy->isPointerType()) {
+ LValue Ptr;
+ if (!EvaluatePointer(E->getArg(0), Ptr, Info))
+ return false;
+ Ptr.moveInto(Val);
+ } else if (!SrcTy->isIntegralOrEnumerationType()) {
+ Info.FFDiag(E->getArg(0));
+ return false;
+ } else {
+ APSInt SrcInt;
+ if (!EvaluateInteger(E->getArg(0), SrcInt, Info))
+ return false;
+ assert(SrcInt.getBitWidth() >= Alignment.getBitWidth() &&
+ "Bit widths must be the same");
+ Val = APValue(SrcInt);
+ }
+ assert(Val.hasValue());
+ return true;
+}
+
bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
unsigned BuiltinOp) {
switch (unsigned BuiltinOp = E->getBuiltinCallee()) {
@@ -10533,6 +10699,66 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return Success(Layout.size().getQuantity(), E);
}
+ case Builtin::BI__builtin_is_aligned: {
+ APValue Src;
+ APSInt Alignment;
+ if (!getBuiltinAlignArguments(E, Info, Src, Alignment))
+ return false;
+ if (Src.isLValue()) {
+ // If we evaluated a pointer, check the minimum known alignment.
+ LValue Ptr;
+ Ptr.setFrom(Info.Ctx, Src);
+ CharUnits BaseAlignment = getBaseAlignment(Info, Ptr);
+ CharUnits PtrAlign = BaseAlignment.alignmentAtOffset(Ptr.Offset);
+ // We can return true if the known alignment at the computed offset is
+ // greater than the requested alignment.
+ assert(PtrAlign.isPowerOfTwo());
+ assert(Alignment.isPowerOf2());
+ if (PtrAlign.getQuantity() >= Alignment)
+ return Success(1, E);
+ // If the alignment is not known to be sufficient, some cases could still
+ // be aligned at run time. However, if the requested alignment is less or
+ // equal to the base alignment and the offset is not aligned, we know that
+ // the run-time value can never be aligned.
+ if (BaseAlignment.getQuantity() >= Alignment &&
+ PtrAlign.getQuantity() < Alignment)
+ return Success(0, E);
+ // Otherwise we can't infer whether the value is sufficiently aligned.
+ // TODO: __builtin_is_aligned(__builtin_align_{down,up{(expr, N), N)
+ // in cases where we can't fully evaluate the pointer.
+ Info.FFDiag(E->getArg(0), diag::note_constexpr_alignment_compute)
+ << Alignment;
+ return false;
+ }
+ assert(Src.isInt());
+ return Success((Src.getInt() & (Alignment - 1)) == 0 ? 1 : 0, E);
+ }
+ case Builtin::BI__builtin_align_up: {
+ APValue Src;
+ APSInt Alignment;
+ if (!getBuiltinAlignArguments(E, Info, Src, Alignment))
+ return false;
+ if (!Src.isInt())
+ return Error(E);
+ APSInt AlignedVal =
+ APSInt((Src.getInt() + (Alignment - 1)) & ~(Alignment - 1),
+ Src.getInt().isUnsigned());
+ assert(AlignedVal.getBitWidth() == Src.getInt().getBitWidth());
+ return Success(AlignedVal, E);
+ }
+ case Builtin::BI__builtin_align_down: {
+ APValue Src;
+ APSInt Alignment;
+ if (!getBuiltinAlignArguments(E, Info, Src, Alignment))
+ return false;
+ if (!Src.isInt())
+ return Error(E);
+ APSInt AlignedVal =
+ APSInt(Src.getInt() & ~(Alignment - 1), Src.getInt().isUnsigned());
+ assert(AlignedVal.getBitWidth() == Src.getInt().getBitWidth());
+ return Success(AlignedVal, E);
+ }
+
case Builtin::BI__builtin_bswap16:
case Builtin::BI__builtin_bswap32:
case Builtin::BI__builtin_bswap64: {
@@ -10583,8 +10809,24 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return false;
}
- case Builtin::BI__builtin_is_constant_evaluated:
+ case Builtin::BI__builtin_is_constant_evaluated: {
+ const auto *Callee = Info.CurrentCall->getCallee();
+ if (Info.InConstantContext && !Info.CheckingPotentialConstantExpression &&
+ (Info.CallStackDepth == 1 ||
+ (Info.CallStackDepth == 2 && Callee->isInStdNamespace() &&
+ Callee->getIdentifier() &&
+ Callee->getIdentifier()->isStr("is_constant_evaluated")))) {
+ // FIXME: Find a better way to avoid duplicated diagnostics.
+ if (Info.EvalStatus.Diag)
+ Info.report((Info.CallStackDepth == 1) ? E->getExprLoc()
+ : Info.CurrentCall->CallLoc,
+ diag::warn_is_constant_evaluated_always_true_constexpr)
+ << (Info.CallStackDepth == 1 ? "__builtin_is_constant_evaluated"
+ : "std::is_constant_evaluated");
+ }
+
return Success(Info.InConstantContext, E);
+ }
case Builtin::BI__builtin_ctz:
case Builtin::BI__builtin_ctzl:
@@ -11417,6 +11659,14 @@ public:
}
}
};
+
+enum class CmpResult {
+ Unequal,
+ Less,
+ Equal,
+ Greater,
+ Unordered,
+};
}
template <class SuccessCB, class AfterCB>
@@ -11432,15 +11682,8 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
return false;
};
- using CCR = ComparisonCategoryResult;
- bool IsRelational = E->isRelationalOp();
+ bool IsRelational = E->isRelationalOp() || E->getOpcode() == BO_Cmp;
bool IsEquality = E->isEqualityOp();
- if (E->getOpcode() == BO_Cmp) {
- const ComparisonCategoryInfo &CmpInfo =
- Info.Ctx.CompCategories.getInfoForType(E->getType());
- IsRelational = CmpInfo.isOrdered();
- IsEquality = CmpInfo.isEquality();
- }
QualType LHSTy = E->getLHS()->getType();
QualType RHSTy = E->getRHS()->getType();
@@ -11454,10 +11697,10 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
if (!EvaluateInteger(E->getRHS(), RHS, Info) || !LHSOK)
return false;
if (LHS < RHS)
- return Success(CCR::Less, E);
+ return Success(CmpResult::Less, E);
if (LHS > RHS)
- return Success(CCR::Greater, E);
- return Success(CCR::Equal, E);
+ return Success(CmpResult::Greater, E);
+ return Success(CmpResult::Equal, E);
}
if (LHSTy->isFixedPointType() || RHSTy->isFixedPointType()) {
@@ -11470,10 +11713,10 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
if (!EvaluateFixedPointOrInteger(E->getRHS(), RHSFX, Info) || !LHSOK)
return false;
if (LHSFX < RHSFX)
- return Success(CCR::Less, E);
+ return Success(CmpResult::Less, E);
if (LHSFX > RHSFX)
- return Success(CCR::Greater, E);
- return Success(CCR::Equal, E);
+ return Success(CmpResult::Greater, E);
+ return Success(CmpResult::Equal, E);
}
if (LHSTy->isAnyComplexType() || RHSTy->isAnyComplexType()) {
@@ -11509,12 +11752,12 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
APFloat::cmpResult CR_i =
LHS.getComplexFloatImag().compare(RHS.getComplexFloatImag());
bool IsEqual = CR_r == APFloat::cmpEqual && CR_i == APFloat::cmpEqual;
- return Success(IsEqual ? CCR::Equal : CCR::Nonequal, E);
+ return Success(IsEqual ? CmpResult::Equal : CmpResult::Unequal, E);
} else {
assert(IsEquality && "invalid complex comparison");
bool IsEqual = LHS.getComplexIntReal() == RHS.getComplexIntReal() &&
LHS.getComplexIntImag() == RHS.getComplexIntImag();
- return Success(IsEqual ? CCR::Equal : CCR::Nonequal, E);
+ return Success(IsEqual ? CmpResult::Equal : CmpResult::Unequal, E);
}
}
@@ -11533,13 +11776,13 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
auto GetCmpRes = [&]() {
switch (LHS.compare(RHS)) {
case APFloat::cmpEqual:
- return CCR::Equal;
+ return CmpResult::Equal;
case APFloat::cmpLessThan:
- return CCR::Less;
+ return CmpResult::Less;
case APFloat::cmpGreaterThan:
- return CCR::Greater;
+ return CmpResult::Greater;
case APFloat::cmpUnordered:
- return CCR::Unordered;
+ return CmpResult::Unordered;
}
llvm_unreachable("Unrecognised APFloat::cmpResult enum");
};
@@ -11561,8 +11804,10 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
if (!HasSameBase(LHSValue, RHSValue)) {
// Inequalities and subtractions between unrelated pointers have
// unspecified or undefined behavior.
- if (!IsEquality)
- return Error(E);
+ if (!IsEquality) {
+ Info.FFDiag(E, diag::note_constexpr_pointer_comparison_unspecified);
+ return false;
+ }
// 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.
@@ -11592,7 +11837,7 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
if ((RHSValue.Base && isZeroSized(LHSValue)) ||
(LHSValue.Base && isZeroSized(RHSValue)))
return Error(E);
- return Success(CCR::Nonequal, E);
+ return Success(CmpResult::Unequal, E);
}
const CharUnits &LHSOffset = LHSValue.getLValueOffset();
@@ -11676,10 +11921,10 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
}
if (CompareLHS < CompareRHS)
- return Success(CCR::Less, E);
+ return Success(CmpResult::Less, E);
if (CompareLHS > CompareRHS)
- return Success(CCR::Greater, E);
- return Success(CCR::Equal, E);
+ return Success(CmpResult::Greater, E);
+ return Success(CmpResult::Equal, E);
}
if (LHSTy->isMemberPointerType()) {
@@ -11700,7 +11945,7 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
// null, they compare unequal.
if (!LHSValue.getDecl() || !RHSValue.getDecl()) {
bool Equal = !LHSValue.getDecl() && !RHSValue.getDecl();
- return Success(Equal ? CCR::Equal : CCR::Nonequal, E);
+ return Success(Equal ? CmpResult::Equal : CmpResult::Unequal, E);
}
// Otherwise if either is a pointer to a virtual member function, the
@@ -11717,7 +11962,7 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
// they were dereferenced with a hypothetical object of the associated
// class type.
bool Equal = LHSValue == RHSValue;
- return Success(Equal ? CCR::Equal : CCR::Nonequal, E);
+ return Success(Equal ? CmpResult::Equal : CmpResult::Unequal, E);
}
if (LHSTy->isNullPtrType()) {
@@ -11726,7 +11971,7 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
// C++11 [expr.rel]p4, [expr.eq]p3: If two operands of type std::nullptr_t
// are compared, the result is true of the operator is <=, >= or ==, and
// false otherwise.
- return Success(CCR::Equal, E);
+ return Success(CmpResult::Equal, E);
}
return DoAfter();
@@ -11736,14 +11981,29 @@ bool RecordExprEvaluator::VisitBinCmp(const BinaryOperator *E) {
if (!CheckLiteralType(Info, E))
return false;
- auto OnSuccess = [&](ComparisonCategoryResult ResKind,
- const BinaryOperator *E) {
+ auto OnSuccess = [&](CmpResult CR, const BinaryOperator *E) {
+ ComparisonCategoryResult CCR;
+ switch (CR) {
+ case CmpResult::Unequal:
+ llvm_unreachable("should never produce Unequal for three-way comparison");
+ case CmpResult::Less:
+ CCR = ComparisonCategoryResult::Less;
+ break;
+ case CmpResult::Equal:
+ CCR = ComparisonCategoryResult::Equal;
+ break;
+ case CmpResult::Greater:
+ CCR = ComparisonCategoryResult::Greater;
+ break;
+ case CmpResult::Unordered:
+ CCR = ComparisonCategoryResult::Unordered;
+ break;
+ }
// Evaluation succeeded. Lookup the information for the comparison category
// type and fetch the VarDecl for the result.
const ComparisonCategoryInfo &CmpInfo =
Info.Ctx.CompCategories.getInfoForType(E->getType());
- const VarDecl *VD =
- CmpInfo.getValueInfo(CmpInfo.makeWeakResult(ResKind))->VD;
+ const VarDecl *VD = CmpInfo.getValueInfo(CmpInfo.makeWeakResult(CCR))->VD;
// Check and evaluate the result as a constant expression.
LValue LV;
LV.set(VD);
@@ -11771,14 +12031,14 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
"DataRecursiveIntBinOpEvaluator should have handled integral types");
if (E->isComparisonOp()) {
- // Evaluate builtin binary comparisons by evaluating them as C++2a three-way
+ // Evaluate builtin binary comparisons by evaluating them as three-way
// comparisons and then translating the result.
- auto OnSuccess = [&](ComparisonCategoryResult ResKind,
- const BinaryOperator *E) {
- using CCR = ComparisonCategoryResult;
- bool IsEqual = ResKind == CCR::Equal,
- IsLess = ResKind == CCR::Less,
- IsGreater = ResKind == CCR::Greater;
+ auto OnSuccess = [&](CmpResult CR, const BinaryOperator *E) {
+ assert((CR != CmpResult::Unequal || E->isEqualityOp()) &&
+ "should only produce Unequal for equality comparisons");
+ bool IsEqual = CR == CmpResult::Equal,
+ IsLess = CR == CmpResult::Less,
+ IsGreater = CR == CmpResult::Greater;
auto Op = E->getOpcode();
switch (Op) {
default:
@@ -11786,10 +12046,14 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
case BO_EQ:
case BO_NE:
return Success(IsEqual == (Op == BO_EQ), E);
- case BO_LT: return Success(IsLess, E);
- case BO_GT: return Success(IsGreater, E);
- case BO_LE: return Success(IsEqual || IsLess, E);
- case BO_GE: return Success(IsEqual || IsGreater, E);
+ case BO_LT:
+ return Success(IsLess, E);
+ case BO_GT:
+ return Success(IsGreater, E);
+ case BO_LE:
+ return Success(IsEqual || IsLess, E);
+ case BO_GE:
+ return Success(IsEqual || IsGreater, E);
}
};
return EvaluateComparisonBinaryOperator(Info, E, OnSuccess, [&]() {
@@ -13374,32 +13638,25 @@ static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, const LValue &This,
/// EvaluateAsRValue - Try to evaluate this expression, performing an implicit
/// lvalue-to-rvalue cast if it is an lvalue.
static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) {
- if (Info.EnableNewConstInterp) {
- auto &InterpCtx = Info.Ctx.getInterpContext();
- switch (InterpCtx.evaluateAsRValue(Info, E, Result)) {
- case interp::InterpResult::Success:
- return true;
- case interp::InterpResult::Fail:
+ if (Info.EnableNewConstInterp) {
+ if (!Info.Ctx.getInterpContext().evaluateAsRValue(Info, E, Result))
+ return false;
+ } else {
+ if (E->getType().isNull())
return false;
- case interp::InterpResult::Bail:
- break;
- }
- }
-
- if (E->getType().isNull())
- return false;
-
- if (!CheckLiteralType(Info, E))
- return false;
- if (!::Evaluate(Result, Info, E))
- return false;
+ if (!CheckLiteralType(Info, E))
+ return false;
- if (E->isGLValue()) {
- LValue LV;
- LV.setFrom(Info.Ctx, Result);
- if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result))
+ if (!::Evaluate(Result, Info, E))
return false;
+
+ if (E->isGLValue()) {
+ LValue LV;
+ LV.setFrom(Info.Ctx, Result);
+ if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result))
+ return false;
+ }
}
// Check this core constant expression is a constant expression.
@@ -13611,46 +13868,36 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
if (Info.EnableNewConstInterp) {
auto &InterpCtx = const_cast<ASTContext &>(Ctx).getInterpContext();
- switch (InterpCtx.evaluateAsInitializer(Info, VD, Value)) {
- case interp::InterpResult::Fail:
- // Bail out if an error was encountered.
+ if (!InterpCtx.evaluateAsInitializer(Info, VD, Value))
return false;
- case interp::InterpResult::Success:
- // Evaluation succeeded and value was set.
- return CheckConstantExpression(Info, DeclLoc, DeclTy, Value);
- case interp::InterpResult::Bail:
- // Evaluate the value again for the tree evaluator to use.
- break;
- }
- }
+ } else {
+ LValue LVal;
+ LVal.set(VD);
- LValue LVal;
- LVal.set(VD);
+ // C++11 [basic.start.init]p2:
+ // Variables with static storage duration or thread storage duration shall
+ // be zero-initialized before any other initialization takes place.
+ // This behavior is not present in C.
+ if (Ctx.getLangOpts().CPlusPlus && !VD->hasLocalStorage() &&
+ !DeclTy->isReferenceType()) {
+ ImplicitValueInitExpr VIE(DeclTy);
+ if (!EvaluateInPlace(Value, Info, LVal, &VIE,
+ /*AllowNonLiteralTypes=*/true))
+ return false;
+ }
- // C++11 [basic.start.init]p2:
- // Variables with static storage duration or thread storage duration shall be
- // zero-initialized before any other initialization takes place.
- // This behavior is not present in C.
- if (Ctx.getLangOpts().CPlusPlus && !VD->hasLocalStorage() &&
- !DeclTy->isReferenceType()) {
- ImplicitValueInitExpr VIE(DeclTy);
- if (!EvaluateInPlace(Value, Info, LVal, &VIE,
- /*AllowNonLiteralTypes=*/true))
+ if (!EvaluateInPlace(Value, Info, LVal, this,
+ /*AllowNonLiteralTypes=*/true) ||
+ EStatus.HasSideEffects)
return false;
- }
- if (!EvaluateInPlace(Value, Info, LVal, this,
- /*AllowNonLiteralTypes=*/true) ||
- EStatus.HasSideEffects)
- return false;
-
- // At this point, any lifetime-extended temporaries are completely
- // initialized.
- Info.performLifetimeExtension();
-
- if (!Info.discardCleanups())
- llvm_unreachable("Unhandled cleanup; missing full expression marker?");
+ // At this point, any lifetime-extended temporaries are completely
+ // initialized.
+ Info.performLifetimeExtension();
+ if (!Info.discardCleanups())
+ llvm_unreachable("Unhandled cleanup; missing full expression marker?");
+ }
return CheckConstantExpression(Info, DeclLoc, DeclTy, Value) &&
CheckMemoryLeaks(Info);
}
@@ -14333,27 +14580,41 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
assert(MD && "Don't provide `this` for non-methods.");
assert(!MD->isStatic() && "Don't provide `this` for static methods.");
#endif
- if (EvaluateObjectArgument(Info, This, ThisVal))
+ if (!This->isValueDependent() &&
+ EvaluateObjectArgument(Info, This, ThisVal) &&
+ !Info.EvalStatus.HasSideEffects)
ThisPtr = &ThisVal;
- if (Info.EvalStatus.HasSideEffects)
- return false;
+
+ // Ignore any side-effects from a failed evaluation. This is safe because
+ // they can't interfere with any other argument evaluation.
+ Info.EvalStatus.HasSideEffects = false;
}
ArgVector ArgValues(Args.size());
for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
I != E; ++I) {
if ((*I)->isValueDependent() ||
- !Evaluate(ArgValues[I - Args.begin()], Info, *I))
+ !Evaluate(ArgValues[I - Args.begin()], Info, *I) ||
+ Info.EvalStatus.HasSideEffects)
// If evaluation fails, throw away the argument entirely.
ArgValues[I - Args.begin()] = APValue();
- if (Info.EvalStatus.HasSideEffects)
- return false;
+
+ // Ignore any side-effects from a failed evaluation. This is safe because
+ // they can't interfere with any other argument evaluation.
+ Info.EvalStatus.HasSideEffects = false;
}
+ // Parameter cleanups happen in the caller and are not part of this
+ // evaluation.
+ Info.discardCleanups();
+ Info.EvalStatus.HasSideEffects = false;
+
// Build fake call to Callee.
CallStackFrame Frame(Info, Callee->getLocation(), Callee, ThisPtr,
ArgValues.data());
- return Evaluate(Value, Info, this) && Info.discardCleanups() &&
+ // FIXME: Missing ExprWithCleanups in enable_if conditions?
+ FullExpressionRAII Scope(Info);
+ return Evaluate(Value, Info, this) && Scope.destroy() &&
!Info.EvalStatus.HasSideEffects;
}
@@ -14375,14 +14636,8 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
// The constexpr VM attempts to compile all methods to bytecode here.
if (Info.EnableNewConstInterp) {
- auto &InterpCtx = Info.Ctx.getInterpContext();
- switch (InterpCtx.isPotentialConstantExpr(Info, FD)) {
- case interp::InterpResult::Success:
- case interp::InterpResult::Fail:
- return Diags.empty();
- case interp::InterpResult::Bail:
- break;
- }
+ Info.Ctx.getInterpContext().isPotentialConstantExpr(Info, FD);
+ return Diags.empty();
}
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
diff --git a/clang/lib/AST/ExternalASTMerger.cpp b/clang/lib/AST/ExternalASTMerger.cpp
index f678c2dd3b59..88bbe90a4e90 100644
--- a/clang/lib/AST/ExternalASTMerger.cpp
+++ b/clang/lib/AST/ExternalASTMerger.cpp
@@ -510,9 +510,7 @@ bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC,
Decl *LookupRes = C.first.get();
ASTImporter *Importer = C.second;
auto NDOrErr = Importer->Import(LookupRes);
- assert(NDOrErr);
- (void)static_cast<bool>(NDOrErr);
- NamedDecl *ND = cast_or_null<NamedDecl>(*NDOrErr);
+ NamedDecl *ND = cast<NamedDecl>(llvm::cantFail(std::move(NDOrErr)));
assert(ND);
// If we don't import specialization, they are not available via lookup
// because the lookup result is imported TemplateDecl and it does not
diff --git a/clang/lib/AST/ExternalASTSource.cpp b/clang/lib/AST/ExternalASTSource.cpp
index 730102757440..837be5527fce 100644
--- a/clang/lib/AST/ExternalASTSource.cpp
+++ b/clang/lib/AST/ExternalASTSource.cpp
@@ -24,6 +24,8 @@
using namespace clang;
+char ExternalASTSource::ID;
+
ExternalASTSource::~ExternalASTSource() = default;
llvm::Optional<ExternalASTSource::ASTSourceDescriptor>
diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
index c71301598bde..5b47489e65e0 100644
--- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -14,13 +14,11 @@
#include "PrimType.h"
#include "Program.h"
#include "State.h"
+#include "clang/Basic/LLVM.h"
using namespace clang;
using namespace clang::interp;
-template <typename T> using Expected = llvm::Expected<T>;
-template <typename T> using Optional = llvm::Optional<T>;
-
namespace clang {
namespace interp {
diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp
index 4f8f7b96e7c3..e7f9ba0f010a 100644
--- a/clang/lib/AST/Interp/Context.cpp
+++ b/clang/lib/AST/Interp/Context.cpp
@@ -21,44 +21,37 @@
using namespace clang;
using namespace clang::interp;
-Context::Context(ASTContext &Ctx)
- : Ctx(Ctx), ForceInterp(getLangOpts().ForceNewConstInterp),
- P(new Program(*this)) {}
+Context::Context(ASTContext &Ctx) : Ctx(Ctx), P(new Program(*this)) {}
Context::~Context() {}
-InterpResult Context::isPotentialConstantExpr(State &Parent,
- const FunctionDecl *FD) {
+bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {
Function *Func = P->getFunction(FD);
if (!Func) {
if (auto R = ByteCodeStmtGen<ByteCodeEmitter>(*this, *P).compileFunc(FD)) {
Func = *R;
- } else if (ForceInterp) {
+ } else {
handleAllErrors(R.takeError(), [&Parent](ByteCodeGenError &Err) {
Parent.FFDiag(Err.getLoc(), diag::err_experimental_clang_interp_failed);
});
- return InterpResult::Fail;
- } else {
- consumeError(R.takeError());
- return InterpResult::Bail;
+ return false;
}
}
if (!Func->isConstexpr())
- return InterpResult::Fail;
+ return false;
APValue Dummy;
return Run(Parent, Func, Dummy);
}
-InterpResult Context::evaluateAsRValue(State &Parent, const Expr *E,
- APValue &Result) {
+bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {
ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result);
return Check(Parent, C.interpretExpr(E));
}
-InterpResult Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
- APValue &Result) {
+bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
+ APValue &Result) {
ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result);
return Check(Parent, C.interpretDecl(VD));
}
@@ -116,33 +109,20 @@ unsigned Context::getCharBit() const {
return Ctx.getTargetInfo().getCharWidth();
}
-InterpResult Context::Run(State &Parent, Function *Func, APValue &Result) {
- InterpResult Flag;
- {
- InterpState State(Parent, *P, Stk, *this);
- State.Current = new InterpFrame(State, Func, nullptr, {}, {});
- if (Interpret(State, Result)) {
- Flag = InterpResult::Success;
- } else {
- Flag = InterpResult::Fail;
- }
- }
-
- if (Flag != InterpResult::Success)
- Stk.clear();
- return Flag;
+bool Context::Run(State &Parent, Function *Func, APValue &Result) {
+ InterpState State(Parent, *P, Stk, *this);
+ State.Current = new InterpFrame(State, Func, nullptr, {}, {});
+ if (Interpret(State, Result))
+ return true;
+ Stk.clear();
+ return false;
}
-InterpResult Context::Check(State &Parent, llvm::Expected<bool> &&R) {
- if (R) {
- return *R ? InterpResult::Success : InterpResult::Fail;
- } else if (ForceInterp) {
- handleAllErrors(R.takeError(), [&Parent](ByteCodeGenError &Err) {
- Parent.FFDiag(Err.getLoc(), diag::err_experimental_clang_interp_failed);
- });
- return InterpResult::Fail;
- } else {
- consumeError(R.takeError());
- return InterpResult::Bail;
- }
+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);
+ });
+ return false;
}
diff --git a/clang/lib/AST/Interp/Context.h b/clang/lib/AST/Interp/Context.h
index 96368b6e5f02..e4d831cbb991 100644
--- a/clang/lib/AST/Interp/Context.h
+++ b/clang/lib/AST/Interp/Context.h
@@ -34,16 +34,6 @@ class Program;
class State;
enum PrimType : unsigned;
-/// Wrapper around interpreter termination results.
-enum class InterpResult {
- /// Interpreter successfully computed a value.
- Success,
- /// Interpreter encountered an error and quit.
- Fail,
- /// Interpreter encountered an unimplemented feature, AST fallback.
- Bail,
-};
-
/// Holds all information required to evaluate constexpr code in a module.
class Context {
public:
@@ -54,15 +44,13 @@ public:
~Context();
/// Checks if a function is a potential constant expression.
- InterpResult isPotentialConstantExpr(State &Parent,
- const FunctionDecl *FnDecl);
+ bool isPotentialConstantExpr(State &Parent, const FunctionDecl *FnDecl);
/// Evaluates a toplevel expression as an rvalue.
- InterpResult evaluateAsRValue(State &Parent, const Expr *E, APValue &Result);
+ bool evaluateAsRValue(State &Parent, const Expr *E, APValue &Result);
/// Evaluates a toplevel initializer.
- InterpResult evaluateAsInitializer(State &Parent, const VarDecl *VD,
- APValue &Result);
+ bool evaluateAsInitializer(State &Parent, const VarDecl *VD, APValue &Result);
/// Returns the AST context.
ASTContext &getASTContext() const { return Ctx; }
@@ -78,16 +66,14 @@ public:
private:
/// Runs a function.
- InterpResult Run(State &Parent, Function *Func, APValue &Result);
+ bool Run(State &Parent, Function *Func, APValue &Result);
/// Checks a result fromt the interpreter.
- InterpResult Check(State &Parent, llvm::Expected<bool> &&R);
+ bool Check(State &Parent, llvm::Expected<bool> &&R);
private:
/// Current compilation context.
ASTContext &Ctx;
- /// Flag to indicate if the use of the interpreter is mandatory.
- bool ForceInterp;
/// Interpreter stack, shared across invocations.
InterpStack Stk;
/// Constexpr program.
diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 8934efa13b9c..c12caa639da7 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -196,11 +196,8 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
const Pointer &RHS = S.Stk.pop<Pointer>();
const Pointer &LHS = S.Stk.pop<Pointer>();
- if (LHS.isZero() || RHS.isZero()) {
- if (LHS.isZero() && RHS.isZero())
- S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
- else
- S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Nonequal)));
+ if (LHS.isZero() && RHS.isZero()) {
+ S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
return true;
}
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index c55a90137578..0d567edac521 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -2301,6 +2301,16 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals, const DependentAddressSp
case LangAS::cuda_device: ASString = "CUdevice"; break;
case LangAS::cuda_constant: ASString = "CUconstant"; break;
case LangAS::cuda_shared: ASString = "CUshared"; break;
+ // <ptrsize-addrspace> ::= [ "ptr32_sptr" | "ptr32_uptr" | "ptr64" ]
+ case LangAS::ptr32_sptr:
+ ASString = "ptr32_sptr";
+ break;
+ case LangAS::ptr32_uptr:
+ ASString = "ptr32_uptr";
+ break;
+ case LangAS::ptr64:
+ ASString = "ptr64";
+ break;
}
}
if (!ASString.empty())
@@ -4338,7 +4348,7 @@ recurse:
}
case Expr::MaterializeTemporaryExprClass: {
- mangleExpression(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr());
+ mangleExpression(cast<MaterializeTemporaryExpr>(E)->getSubExpr());
break;
}
diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
index f60d761c996c..c30b07137edc 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -202,14 +202,20 @@ void JSONNodeDumper::writeBareSourceLocation(SourceLocation Loc,
PresumedLoc Presumed = SM.getPresumedLoc(Loc);
unsigned ActualLine = IsSpelling ? SM.getSpellingLineNumber(Loc)
: SM.getExpansionLineNumber(Loc);
+ StringRef ActualFile = SM.getBufferName(Loc);
+
if (Presumed.isValid()) {
JOS.attribute("offset", SM.getDecomposedLoc(Loc).second);
- if (LastLocFilename != Presumed.getFilename()) {
- JOS.attribute("file", Presumed.getFilename());
+ if (LastLocFilename != ActualFile) {
+ JOS.attribute("file", ActualFile);
JOS.attribute("line", ActualLine);
} else if (LastLocLine != ActualLine)
JOS.attribute("line", ActualLine);
+ StringRef PresumedFile = Presumed.getFilename();
+ if (PresumedFile != ActualFile && LastLocPresumedFilename != PresumedFile)
+ JOS.attribute("presumedFile", PresumedFile);
+
unsigned PresumedLine = Presumed.getLine();
if (ActualLine != PresumedLine && LastLocPresumedLine != PresumedLine)
JOS.attribute("presumedLine", PresumedLine);
@@ -217,7 +223,8 @@ void JSONNodeDumper::writeBareSourceLocation(SourceLocation Loc,
JOS.attribute("col", Presumed.getColumn());
JOS.attribute("tokLen",
Lexer::MeasureTokenLength(Loc, SM, Ctx.getLangOpts()));
- LastLocFilename = Presumed.getFilename();
+ LastLocFilename = ActualFile;
+ LastLocPresumedFilename = PresumedFile;
LastLocPresumedLine = PresumedLine;
LastLocLine = ActualLine;
@@ -688,8 +695,12 @@ void JSONNodeDumper::VisitMemberPointerType(const MemberPointerType *MPT) {
}
void JSONNodeDumper::VisitNamedDecl(const NamedDecl *ND) {
- if (ND && ND->getDeclName())
+ if (ND && ND->getDeclName()) {
JOS.attribute("name", ND->getNameAsString());
+ std::string MangledName = ASTNameGen.getName(ND);
+ if (!MangledName.empty())
+ JOS.attribute("mangledName", MangledName);
+ }
}
void JSONNodeDumper::VisitTypedefDecl(const TypedefDecl *TD) {
@@ -874,12 +885,6 @@ void JSONNodeDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *LSD) {
switch (LSD->getLanguage()) {
case LinkageSpecDecl::lang_c: Lang = "C"; break;
case LinkageSpecDecl::lang_cxx: Lang = "C++"; break;
- case LinkageSpecDecl::lang_cxx_11:
- Lang = "C++11";
- break;
- case LinkageSpecDecl::lang_cxx_14:
- Lang = "C++14";
- break;
}
JOS.attribute("language", Lang);
attributeOnlyIfTrue("hasBraces", LSD->hasBraces());
@@ -1013,6 +1018,7 @@ void JSONNodeDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
attributeOnlyIfTrue("unsafe_unretained",
Attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
attributeOnlyIfTrue("class", Attrs & ObjCPropertyDecl::OBJC_PR_class);
+ attributeOnlyIfTrue("direct", Attrs & ObjCPropertyDecl::OBJC_PR_direct);
attributeOnlyIfTrue("nullability",
Attrs & ObjCPropertyDecl::OBJC_PR_nullability);
attributeOnlyIfTrue("null_resettable",
@@ -1512,6 +1518,9 @@ void JSONNodeDumper::visitInlineCommandComment(
case comments::InlineCommandComment::RenderMonospaced:
JOS.attribute("renderKind", "monospaced");
break;
+ case comments::InlineCommandComment::RenderAnchor:
+ JOS.attribute("renderKind", "anchor");
+ break;
}
llvm::json::Array Args;
diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp
index 32d466cb5718..e106b31f59f0 100644
--- a/clang/lib/AST/Mangle.cpp
+++ b/clang/lib/AST/Mangle.cpp
@@ -63,9 +63,7 @@ static CCMangling getCallingConvMangling(const ASTContext &Context,
const NamedDecl *ND) {
const TargetInfo &TI = Context.getTargetInfo();
const llvm::Triple &Triple = TI.getTriple();
- if (!Triple.isOSWindows() ||
- !(Triple.getArch() == llvm::Triple::x86 ||
- Triple.getArch() == llvm::Triple::x86_64))
+ if (!Triple.isOSWindows() || !Triple.isX86())
return CCM_Other;
if (Context.getLangOpts().CPlusPlus && !isExternC(ND) &&
diff --git a/clang/lib/AST/MicrosoftCXXABI.cpp b/clang/lib/AST/MicrosoftCXXABI.cpp
index 074abba3d458..f9f9fe985b6f 100644
--- a/clang/lib/AST/MicrosoftCXXABI.cpp
+++ b/clang/lib/AST/MicrosoftCXXABI.cpp
@@ -14,6 +14,7 @@
#include "CXXABI.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/MangleNumberingContext.h"
#include "clang/AST/RecordLayout.h"
@@ -154,27 +155,32 @@ static bool usesMultipleInheritanceModel(const CXXRecordDecl *RD) {
return false;
}
-MSInheritanceAttr::Spelling CXXRecordDecl::calculateInheritanceModel() const {
+MSInheritanceModel CXXRecordDecl::calculateInheritanceModel() const {
if (!hasDefinition() || isParsingBaseSpecifiers())
- return MSInheritanceAttr::Keyword_unspecified_inheritance;
+ return MSInheritanceModel::Unspecified;
if (getNumVBases() > 0)
- return MSInheritanceAttr::Keyword_virtual_inheritance;
+ return MSInheritanceModel::Virtual;
if (usesMultipleInheritanceModel(this))
- return MSInheritanceAttr::Keyword_multiple_inheritance;
- return MSInheritanceAttr::Keyword_single_inheritance;
+ return MSInheritanceModel::Multiple;
+ return MSInheritanceModel::Single;
}
-MSInheritanceAttr::Spelling
-CXXRecordDecl::getMSInheritanceModel() const {
+MSInheritanceModel CXXRecordDecl::getMSInheritanceModel() const {
MSInheritanceAttr *IA = getAttr<MSInheritanceAttr>();
assert(IA && "Expected MSInheritanceAttr on the CXXRecordDecl!");
- return IA->getSemanticSpelling();
+ return IA->getInheritanceModel();
}
-MSVtorDispAttr::Mode CXXRecordDecl::getMSVtorDispMode() const {
+bool CXXRecordDecl::nullFieldOffsetIsZero() const {
+ return !inheritanceModelHasOnlyOneField(/*IsMemberFunction=*/false,
+ getMSInheritanceModel()) ||
+ (hasDefinition() && isPolymorphic());
+}
+
+MSVtorDispMode CXXRecordDecl::getMSVtorDispMode() const {
if (MSVtorDispAttr *VDA = getAttr<MSVtorDispAttr>())
return VDA->getVtorDispMode();
- return MSVtorDispAttr::Mode(getASTContext().getLangOpts().VtorDispMode);
+ return getASTContext().getLangOpts().getVtorDispMode();
}
// Returns the number of pointer and integer slots used to represent a member
@@ -209,19 +215,19 @@ MSVtorDispAttr::Mode CXXRecordDecl::getMSVtorDispMode() const {
static std::pair<unsigned, unsigned>
getMSMemberPointerSlots(const MemberPointerType *MPT) {
const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
- MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
+ MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
unsigned Ptrs = 0;
unsigned Ints = 0;
if (MPT->isMemberFunctionPointer())
Ptrs = 1;
else
Ints = 1;
- if (MSInheritanceAttr::hasNVOffsetField(MPT->isMemberFunctionPointer(),
+ if (inheritanceModelHasNVOffsetField(MPT->isMemberFunctionPointer(),
Inheritance))
Ints++;
- if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance))
+ if (inheritanceModelHasVBPtrOffsetField(Inheritance))
Ints++;
- if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
+ if (inheritanceModelHasVBTableOffsetField(Inheritance))
Ints++;
return std::make_pair(Ptrs, Ints);
}
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index f871a1b99900..a286c5335584 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -279,8 +279,6 @@ class MicrosoftCXXNameMangler {
ASTContext &getASTContext() const { return Context.getASTContext(); }
- // FIXME: If we add support for __ptr32/64 qualifiers, then we should push
- // this check into mangleQualifiers().
const bool PointersAre64Bit;
public:
@@ -335,6 +333,13 @@ private:
return ND == Structor || getStructor(ND) == Structor;
}
+ bool is64BitPointer(Qualifiers Quals) const {
+ LangAS AddrSpace = Quals.getAddressSpace();
+ return AddrSpace == LangAS::ptr64 ||
+ (PointersAre64Bit && !(AddrSpace == LangAS::ptr32_sptr ||
+ AddrSpace == LangAS::ptr32_uptr));
+ }
+
void mangleUnqualifiedName(const NamedDecl *ND) {
mangleUnqualifiedName(ND, ND->getDeclName());
}
@@ -592,7 +597,7 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD,
int64_t FieldOffset;
int64_t VBTableOffset;
- MSInheritanceAttr::Spelling IM = RD->getMSInheritanceModel();
+ MSInheritanceModel IM = RD->getMSInheritanceModel();
if (VD) {
FieldOffset = getASTContext().getFieldOffset(VD);
assert(FieldOffset % getASTContext().getCharWidth() == 0 &&
@@ -601,7 +606,7 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD,
VBTableOffset = 0;
- if (IM == MSInheritanceAttr::Keyword_virtual_inheritance)
+ if (IM == MSInheritanceModel::Virtual)
FieldOffset -= getASTContext().getOffsetOfBaseWithVBPtr(RD).getQuantity();
} else {
FieldOffset = RD->nullFieldOffsetIsZero() ? 0 : -1;
@@ -611,12 +616,10 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD,
char Code = '\0';
switch (IM) {
- case MSInheritanceAttr::Keyword_single_inheritance: Code = '0'; break;
- case MSInheritanceAttr::Keyword_multiple_inheritance: Code = '0'; break;
- case MSInheritanceAttr::Keyword_virtual_inheritance: Code = 'F'; break;
- case MSInheritanceAttr::Keyword_unspecified_inheritance: Code = 'G'; break;
- case MSInheritanceAttr::SpellingNotCalculated:
- llvm_unreachable("not reachable");
+ case MSInheritanceModel::Single: Code = '0'; break;
+ case MSInheritanceModel::Multiple: Code = '0'; break;
+ case MSInheritanceModel::Virtual: Code = 'F'; break;
+ case MSInheritanceModel::Unspecified: Code = 'G'; break;
}
Out << '$' << Code;
@@ -626,9 +629,9 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD,
// The C++ standard doesn't allow base-to-derived member pointer conversions
// in template parameter contexts, so the vbptr offset of data member pointers
// is always zero.
- if (MSInheritanceAttr::hasVBPtrOffsetField(IM))
+ if (inheritanceModelHasVBPtrOffsetField(IM))
mangleNumber(0);
- if (MSInheritanceAttr::hasVBTableOffsetField(IM))
+ if (inheritanceModelHasVBTableOffsetField(IM))
mangleNumber(VBTableOffset);
}
@@ -640,16 +643,14 @@ MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD,
// ::= $I? <name> <number> <number>
// ::= $J? <name> <number> <number> <number>
- MSInheritanceAttr::Spelling IM = RD->getMSInheritanceModel();
+ MSInheritanceModel IM = RD->getMSInheritanceModel();
char Code = '\0';
switch (IM) {
- case MSInheritanceAttr::Keyword_single_inheritance: Code = '1'; break;
- case MSInheritanceAttr::Keyword_multiple_inheritance: Code = 'H'; break;
- case MSInheritanceAttr::Keyword_virtual_inheritance: Code = 'I'; break;
- case MSInheritanceAttr::Keyword_unspecified_inheritance: Code = 'J'; break;
- case MSInheritanceAttr::SpellingNotCalculated:
- llvm_unreachable("not reachable");
+ case MSInheritanceModel::Single: Code = '1'; break;
+ case MSInheritanceModel::Multiple: Code = 'H'; break;
+ case MSInheritanceModel::Virtual: Code = 'I'; break;
+ case MSInheritanceModel::Unspecified: Code = 'J'; break;
}
// If non-virtual, mangle the name. If virtual, mangle as a virtual memptr
@@ -676,25 +677,24 @@ MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD,
mangleFunctionEncoding(MD, /*ShouldMangle=*/true);
}
- if (VBTableOffset == 0 &&
- IM == MSInheritanceAttr::Keyword_virtual_inheritance)
+ if (VBTableOffset == 0 && IM == MSInheritanceModel::Virtual)
NVOffset -= getASTContext().getOffsetOfBaseWithVBPtr(RD).getQuantity();
} else {
// Null single inheritance member functions are encoded as a simple nullptr.
- if (IM == MSInheritanceAttr::Keyword_single_inheritance) {
+ if (IM == MSInheritanceModel::Single) {
Out << "$0A@";
return;
}
- if (IM == MSInheritanceAttr::Keyword_unspecified_inheritance)
+ if (IM == MSInheritanceModel::Unspecified)
VBTableOffset = -1;
Out << '$' << Code;
}
- if (MSInheritanceAttr::hasNVOffsetField(/*IsMemberFunction=*/true, IM))
+ if (inheritanceModelHasNVOffsetField(/*IsMemberFunction=*/true, IM))
mangleNumber(static_cast<uint32_t>(NVOffset));
- if (MSInheritanceAttr::hasVBPtrOffsetField(IM))
+ if (inheritanceModelHasVBPtrOffsetField(IM))
mangleNumber(VBPtrOffset);
- if (MSInheritanceAttr::hasVBTableOffsetField(IM))
+ if (inheritanceModelHasVBTableOffsetField(IM))
mangleNumber(VBTableOffset);
}
@@ -710,7 +710,7 @@ void MicrosoftCXXNameMangler::mangleVirtualMemPtrThunk(
Out << "$B";
mangleNumber(OffsetInVFTable);
Out << 'A';
- mangleCallingConvention(MD->getType()->getAs<FunctionProtoType>());
+ mangleCallingConvention(MD->getType()->castAs<FunctionProtoType>());
}
void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) {
@@ -1708,8 +1708,10 @@ MicrosoftCXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) {
void MicrosoftCXXNameMangler::manglePointerExtQualifiers(Qualifiers Quals,
QualType PointeeType) {
- if (PointersAre64Bit &&
- (PointeeType.isNull() || !PointeeType->isFunctionType()))
+ // Check if this is a default 64-bit pointer or has __ptr64 qualifier.
+ bool is64Bit = PointeeType.isNull() ? PointersAre64Bit :
+ is64BitPointer(PointeeType.getQualifiers());
+ if (is64Bit && (PointeeType.isNull() || !PointeeType->isFunctionType()))
Out << 'E';
if (Quals.hasRestrict())
@@ -1869,6 +1871,10 @@ void MicrosoftCXXNameMangler::mangleAddressSpaceType(QualType T,
case LangAS::cuda_shared:
Extra.mangleSourceName("_ASCUshared");
break;
+ case LangAS::ptr32_sptr:
+ case LangAS::ptr32_uptr:
+ case LangAS::ptr64:
+ llvm_unreachable("don't mangle ptr address spaces with _AS");
}
}
@@ -2602,10 +2608,13 @@ void MicrosoftCXXNameMangler::mangleType(const PointerType *T, Qualifiers Quals,
manglePointerCVQualifiers(Quals);
manglePointerExtQualifiers(Quals, PointeeType);
- if (PointeeType.getQualifiers().hasAddressSpace())
- mangleAddressSpaceType(PointeeType, PointeeType.getQualifiers(), Range);
- else
+ // For pointer size address spaces, go down the same type mangling path as
+ // non address space types.
+ LangAS AddrSpace = PointeeType.getQualifiers().getAddressSpace();
+ if (isPtrSizeAddressSpace(AddrSpace) || AddrSpace == LangAS::Default)
mangleType(PointeeType, Range);
+ else
+ mangleAddressSpaceType(PointeeType, PointeeType.getQualifiers(), Range);
}
void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T,
@@ -2692,9 +2701,7 @@ void MicrosoftCXXNameMangler::mangleType(const VectorType *T, Qualifiers Quals,
// doesn't match the Intel types uses a custom mangling below.
size_t OutSizeBefore = Out.tell();
if (!isa<ExtVectorType>(T)) {
- llvm::Triple::ArchType AT =
- getASTContext().getTargetInfo().getTriple().getArch();
- if (AT == llvm::Triple::x86 || AT == llvm::Triple::x86_64) {
+ if (getASTContext().getTargetInfo().getTriple().isX86()) {
if (Width == 64 && ET->getKind() == BuiltinType::LongLong) {
mangleArtificialTagType(TTK_Union, "__m64");
} else if (Width >= 128) {
diff --git a/clang/lib/AST/NestedNameSpecifier.cpp b/clang/lib/AST/NestedNameSpecifier.cpp
index 09d85102585b..137953fa8203 100644
--- a/clang/lib/AST/NestedNameSpecifier.cpp
+++ b/clang/lib/AST/NestedNameSpecifier.cpp
@@ -472,7 +472,7 @@ TypeLoc NestedNameSpecifierLoc::getTypeLoc() const {
}
static void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize,
- unsigned &BufferCapacity) {
+ unsigned &BufferCapacity) {
if (Start == End)
return;
@@ -489,9 +489,9 @@ static void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize,
Buffer = NewBuffer;
BufferCapacity = NewCapacity;
}
-
+ assert(Buffer && Start && End && End > Start && "Illegal memory buffer copy");
memcpy(Buffer + BufferSize, Start, End - Start);
- BufferSize += End-Start;
+ BufferSize += End - Start;
}
/// Save a source location to the given buffer.
diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
index 3b89c630b451..27fdca1c4b9c 100644
--- a/clang/lib/AST/ODRHash.cpp
+++ b/clang/lib/AST/ODRHash.cpp
@@ -380,6 +380,11 @@ public:
}
Hash.AddBoolean(D->isParameterPack());
+ const TypeConstraint *TC = D->getTypeConstraint();
+ Hash.AddBoolean(TC != nullptr);
+ if (TC)
+ AddStmt(TC->getImmediatelyDeclaredConstraint());
+
Inherited::VisitTemplateTypeParmDecl(D);
}
diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp
index fe1334469d48..5ef82648c89d 100644
--- a/clang/lib/AST/OpenMPClause.cpp
+++ b/clang/lib/AST/OpenMPClause.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclOpenMP.h"
#include "clang/Basic/LLVM.h"
+#include "clang/Basic/OpenMPKinds.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
@@ -135,6 +136,7 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
case OMPC_atomic_default_mem_order:
case OMPC_device_type:
case OMPC_match:
+ case OMPC_nontemporal:
break;
}
@@ -213,6 +215,7 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C)
case OMPC_atomic_default_mem_order:
case OMPC_device_type:
case OMPC_match:
+ case OMPC_nontemporal:
break;
}
@@ -402,11 +405,12 @@ void OMPLastprivateClause::setAssignmentOps(ArrayRef<Expr *> AssignmentOps) {
OMPLastprivateClause *OMPLastprivateClause::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs,
- ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps, Stmt *PreInit,
- Expr *PostUpdate) {
+ ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps,
+ OpenMPLastprivateModifier LPKind, SourceLocation LPKindLoc,
+ SourceLocation ColonLoc, Stmt *PreInit, Expr *PostUpdate) {
void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * VL.size()));
- OMPLastprivateClause *Clause =
- new (Mem) OMPLastprivateClause(StartLoc, LParenLoc, EndLoc, VL.size());
+ OMPLastprivateClause *Clause = new (Mem) OMPLastprivateClause(
+ StartLoc, LParenLoc, EndLoc, LPKind, LPKindLoc, ColonLoc, VL.size());
Clause->setVarRefs(VL);
Clause->setSourceExprs(SrcExprs);
Clause->setDestinationExprs(DstExprs);
@@ -1155,13 +1159,38 @@ OMPIsDevicePtrClause::CreateEmpty(const ASTContext &C,
return new (Mem) OMPIsDevicePtrClause(Sizes);
}
+OMPNontemporalClause *OMPNontemporalClause::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc,
+ ArrayRef<Expr *> VL) {
+ // Allocate space for nontemporal variables + private references.
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(2 * VL.size()));
+ auto *Clause =
+ new (Mem) OMPNontemporalClause(StartLoc, LParenLoc, EndLoc, VL.size());
+ Clause->setVarRefs(VL);
+ return Clause;
+}
+
+OMPNontemporalClause *OMPNontemporalClause::CreateEmpty(const ASTContext &C,
+ unsigned N) {
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(2 * N));
+ return new (Mem) OMPNontemporalClause(N);
+}
+
+void OMPNontemporalClause::setPrivateRefs(ArrayRef<Expr *> VL) {
+ assert(VL.size() == varlist_size() && "Number of private references is not "
+ "the same as the preallocated buffer");
+ std::copy(VL.begin(), VL.end(), varlist_end());
+}
+
//===----------------------------------------------------------------------===//
// OpenMP clauses printing methods
//===----------------------------------------------------------------------===//
void OMPClausePrinter::VisitOMPIfClause(OMPIfClause *Node) {
OS << "if(";
- if (Node->getNameModifier() != OMPD_unknown)
+ if (Node->getNameModifier() != llvm::omp::OMPD_unknown)
OS << getOpenMPDirectiveName(Node->getNameModifier()) << ": ";
Node->getCondition()->printPretty(OS, nullptr, Policy, 0);
OS << ")";
@@ -1211,7 +1240,8 @@ void OMPClausePrinter::VisitOMPDefaultClause(OMPDefaultClause *Node) {
void OMPClausePrinter::VisitOMPProcBindClause(OMPProcBindClause *Node) {
OS << "proc_bind("
- << getOpenMPSimpleClauseTypeName(OMPC_proc_bind, Node->getProcBindKind())
+ << getOpenMPSimpleClauseTypeName(OMPC_proc_bind,
+ unsigned(Node->getProcBindKind()))
<< ")";
}
@@ -1401,7 +1431,13 @@ void OMPClausePrinter::VisitOMPFirstprivateClause(OMPFirstprivateClause *Node) {
void OMPClausePrinter::VisitOMPLastprivateClause(OMPLastprivateClause *Node) {
if (!Node->varlist_empty()) {
OS << "lastprivate";
- VisitOMPClauseList(Node, '(');
+ OpenMPLastprivateModifier LPKind = Node->getKind();
+ if (LPKind != OMPC_LASTPRIVATE_unknown) {
+ OS << "("
+ << getOpenMPSimpleClauseTypeName(OMPC_lastprivate, Node->getKind())
+ << ":";
+ }
+ VisitOMPClauseList(Node, LPKind == OMPC_LASTPRIVATE_unknown ? '(' : ' ');
OS << ")";
}
}
@@ -1648,3 +1684,10 @@ void OMPClausePrinter::VisitOMPIsDevicePtrClause(OMPIsDevicePtrClause *Node) {
}
}
+void OMPClausePrinter::VisitOMPNontemporalClause(OMPNontemporalClause *Node) {
+ if (!Node->varlist_empty()) {
+ OS << "nontemporal";
+ VisitOMPClauseList(Node, '(');
+ OS << ")";
+ }
+}
diff --git a/clang/lib/AST/QualTypeNames.cpp b/clang/lib/AST/QualTypeNames.cpp
index f28f00171cce..73a33a208233 100644
--- a/clang/lib/AST/QualTypeNames.cpp
+++ b/clang/lib/AST/QualTypeNames.cpp
@@ -192,7 +192,7 @@ static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D,
// Ignore inline namespace;
NS = dyn_cast<NamespaceDecl>(NS->getDeclContext());
}
- if (NS->getDeclName()) {
+ if (NS && NS->getDeclName()) {
return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix);
}
return nullptr; // no starting '::', no anonymous
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp
index 2a3419a0cec3..9a21732b63e3 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -2956,7 +2956,7 @@ void MicrosoftRecordLayoutBuilder::computeVtorDispSet(
const CXXRecordDecl *RD) const {
// /vd2 or #pragma vtordisp(2): Always use vtordisps for virtual bases with
// vftables.
- if (RD->getMSVtorDispMode() == MSVtorDispAttr::ForVFTable) {
+ if (RD->getMSVtorDispMode() == MSVtorDispMode::ForVFTable) {
for (const CXXBaseSpecifier &Base : RD->vbases()) {
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
@@ -2979,12 +2979,12 @@ void MicrosoftRecordLayoutBuilder::computeVtorDispSet(
// * A user declared constructor or destructor aren't declared.
// * #pragma vtordisp(0) or the /vd0 flag are in use.
if ((!RD->hasUserDeclaredConstructor() && !RD->hasUserDeclaredDestructor()) ||
- RD->getMSVtorDispMode() == MSVtorDispAttr::Never)
+ RD->getMSVtorDispMode() == MSVtorDispMode::Never)
return;
// /vd1 or #pragma vtordisp(1): Try to guess based on whether we think it's
// possible for a partially constructed object with virtual base overrides to
// escape a non-trivial constructor.
- assert(RD->getMSVtorDispMode() == MSVtorDispAttr::ForVBaseOverride);
+ assert(RD->getMSVtorDispMode() == MSVtorDispMode::ForVBaseOverride);
// Compute a set of base classes which define methods we override. A virtual
// base in this set will require a vtordisp. A virtual base that transitively
// contains one of these bases as a non-virtual base will also require a
diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp
index 80a1451ac789..b6e4d8aff21e 100644
--- a/clang/lib/AST/Stmt.cpp
+++ b/clang/lib/AST/Stmt.cpp
@@ -908,6 +908,12 @@ bool IfStmt::isObjCAvailabilityCheck() const {
return isa<ObjCAvailabilityCheckExpr>(getCond());
}
+Optional<const Stmt*> IfStmt::getNondiscardedCase(const ASTContext &Ctx) const {
+ if (!isConstexpr() || getCond()->isValueDependent())
+ return None;
+ return !getCond()->EvaluateKnownConstInt(Ctx) ? getElse() : getThen();
+}
+
ForStmt::ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar,
Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP,
SourceLocation RP)
diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp
index da1364ebffc4..da6d308ad15b 100644
--- a/clang/lib/AST/StmtOpenMP.cpp
+++ b/clang/lib/AST/StmtOpenMP.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/ASTContext.h"
using namespace clang;
+using namespace llvm::omp;
void OMPExecutableDirective::setClauses(ArrayRef<OMPClause *> Clauses) {
assert(Clauses.size() == getNumClauses() &&
@@ -41,6 +42,74 @@ const Stmt *OMPExecutableDirective::getStructuredBlock() const {
return getInnermostCapturedStmt()->getCapturedStmt();
}
+Stmt *OMPLoopDirective::tryToFindNextInnerLoop(Stmt *CurStmt,
+ bool TryImperfectlyNestedLoops) {
+ Stmt *OrigStmt = CurStmt;
+ CurStmt = CurStmt->IgnoreContainers();
+ // Additional work for imperfectly nested loops, introduced in OpenMP 5.0.
+ if (TryImperfectlyNestedLoops) {
+ if (auto *CS = dyn_cast<CompoundStmt>(CurStmt)) {
+ CurStmt = nullptr;
+ SmallVector<CompoundStmt *, 4> Statements(1, CS);
+ SmallVector<CompoundStmt *, 4> NextStatements;
+ while (!Statements.empty()) {
+ CS = Statements.pop_back_val();
+ if (!CS)
+ continue;
+ for (Stmt *S : CS->body()) {
+ if (!S)
+ continue;
+ if (isa<ForStmt>(S) || isa<CXXForRangeStmt>(S)) {
+ // Only single loop construct is allowed.
+ if (CurStmt) {
+ CurStmt = OrigStmt;
+ break;
+ }
+ CurStmt = S;
+ continue;
+ }
+ S = S->IgnoreContainers();
+ if (auto *InnerCS = dyn_cast_or_null<CompoundStmt>(S))
+ NextStatements.push_back(InnerCS);
+ }
+ if (Statements.empty()) {
+ // Found single inner loop or multiple loops - exit.
+ if (CurStmt)
+ break;
+ Statements.swap(NextStatements);
+ }
+ }
+ if (!CurStmt)
+ CurStmt = OrigStmt;
+ }
+ }
+ return CurStmt;
+}
+
+Stmt *OMPLoopDirective::getBody() {
+ // This relies on the loop form is already checked by Sema.
+ Stmt *Body =
+ getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers();
+ if (auto *For = dyn_cast<ForStmt>(Body)) {
+ Body = For->getBody();
+ } else {
+ assert(isa<CXXForRangeStmt>(Body) &&
+ "Expected canonical for loop or range-based for loop.");
+ Body = cast<CXXForRangeStmt>(Body)->getBody();
+ }
+ for (unsigned Cnt = 1; Cnt < CollapsedNum; ++Cnt) {
+ Body = tryToFindNextInnerLoop(Body, /*TryImperfectlyNestedLoops=*/true);
+ if (auto *For = dyn_cast<ForStmt>(Body)) {
+ Body = For->getBody();
+ } else {
+ assert(isa<CXXForRangeStmt>(Body) &&
+ "Expected canonical for loop or range-based for loop.");
+ Body = cast<CXXForRangeStmt>(Body)->getBody();
+ }
+ }
+ return Body;
+}
+
void OMPLoopDirective::setCounters(ArrayRef<Expr *> A) {
assert(A.size() == getCollapsedNumber() &&
"Number of loop counters is not the same as the collapsed number");
@@ -482,6 +551,30 @@ OMPParallelForSimdDirective::CreateEmpty(const ASTContext &C,
return new (Mem) OMPParallelForSimdDirective(CollapsedNum, NumClauses);
}
+OMPParallelMasterDirective *OMPParallelMasterDirective::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt) {
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPParallelMasterDirective), alignof(OMPClause *));
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *));
+ auto *Dir =
+ new (Mem) OMPParallelMasterDirective(StartLoc, EndLoc, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ return Dir;
+}
+
+OMPParallelMasterDirective *OMPParallelMasterDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ EmptyShell) {
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPParallelMasterDirective), alignof(OMPClause *));
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *));
+ return new (Mem) OMPParallelMasterDirective(NumClauses);
+}
+
OMPParallelSectionsDirective *OMPParallelSectionsDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, bool HasCancel) {
@@ -1182,6 +1275,63 @@ OMPParallelMasterTaskLoopDirective::CreateEmpty(const ASTContext &C,
return new (Mem) OMPParallelMasterTaskLoopDirective(CollapsedNum, NumClauses);
}
+OMPParallelMasterTaskLoopSimdDirective *
+OMPParallelMasterTaskLoopSimdDirective::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
+ const HelperExprs &Exprs) {
+ unsigned Size = llvm::alignTo(sizeof(OMPParallelMasterTaskLoopSimdDirective),
+ alignof(OMPClause *));
+ void *Mem = C.Allocate(
+ Size + sizeof(OMPClause *) * Clauses.size() +
+ sizeof(Stmt *) *
+ numLoopChildren(CollapsedNum, OMPD_parallel_master_taskloop_simd));
+ auto *Dir = new (Mem) OMPParallelMasterTaskLoopSimdDirective(
+ StartLoc, EndLoc, CollapsedNum, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ Dir->setIterationVariable(Exprs.IterationVarRef);
+ Dir->setLastIteration(Exprs.LastIteration);
+ Dir->setCalcLastIteration(Exprs.CalcLastIteration);
+ Dir->setPreCond(Exprs.PreCond);
+ Dir->setCond(Exprs.Cond);
+ Dir->setInit(Exprs.Init);
+ Dir->setInc(Exprs.Inc);
+ Dir->setIsLastIterVariable(Exprs.IL);
+ Dir->setLowerBoundVariable(Exprs.LB);
+ Dir->setUpperBoundVariable(Exprs.UB);
+ Dir->setStrideVariable(Exprs.ST);
+ Dir->setEnsureUpperBound(Exprs.EUB);
+ Dir->setNextLowerBound(Exprs.NLB);
+ Dir->setNextUpperBound(Exprs.NUB);
+ Dir->setNumIterations(Exprs.NumIterations);
+ Dir->setCounters(Exprs.Counters);
+ Dir->setPrivateCounters(Exprs.PrivateCounters);
+ Dir->setInits(Exprs.Inits);
+ Dir->setUpdates(Exprs.Updates);
+ Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
+ Dir->setPreInits(Exprs.PreInits);
+ return Dir;
+}
+
+OMPParallelMasterTaskLoopSimdDirective *
+OMPParallelMasterTaskLoopSimdDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ unsigned CollapsedNum,
+ EmptyShell) {
+ unsigned Size = llvm::alignTo(sizeof(OMPParallelMasterTaskLoopSimdDirective),
+ alignof(OMPClause *));
+ void *Mem = C.Allocate(
+ Size + sizeof(OMPClause *) * NumClauses +
+ sizeof(Stmt *) *
+ numLoopChildren(CollapsedNum, OMPD_parallel_master_taskloop_simd));
+ return new (Mem)
+ OMPParallelMasterTaskLoopSimdDirective(CollapsedNum, NumClauses);
+}
+
OMPDistributeDirective *OMPDistributeDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index 7759ff6c1389..c14bb886bb11 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -697,7 +697,7 @@ void StmtPrinter::VisitOMPCriticalDirective(OMPCriticalDirective *Node) {
Indent() << "#pragma omp critical";
if (Node->getDirectiveName().getName()) {
OS << " (";
- Node->getDirectiveName().printName(OS);
+ Node->getDirectiveName().printName(OS, Policy);
OS << ")";
}
PrintOMPExecutableDirective(Node);
@@ -714,6 +714,12 @@ void StmtPrinter::VisitOMPParallelForSimdDirective(
PrintOMPExecutableDirective(Node);
}
+void StmtPrinter::VisitOMPParallelMasterDirective(
+ OMPParallelMasterDirective *Node) {
+ Indent() << "#pragma omp parallel master";
+ PrintOMPExecutableDirective(Node);
+}
+
void StmtPrinter::VisitOMPParallelSectionsDirective(
OMPParallelSectionsDirective *Node) {
Indent() << "#pragma omp parallel sections";
@@ -841,6 +847,12 @@ void StmtPrinter::VisitOMPParallelMasterTaskLoopDirective(
PrintOMPExecutableDirective(Node);
}
+void StmtPrinter::VisitOMPParallelMasterTaskLoopSimdDirective(
+ OMPParallelMasterTaskLoopSimdDirective *Node) {
+ Indent() << "#pragma omp parallel master taskloop simd";
+ PrintOMPExecutableDirective(Node);
+}
+
void StmtPrinter::VisitOMPDistributeDirective(OMPDistributeDirective *Node) {
Indent() << "#pragma omp distribute";
PrintOMPExecutableDirective(Node);
@@ -1298,7 +1310,7 @@ void StmtPrinter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node){
void StmtPrinter::VisitGenericSelectionExpr(GenericSelectionExpr *Node) {
OS << "_Generic(";
PrintExpr(Node->getControllingExpr());
- for (const GenericSelectionExpr::Association &Assoc : Node->associations()) {
+ for (const GenericSelectionExpr::Association Assoc : Node->associations()) {
OS << ", ";
QualType T = Assoc.getType();
if (T.isNull())
@@ -2229,7 +2241,7 @@ void StmtPrinter::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) {
}
void StmtPrinter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *Node){
- PrintExpr(Node->GetTemporaryExpr());
+ PrintExpr(Node->getSubExpr());
}
void StmtPrinter::VisitCXXFoldExpr(CXXFoldExpr *E) {
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index d1e856538932..2aa5106e90fa 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -769,7 +769,13 @@ void OMPClauseProfiler::VisitOMPIsDevicePtrClause(
const OMPIsDevicePtrClause *C) {
VisitOMPClauseList(C);
}
+void OMPClauseProfiler::VisitOMPNontemporalClause(
+ const OMPNontemporalClause *C) {
+ VisitOMPClauseList(C);
+ for (auto *E : C->private_refs())
+ Profiler->VisitStmt(E);
}
+} // namespace
void
StmtProfiler::VisitOMPExecutableDirective(const OMPExecutableDirective *S) {
@@ -833,6 +839,11 @@ void StmtProfiler::VisitOMPParallelForSimdDirective(
VisitOMPLoopDirective(S);
}
+void StmtProfiler::VisitOMPParallelMasterDirective(
+ const OMPParallelMasterDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
void StmtProfiler::VisitOMPParallelSectionsDirective(
const OMPParallelSectionsDirective *S) {
VisitOMPExecutableDirective(S);
@@ -937,6 +948,11 @@ void StmtProfiler::VisitOMPParallelMasterTaskLoopDirective(
VisitOMPLoopDirective(S);
}
+void StmtProfiler::VisitOMPParallelMasterTaskLoopSimdDirective(
+ const OMPParallelMasterTaskLoopSimdDirective *S) {
+ VisitOMPLoopDirective(S);
+}
+
void StmtProfiler::VisitOMPDistributeDirective(
const OMPDistributeDirective *S) {
VisitOMPLoopDirective(S);
@@ -1291,7 +1307,7 @@ void StmtProfiler::VisitBlockExpr(const BlockExpr *S) {
void StmtProfiler::VisitGenericSelectionExpr(const GenericSelectionExpr *S) {
VisitExpr(S);
- for (const GenericSelectionExpr::ConstAssociation &Assoc :
+ for (const GenericSelectionExpr::ConstAssociation Assoc :
S->associations()) {
QualType T = Assoc.getType();
if (T.isNull())
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 63a6510324f7..965ad17fcfa5 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -489,6 +489,9 @@ void TextNodeDumper::visitInlineCommandComment(
case comments::InlineCommandComment::RenderEmphasized:
OS << " RenderEmphasized";
break;
+ case comments::InlineCommandComment::RenderAnchor:
+ OS << " RenderAnchor";
+ break;
}
for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
@@ -1338,6 +1341,17 @@ void TextNodeDumper::VisitFunctionDecl(const FunctionDecl *D) {
OS << " <<<NULL params x " << D->getNumParams() << ">>>";
}
+void TextNodeDumper::VisitLifetimeExtendedTemporaryDecl(
+ const LifetimeExtendedTemporaryDecl *D) {
+ OS << " extended by ";
+ dumpBareDeclRef(D->getExtendingDecl());
+ OS << " mangling ";
+ {
+ ColorScope Color(OS, ShowColors, ValueColor);
+ OS << D->getManglingNumber();
+ }
+}
+
void TextNodeDumper::VisitFieldDecl(const FieldDecl *D) {
dumpName(D);
dumpType(D->getType());
@@ -1680,7 +1694,16 @@ void TextNodeDumper::VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D) {
}
void TextNodeDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
- if (D->wasDeclaredWithTypename())
+ if (const auto *TC = D->getTypeConstraint()) {
+ OS << " ";
+ dumpBareDeclRef(TC->getNamedConcept());
+ if (TC->getNamedConcept() != TC->getFoundDecl()) {
+ OS << " (";
+ dumpBareDeclRef(TC->getFoundDecl());
+ OS << ")";
+ }
+ Visit(TC->getImmediatelyDeclaredConstraint());
+ } else if (D->wasDeclaredWithTypename())
OS << " typename";
else
OS << " class";
@@ -1769,12 +1792,6 @@ void TextNodeDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *D) {
case LinkageSpecDecl::lang_cxx:
OS << " C++";
break;
- case LinkageSpecDecl::lang_cxx_11:
- OS << " C++11";
- break;
- case LinkageSpecDecl::lang_cxx_14:
- OS << " C++14";
- break;
}
}
@@ -1921,6 +1938,8 @@ void TextNodeDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
OS << " unsafe_unretained";
if (Attrs & ObjCPropertyDecl::OBJC_PR_class)
OS << " class";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_direct)
+ OS << " direct";
if (Attrs & ObjCPropertyDecl::OBJC_PR_getter)
dumpDeclRef(D->getGetterMethodDecl(), "getter");
if (Attrs & ObjCPropertyDecl::OBJC_PR_setter)
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 4d54ea1061ed..c5ad711d872e 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -663,10 +663,6 @@ ObjCTypeParamType::ObjCTypeParamType(const ObjCTypeParamDecl *D,
initialize(protocols);
}
-QualType ObjCTypeParamType::desugar() const {
- return getDecl()->getUnderlyingType();
-}
-
ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base,
ArrayRef<QualType> typeArgs,
ArrayRef<ObjCProtocolDecl *> protocols,
@@ -1860,13 +1856,12 @@ bool Type::isIntegralOrUnscopedEnumerationType() const {
if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() >= BuiltinType::Bool &&
BT->getKind() <= BuiltinType::Int128;
+ return isUnscopedEnumerationType();
+}
- // Check for a complete enum type; incomplete enum types are not properly an
- // enumeration type in the sense required here.
- // C++0x: However, if the underlying type of the enum is fixed, it is
- // considered complete.
+bool Type::isUnscopedEnumerationType() const {
if (const auto *ET = dyn_cast<EnumType>(CanonicalType))
- return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped();
+ return !ET->getDecl()->isScoped();
return false;
}
@@ -3069,6 +3064,12 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params,
} else {
FunctionTypeBits.HasExtQuals = 0;
}
+
+ // Fill in the Ellipsis location info if present.
+ if (epi.Variadic) {
+ auto &EllipsisLoc = *getTrailingObjects<SourceLocation>();
+ EllipsisLoc = epi.EllipsisLoc;
+ }
}
bool FunctionProtoType::hasDependentExceptionSpec() const {
diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp
index e4788f32b265..6e67ca8e0af7 100644
--- a/clang/lib/AST/TypeLoc.cpp
+++ b/clang/lib/AST/TypeLoc.cpp
@@ -12,6 +12,7 @@
#include "clang/AST/TypeLoc.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Expr.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TemplateBase.h"
@@ -293,6 +294,12 @@ bool TypeSpecTypeLoc::isKind(const TypeLoc &TL) {
return TSTChecker().Visit(TL);
}
+bool TagTypeLoc::isDefinition() const {
+ TagDecl *D = getDecl();
+ return D->isCompleteDefinition() &&
+ (D->getIdentifier() == nullptr || D->getLocation() == getNameLoc());
+}
+
// Reimplemented to account for GNU/C++ extension
// typeof unary-expression
// where there are no parentheses.
@@ -467,6 +474,19 @@ void ObjCObjectTypeLoc::initializeLocal(ASTContext &Context,
setProtocolLoc(i, Loc);
}
+SourceRange AttributedTypeLoc::getLocalSourceRange() const {
+ // Note that this does *not* include the range of the attribute
+ // enclosure, e.g.:
+ // __attribute__((foo(bar)))
+ // ^~~~~~~~~~~~~~~ ~~
+ // or
+ // [[foo(bar)]]
+ // ^~ ~~
+ // That enclosure doesn't necessarily belong to a single attribute
+ // anyway.
+ return getAttr() ? getAttr()->getRange() : SourceRange();
+}
+
void TypeOfTypeLoc::initializeLocal(ASTContext &Context,
SourceLocation Loc) {
TypeofLikeTypeLoc<TypeOfTypeLoc, TypeOfType, TypeOfTypeLocInfo>
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index dacbf9a96d81..c2f4baec989e 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1189,8 +1189,8 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) {
if (PLoc.isValid()) {
OS << " at ";
StringRef File = PLoc.getFilename();
- if (Policy.RemapFilePaths)
- OS << Policy.remapPath(File);
+ if (auto *Callbacks = Policy.Callbacks)
+ OS << Callbacks->remapPath(File);
else
OS << File;
OS << ':' << PLoc.getLine() << ':' << PLoc.getColumn();
@@ -1555,6 +1555,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
case attr::NoDeref:
OS << "noderef";
break;
+ case attr::AcquireHandle:
+ OS << "acquire_handle";
+ break;
}
OS << "))";
}
@@ -1772,6 +1775,37 @@ bool Qualifiers::isEmptyWhenPrinted(const PrintingPolicy &Policy) const {
return true;
}
+std::string Qualifiers::getAddrSpaceAsString(LangAS AS) {
+ switch (AS) {
+ case LangAS::Default:
+ return "";
+ case LangAS::opencl_global:
+ return "__global";
+ case LangAS::opencl_local:
+ return "__local";
+ case LangAS::opencl_private:
+ return "__private";
+ case LangAS::opencl_constant:
+ return "__constant";
+ case LangAS::opencl_generic:
+ return "__generic";
+ case LangAS::cuda_device:
+ return "__device__";
+ case LangAS::cuda_constant:
+ return "__constant__";
+ case LangAS::cuda_shared:
+ return "__shared__";
+ case LangAS::ptr32_sptr:
+ return "__sptr __ptr32";
+ case LangAS::ptr32_uptr:
+ return "__uptr __ptr32";
+ case LangAS::ptr64:
+ return "__ptr64";
+ default:
+ return std::to_string(toTargetAddressSpace(AS));
+ }
+}
+
// Appends qualifiers to the given string, separated by spaces. Will
// prefix a space if the string is non-empty. Will not append a final
// space.
@@ -1790,43 +1824,18 @@ void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy,
OS << "__unaligned";
addSpace = true;
}
- LangAS addrspace = getAddressSpace();
- if (addrspace != LangAS::Default) {
- if (addrspace != LangAS::opencl_private) {
- if (addSpace)
- OS << ' ';
- addSpace = true;
- switch (addrspace) {
- case LangAS::opencl_global:
- OS << "__global";
- break;
- case LangAS::opencl_local:
- OS << "__local";
- break;
- case LangAS::opencl_private:
- break;
- case LangAS::opencl_constant:
- OS << "__constant";
- break;
- case LangAS::opencl_generic:
- OS << "__generic";
- break;
- case LangAS::cuda_device:
- OS << "__device__";
- break;
- case LangAS::cuda_constant:
- OS << "__constant__";
- break;
- case LangAS::cuda_shared:
- OS << "__shared__";
- break;
- default:
- OS << "__attribute__((address_space(";
- OS << toTargetAddressSpace(addrspace);
- OS << ")))";
- }
- }
+ auto ASStr = getAddrSpaceAsString(getAddressSpace());
+ if (!ASStr.empty()) {
+ if (addSpace)
+ OS << ' ';
+ addSpace = true;
+ // Wrap target address space into an attribute syntax
+ if (isTargetAddressSpace(getAddressSpace()))
+ OS << "__attribute__((address_space(" << ASStr << ")))";
+ else
+ OS << ASStr;
}
+
if (Qualifiers::GC gc = getObjCGCAttr()) {
if (addSpace)
OS << ' ';
diff --git a/clang/lib/AST/VTableBuilder.cpp b/clang/lib/AST/VTableBuilder.cpp
index 5688042dadd9..2b5b74be5961 100644
--- a/clang/lib/AST/VTableBuilder.cpp
+++ b/clang/lib/AST/VTableBuilder.cpp
@@ -270,8 +270,8 @@ static BaseOffset
ComputeReturnAdjustmentBaseOffset(ASTContext &Context,
const CXXMethodDecl *DerivedMD,
const CXXMethodDecl *BaseMD) {
- const FunctionType *BaseFT = BaseMD->getType()->getAs<FunctionType>();
- const FunctionType *DerivedFT = DerivedMD->getType()->getAs<FunctionType>();
+ const auto *BaseFT = BaseMD->getType()->castAs<FunctionType>();
+ const auto *DerivedFT = DerivedMD->getType()->castAs<FunctionType>();
// Canonicalize the return types.
CanQualType CanDerivedReturnType =
diff --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp
index c51fd630e64b..0d1f713db8d3 100644
--- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -59,10 +59,12 @@ struct MatchKey {
DynTypedMatcher::MatcherIDType MatcherID;
ast_type_traits::DynTypedNode Node;
BoundNodesTreeBuilder BoundNodes;
+ ast_type_traits::TraversalKind Traversal = ast_type_traits::TK_AsIs;
bool operator<(const MatchKey &Other) const {
- return std::tie(MatcherID, Node, BoundNodes) <
- std::tie(Other.MatcherID, Other.Node, Other.BoundNodes);
+ return std::tie(MatcherID, Node, BoundNodes, Traversal) <
+ std::tie(Other.MatcherID, Other.Node, Other.BoundNodes,
+ Other.Traversal);
}
};
@@ -136,18 +138,32 @@ public:
ScopedIncrement ScopedDepth(&CurrentDepth);
return (DeclNode == nullptr) || traverse(*DeclNode);
}
- bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue = nullptr) {
- // If we need to keep track of the depth, we can't perform data recursion.
- if (CurrentDepth == 0 || (CurrentDepth <= MaxDepth && MaxDepth < INT_MAX))
- Queue = nullptr;
- ScopedIncrement ScopedDepth(&CurrentDepth);
+ Stmt *getStmtToTraverse(Stmt *StmtNode) {
Stmt *StmtToTraverse = StmtNode;
+ if (auto *ExprNode = dyn_cast_or_null<Expr>(StmtNode)) {
+ auto *LambdaNode = dyn_cast_or_null<LambdaExpr>(StmtNode);
+ if (LambdaNode && Finder->getASTContext().getTraversalKind() ==
+ ast_type_traits::TK_IgnoreUnlessSpelledInSource)
+ StmtToTraverse = LambdaNode;
+ else
+ StmtToTraverse = Finder->getASTContext().traverseIgnored(ExprNode);
+ }
if (Traversal ==
ast_type_traits::TraversalKind::TK_IgnoreImplicitCastsAndParentheses) {
if (Expr *ExprNode = dyn_cast_or_null<Expr>(StmtNode))
StmtToTraverse = ExprNode->IgnoreParenImpCasts();
}
+ return StmtToTraverse;
+ }
+
+ bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue = nullptr) {
+ // If we need to keep track of the depth, we can't perform data recursion.
+ if (CurrentDepth == 0 || (CurrentDepth <= MaxDepth && MaxDepth < INT_MAX))
+ Queue = nullptr;
+
+ ScopedIncrement ScopedDepth(&CurrentDepth);
+ Stmt *StmtToTraverse = getStmtToTraverse(StmtNode);
if (!StmtToTraverse)
return true;
if (!match(*StmtToTraverse))
@@ -199,6 +215,41 @@ public:
ScopedIncrement ScopedDepth(&CurrentDepth);
return traverse(*CtorInit);
}
+ bool TraverseLambdaExpr(LambdaExpr *Node) {
+ if (Finder->getASTContext().getTraversalKind() !=
+ ast_type_traits::TK_IgnoreUnlessSpelledInSource)
+ return VisitorBase::TraverseLambdaExpr(Node);
+ if (!Node)
+ return true;
+ ScopedIncrement ScopedDepth(&CurrentDepth);
+
+ for (unsigned I = 0, N = Node->capture_size(); I != N; ++I) {
+ const auto *C = Node->capture_begin() + I;
+ if (!C->isExplicit())
+ continue;
+ if (Node->isInitCapture(C) && !match(*C->getCapturedVar()))
+ return false;
+ if (!match(*Node->capture_init_begin()[I]))
+ return false;
+ }
+
+ if (const auto *TPL = Node->getTemplateParameterList()) {
+ for (const auto *TP : *TPL) {
+ if (!match(*TP))
+ return false;
+ }
+ }
+
+ for (const auto *P : Node->getCallOperator()->parameters()) {
+ if (!match(*P))
+ return false;
+ }
+
+ if (!match(*Node->getBody()))
+ return false;
+
+ return true;
+ }
bool shouldVisitTemplateInstantiations() const { return true; }
bool shouldVisitImplicitCode() const { return true; }
@@ -390,6 +441,7 @@ public:
// Matches children or descendants of 'Node' with 'BaseMatcher'.
bool memoizedMatchesRecursively(const ast_type_traits::DynTypedNode &Node,
+ ASTContext &Ctx,
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder, int MaxDepth,
ast_type_traits::TraversalKind Traversal,
@@ -404,6 +456,7 @@ public:
Key.Node = Node;
// Note that we key on the bindings *before* the match.
Key.BoundNodes = *Builder;
+ Key.Traversal = Ctx.getTraversalKind();
MemoizationMap::iterator I = ResultCache.find(Key);
if (I != ResultCache.end()) {
@@ -446,36 +499,36 @@ public:
// Implements ASTMatchFinder::matchesChildOf.
bool matchesChildOf(const ast_type_traits::DynTypedNode &Node,
- const DynTypedMatcher &Matcher,
+ ASTContext &Ctx, const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
ast_type_traits::TraversalKind Traversal,
BindKind Bind) override {
if (ResultCache.size() > MaxMemoizationEntries)
ResultCache.clear();
- return memoizedMatchesRecursively(Node, Matcher, Builder, 1, Traversal,
+ return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, 1, Traversal,
Bind);
}
// Implements ASTMatchFinder::matchesDescendantOf.
bool matchesDescendantOf(const ast_type_traits::DynTypedNode &Node,
- const DynTypedMatcher &Matcher,
+ ASTContext &Ctx, const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
BindKind Bind) override {
if (ResultCache.size() > MaxMemoizationEntries)
ResultCache.clear();
- return memoizedMatchesRecursively(Node, Matcher, Builder, INT_MAX,
+ return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, INT_MAX,
ast_type_traits::TraversalKind::TK_AsIs,
Bind);
}
// Implements ASTMatchFinder::matchesAncestorOf.
bool matchesAncestorOf(const ast_type_traits::DynTypedNode &Node,
- const DynTypedMatcher &Matcher,
+ ASTContext &Ctx, const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
AncestorMatchMode MatchMode) override {
// Reset the cache outside of the recursive call to make sure we
// don't invalidate any iterators.
if (ResultCache.size() > MaxMemoizationEntries)
ResultCache.clear();
- return memoizedMatchesAncestorOfRecursively(Node, Matcher, Builder,
+ return memoizedMatchesAncestorOfRecursively(Node, Ctx, Matcher, Builder,
MatchMode);
}
@@ -576,7 +629,7 @@ private:
if (EnableCheckProfiling)
Timer.setBucket(&TimeByBucket[MP.second->getID()]);
BoundNodesTreeBuilder Builder;
- if (MP.first.matchesNoKindCheck(DynNode, this, &Builder)) {
+ if (MP.first.matches(DynNode, this, &Builder)) {
MatchVisitor Visitor(ActiveASTContext, MP.second);
Builder.visitMatches(&Visitor);
}
@@ -640,16 +693,19 @@ private:
// allow simple memoization on the ancestors. Thus, we only memoize as long
// as there is a single parent.
bool memoizedMatchesAncestorOfRecursively(
- const ast_type_traits::DynTypedNode &Node, const DynTypedMatcher &Matcher,
- BoundNodesTreeBuilder *Builder, AncestorMatchMode MatchMode) {
+ const ast_type_traits::DynTypedNode &Node, ASTContext &Ctx,
+ const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder,
+ AncestorMatchMode MatchMode) {
// For AST-nodes that don't have an identity, we can't memoize.
if (!Builder->isComparable())
- return matchesAncestorOfRecursively(Node, Matcher, Builder, MatchMode);
+ return matchesAncestorOfRecursively(Node, Ctx, Matcher, Builder,
+ MatchMode);
MatchKey Key;
Key.MatcherID = Matcher.getID();
Key.Node = Node;
Key.BoundNodes = *Builder;
+ Key.Traversal = Ctx.getTraversalKind();
// Note that we cannot use insert and reuse the iterator, as recursive
// calls to match might invalidate the result cache iterators.
@@ -661,8 +717,8 @@ private:
MemoizedMatchResult Result;
Result.Nodes = *Builder;
- Result.ResultOfMatch =
- matchesAncestorOfRecursively(Node, Matcher, &Result.Nodes, MatchMode);
+ Result.ResultOfMatch = matchesAncestorOfRecursively(
+ Node, Ctx, Matcher, &Result.Nodes, MatchMode);
MemoizedMatchResult &CachedResult = ResultCache[Key];
CachedResult = std::move(Result);
@@ -672,6 +728,7 @@ private:
}
bool matchesAncestorOfRecursively(const ast_type_traits::DynTypedNode &Node,
+ ASTContext &Ctx,
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
AncestorMatchMode MatchMode) {
@@ -705,8 +762,8 @@ private:
return true;
}
if (MatchMode != ASTMatchFinder::AMM_ParentOnly) {
- return memoizedMatchesAncestorOfRecursively(Parent, Matcher, Builder,
- MatchMode);
+ return memoizedMatchesAncestorOfRecursively(Parent, Ctx, Matcher,
+ Builder, MatchMode);
// Once we get back from the recursive call, the result will be the
// same as the parent's result.
}
@@ -804,8 +861,6 @@ private:
/// kind (and derived kinds) so it is a waste to try every matcher on every
/// node.
/// We precalculate a list of matchers that pass the toplevel restrict check.
- /// This also allows us to skip the restrict check at matching time. See
- /// use \c matchesNoKindCheck() above.
llvm::DenseMap<ast_type_traits::ASTNodeKind, std::vector<unsigned short>>
MatcherFiltersMap;
@@ -904,8 +959,9 @@ bool MatchASTVisitor::objcClassIsDerivedFrom(
if (Base.matches(*ClassDecl, this, Builder))
return true;
+ // Not `return false` as a temporary workaround for PR43879.
if (Directly)
- return false;
+ break;
}
return false;
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index 4ee32fbe94b1..199a6d839e2e 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -68,6 +68,11 @@ bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
BoundNodesTreeBuilder *Builder,
ArrayRef<DynTypedMatcher> InnerMatchers);
+bool OptionallyVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder,
+ ArrayRef<DynTypedMatcher> InnerMatchers);
+
void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) {
if (Bindings.empty())
Bindings.push_back(BoundNodesMap());
@@ -112,6 +117,11 @@ public:
return Result;
}
+ llvm::Optional<ast_type_traits::TraversalKind>
+ TraversalKind() const override {
+ return InnerMatcher->TraversalKind();
+ }
+
private:
const std::string ID;
const IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher;
@@ -179,6 +189,11 @@ DynTypedMatcher DynTypedMatcher::constructVariadic(
SupportedKind, RestrictKind,
new VariadicMatcher<EachOfVariadicOperator>(std::move(InnerMatchers)));
+ case VO_Optionally:
+ return DynTypedMatcher(SupportedKind, RestrictKind,
+ new VariadicMatcher<OptionallyVariadicOperator>(
+ std::move(InnerMatchers)));
+
case VO_UnaryNot:
// FIXME: Implement the Not operator to take a single matcher instead of a
// vector.
@@ -189,6 +204,14 @@ DynTypedMatcher DynTypedMatcher::constructVariadic(
llvm_unreachable("Invalid Op value.");
}
+DynTypedMatcher DynTypedMatcher::constructRestrictedWrapper(
+ const DynTypedMatcher &InnerMatcher,
+ ast_type_traits::ASTNodeKind RestrictKind) {
+ DynTypedMatcher Copy = InnerMatcher;
+ Copy.RestrictKind = RestrictKind;
+ return Copy;
+}
+
DynTypedMatcher DynTypedMatcher::trueMatcher(
ast_type_traits::ASTNodeKind NodeKind) {
return DynTypedMatcher(NodeKind, NodeKind, &*TrueMatcherInstance);
@@ -211,8 +234,13 @@ DynTypedMatcher DynTypedMatcher::dynCastTo(
bool DynTypedMatcher::matches(const ast_type_traits::DynTypedNode &DynNode,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
- if (RestrictKind.isBaseOf(DynNode.getNodeKind()) &&
- Implementation->dynMatches(DynNode, Finder, Builder)) {
+ TraversalKindScope RAII(Finder->getASTContext(),
+ Implementation->TraversalKind());
+
+ auto N = Finder->getASTContext().traverseIgnored(DynNode);
+
+ if (RestrictKind.isBaseOf(N.getNodeKind()) &&
+ Implementation->dynMatches(N, Finder, Builder)) {
return true;
}
// Delete all bindings when a matcher does not match.
@@ -225,8 +253,13 @@ bool DynTypedMatcher::matches(const ast_type_traits::DynTypedNode &DynNode,
bool DynTypedMatcher::matchesNoKindCheck(
const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
- assert(RestrictKind.isBaseOf(DynNode.getNodeKind()));
- if (Implementation->dynMatches(DynNode, Finder, Builder)) {
+ TraversalKindScope raii(Finder->getASTContext(),
+ Implementation->TraversalKind());
+
+ auto N = Finder->getASTContext().traverseIgnored(DynNode);
+
+ assert(RestrictKind.isBaseOf(N.getNodeKind()));
+ if (Implementation->dynMatches(N, Finder, Builder)) {
return true;
}
// Delete all bindings when a matcher does not match.
@@ -324,6 +357,20 @@ bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
return false;
}
+bool OptionallyVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder,
+ ArrayRef<DynTypedMatcher> InnerMatchers) {
+ BoundNodesTreeBuilder Result;
+ for (const DynTypedMatcher &InnerMatcher : InnerMatchers) {
+ BoundNodesTreeBuilder BuilderInner(*Builder);
+ if (InnerMatcher.matches(DynNode, Finder, &BuilderInner))
+ Result.addMatch(BuilderInner);
+ }
+ *Builder = std::move(Result);
+ return true;
+}
+
inline static
std::vector<std::string> vectorFromRefs(ArrayRef<const StringRef *> NameRefs) {
std::vector<std::string> Names;
@@ -774,6 +821,9 @@ const internal::VariadicOperatorMatcherFunc<
const internal::VariadicOperatorMatcherFunc<
2, std::numeric_limits<unsigned>::max()>
allOf = {internal::DynTypedMatcher::VO_AllOf};
+const internal::VariadicOperatorMatcherFunc<
+ 1, std::numeric_limits<unsigned>::max()>
+ optionally = {internal::DynTypedMatcher::VO_Optionally};
const internal::VariadicFunction<internal::Matcher<NamedDecl>, StringRef,
internal::hasAnyNameFunc>
hasAnyName = {};
diff --git a/clang/lib/ASTMatchers/Dynamic/Parser.cpp b/clang/lib/ASTMatchers/Dynamic/Parser.cpp
index e3b00b46832c..a0037549ca61 100644
--- a/clang/lib/ASTMatchers/Dynamic/Parser.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Parser.cpp
@@ -38,6 +38,7 @@ struct Parser::TokenInfo {
/// Different possible tokens.
enum TokenKind {
TK_Eof,
+ TK_NewLine,
TK_OpenParen,
TK_CloseParen,
TK_Comma,
@@ -65,12 +66,12 @@ const char* const Parser::TokenInfo::ID_Bind = "bind";
/// Simple tokenizer for the parser.
class Parser::CodeTokenizer {
public:
- explicit CodeTokenizer(StringRef MatcherCode, Diagnostics *Error)
+ explicit CodeTokenizer(StringRef &MatcherCode, Diagnostics *Error)
: Code(MatcherCode), StartOfLine(MatcherCode), Error(Error) {
NextToken = getNextToken();
}
- CodeTokenizer(StringRef MatcherCode, Diagnostics *Error,
+ CodeTokenizer(StringRef &MatcherCode, Diagnostics *Error,
unsigned CodeCompletionOffset)
: Code(MatcherCode), StartOfLine(MatcherCode), Error(Error),
CodeCompletionLocation(MatcherCode.data() + CodeCompletionOffset) {
@@ -87,6 +88,19 @@ public:
return ThisToken;
}
+ TokenInfo SkipNewlines() {
+ while (NextToken.Kind == TokenInfo::TK_NewLine)
+ NextToken = getNextToken();
+ return NextToken;
+ }
+
+ TokenInfo consumeNextTokenIgnoreNewlines() {
+ SkipNewlines();
+ if (NextToken.Kind == TokenInfo::TK_Eof)
+ return NextToken;
+ return consumeNextToken();
+ }
+
TokenInfo::TokenKind nextTokenKind() const { return NextToken.Kind; }
private:
@@ -110,9 +124,8 @@ private:
switch (Code[0]) {
case '#':
- Result.Kind = TokenInfo::TK_Eof;
- Result.Text = "";
- return Result;
+ Code = Code.drop_until([](char c) { return c == '\n'; });
+ return getNextToken();
case ',':
Result.Kind = TokenInfo::TK_Comma;
Result.Text = Code.substr(0, 1);
@@ -123,6 +136,13 @@ private:
Result.Text = Code.substr(0, 1);
Code = Code.drop_front();
break;
+ case '\n':
+ ++Line;
+ StartOfLine = Code.drop_front();
+ Result.Kind = TokenInfo::TK_NewLine;
+ Result.Text = Code.substr(0, 1);
+ Code = Code.drop_front();
+ break;
case '(':
Result.Kind = TokenInfo::TK_OpenParen;
Result.Text = Code.substr(0, 1);
@@ -277,13 +297,10 @@ private:
/// Consume all leading whitespace from \c Code.
void consumeWhitespace() {
- while (!Code.empty() && isWhitespace(Code[0])) {
- if (Code[0] == '\n') {
- ++Line;
- StartOfLine = Code.drop_front();
- }
- Code = Code.drop_front();
- }
+ Code = Code.drop_while([](char c) {
+ // Don't trim newlines.
+ return StringRef(" \t\v\f\r").contains(c);
+ });
}
SourceLocation currentLocation() {
@@ -293,7 +310,7 @@ private:
return Location;
}
- StringRef Code;
+ StringRef &Code;
StringRef StartOfLine;
unsigned Line = 1;
Diagnostics *Error;
@@ -364,10 +381,19 @@ bool Parser::parseIdentifierPrefixImpl(VariantValue *Value) {
}
return false;
}
+
+ if (Tokenizer->nextTokenKind() == TokenInfo::TK_NewLine) {
+ Error->addError(Tokenizer->peekNextToken().Range,
+ Error->ET_ParserNoOpenParen)
+ << "NewLine";
+ return false;
+ }
+
// If the syntax is correct and the name is not a matcher either, report
// unknown named value.
if ((Tokenizer->nextTokenKind() == TokenInfo::TK_Comma ||
Tokenizer->nextTokenKind() == TokenInfo::TK_CloseParen ||
+ Tokenizer->nextTokenKind() == TokenInfo::TK_NewLine ||
Tokenizer->nextTokenKind() == TokenInfo::TK_Eof) &&
!S->lookupMatcherCtor(NameToken.Text)) {
Error->addError(NameToken.Range, Error->ET_RegistryValueNotFound)
@@ -377,6 +403,8 @@ bool Parser::parseIdentifierPrefixImpl(VariantValue *Value) {
// Otherwise, fallback to the matcher parser.
}
+ Tokenizer->SkipNewlines();
+
// Parse as a matcher expression.
return parseMatcherExpressionImpl(NameToken, Value);
}
@@ -392,8 +420,8 @@ bool Parser::parseBindID(std::string &BindID) {
}
const TokenInfo OpenToken = Tokenizer->consumeNextToken();
- const TokenInfo IDToken = Tokenizer->consumeNextToken();
- const TokenInfo CloseToken = Tokenizer->consumeNextToken();
+ const TokenInfo IDToken = Tokenizer->consumeNextTokenIgnoreNewlines();
+ const TokenInfo CloseToken = Tokenizer->consumeNextTokenIgnoreNewlines();
// TODO: We could use different error codes for each/some to be more
// explicit about the syntax error.
@@ -443,6 +471,8 @@ bool Parser::parseMatcherExpressionImpl(const TokenInfo &NameToken,
std::vector<ParserValue> Args;
TokenInfo EndToken;
+ Tokenizer->SkipNewlines();
+
{
ScopedContextEntry SCE(this, Ctor ? *Ctor : nullptr);
@@ -466,12 +496,14 @@ bool Parser::parseMatcherExpressionImpl(const TokenInfo &NameToken,
NameToken.Text, NameToken.Range,
Args.size() + 1);
ParserValue ArgValue;
+ Tokenizer->SkipNewlines();
ArgValue.Text = Tokenizer->peekNextToken().Text;
ArgValue.Range = Tokenizer->peekNextToken().Range;
if (!parseExpressionImpl(&ArgValue.Value)) {
return false;
}
+ Tokenizer->SkipNewlines();
Args.push_back(ArgValue);
SCE.nextArg();
}
@@ -531,7 +563,7 @@ std::vector<MatcherCompletion> Parser::getNamedValueCompletions(
}
void Parser::addExpressionCompletions() {
- const TokenInfo CompToken = Tokenizer->consumeNextToken();
+ const TokenInfo CompToken = Tokenizer->consumeNextTokenIgnoreNewlines();
assert(CompToken.Kind == TokenInfo::TK_CodeCompletion);
// We cannot complete code if there is an invalid element on the context
@@ -575,14 +607,15 @@ bool Parser::parseExpressionImpl(VariantValue *Value) {
case TokenInfo::TK_Error:
// This error was already reported by the tokenizer.
return false;
-
+ case TokenInfo::TK_NewLine:
case TokenInfo::TK_OpenParen:
case TokenInfo::TK_CloseParen:
case TokenInfo::TK_Comma:
case TokenInfo::TK_Period:
case TokenInfo::TK_InvalidChar:
const TokenInfo Token = Tokenizer->consumeNextToken();
- Error->addError(Token.Range, Error->ET_ParserInvalidToken) << Token.Text;
+ Error->addError(Token.Range, Error->ET_ParserInvalidToken)
+ << (Token.Kind == TokenInfo::TK_NewLine ? "NewLine" : Token.Text);
return false;
}
@@ -624,13 +657,14 @@ std::vector<MatcherCompletion> Parser::RegistrySema::getMatcherCompletions(
return Registry::getMatcherCompletions(AcceptedTypes);
}
-bool Parser::parseExpression(StringRef Code, Sema *S,
+bool Parser::parseExpression(StringRef &Code, Sema *S,
const NamedValueMap *NamedValues,
VariantValue *Value, Diagnostics *Error) {
CodeTokenizer Tokenizer(Code, Error);
if (!Parser(&Tokenizer, S, NamedValues, Error).parseExpressionImpl(Value))
return false;
- if (Tokenizer.peekNextToken().Kind != TokenInfo::TK_Eof) {
+ auto NT = Tokenizer.peekNextToken();
+ if (NT.Kind != TokenInfo::TK_Eof && NT.Kind != TokenInfo::TK_NewLine) {
Error->addError(Tokenizer.peekNextToken().Range,
Error->ET_ParserTrailingCode);
return false;
@@ -639,7 +673,7 @@ bool Parser::parseExpression(StringRef Code, Sema *S,
}
std::vector<MatcherCompletion>
-Parser::completeExpression(StringRef Code, unsigned CompletionOffset, Sema *S,
+Parser::completeExpression(StringRef &Code, unsigned CompletionOffset, Sema *S,
const NamedValueMap *NamedValues) {
Diagnostics Error;
CodeTokenizer Tokenizer(Code, &Error, CompletionOffset);
@@ -659,7 +693,7 @@ Parser::completeExpression(StringRef Code, unsigned CompletionOffset, Sema *S,
}
llvm::Optional<DynTypedMatcher>
-Parser::parseMatcherExpression(StringRef Code, Sema *S,
+Parser::parseMatcherExpression(StringRef &Code, Sema *S,
const NamedValueMap *NamedValues,
Diagnostics *Error) {
VariantValue Value;
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index 8c11e069cb05..1c0930c5983a 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -41,7 +41,8 @@ namespace {
using internal::MatcherDescriptor;
-using ConstructorMap = llvm::StringMap<std::unique_ptr<const MatcherDescriptor>>;
+using ConstructorMap =
+ llvm::StringMap<std::unique_ptr<const MatcherDescriptor>>;
class RegistryMaps {
public:
@@ -104,6 +105,7 @@ RegistryMaps::RegistryMaps() {
// equalsNode
REGISTER_OVERLOADED_2(callee);
+ REGISTER_OVERLOADED_2(hasAnyCapture);
REGISTER_OVERLOADED_2(hasPrefix);
REGISTER_OVERLOADED_2(hasType);
REGISTER_OVERLOADED_2(ignoringParens);
@@ -279,6 +281,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(hasIndex);
REGISTER_MATCHER(hasInit);
REGISTER_MATCHER(hasInitializer);
+ REGISTER_MATCHER(hasInitStatement);
REGISTER_MATCHER(hasKeywordSelector);
REGISTER_MATCHER(hasLHS);
REGISTER_MATCHER(hasLocalQualifiers);
@@ -454,6 +457,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(on);
REGISTER_MATCHER(onImplicitObjectArgument);
REGISTER_MATCHER(opaqueValueExpr);
+ REGISTER_MATCHER(optionally);
REGISTER_MATCHER(parameterCountIs);
REGISTER_MATCHER(parenExpr);
REGISTER_MATCHER(parenListExpr);
diff --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp
index 43f9e715b3de..1a7891550542 100644
--- a/clang/lib/Analysis/BodyFarm.cpp
+++ b/clang/lib/Analysis/BodyFarm.cpp
@@ -737,50 +737,69 @@ static const ObjCIvarDecl *findBackingIvar(const ObjCPropertyDecl *Prop) {
}
static Stmt *createObjCPropertyGetter(ASTContext &Ctx,
- const ObjCPropertyDecl *Prop) {
- // First, find the backing ivar.
- const ObjCIvarDecl *IVar = findBackingIvar(Prop);
- if (!IVar)
- return nullptr;
+ const ObjCMethodDecl *MD) {
+ // First, find the backing ivar.
+ const ObjCIvarDecl *IVar = nullptr;
- // Ignore weak variables, which have special behavior.
- if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak)
- return nullptr;
+ // Property accessor stubs sometimes do not correspond to any property decl
+ // in the current interface (but in a superclass). They still have a
+ // corresponding property impl decl in this case.
+ if (MD->isSynthesizedAccessorStub()) {
+ const ObjCInterfaceDecl *IntD = MD->getClassInterface();
+ const ObjCImplementationDecl *ImpD = IntD->getImplementation();
+ for (const auto *PI: ImpD->property_impls()) {
+ if (const ObjCPropertyDecl *P = PI->getPropertyDecl()) {
+ if (P->getGetterName() == MD->getSelector())
+ IVar = P->getPropertyIvarDecl();
+ }
+ }
+ }
- // Look to see if Sema has synthesized a body for us. This happens in
- // Objective-C++ because the return value may be a C++ class type with a
- // non-trivial copy constructor. We can only do this if we can find the
- // @synthesize for this property, though (or if we know it's been auto-
- // synthesized).
- const ObjCImplementationDecl *ImplDecl =
- IVar->getContainingInterface()->getImplementation();
- if (ImplDecl) {
- for (const auto *I : ImplDecl->property_impls()) {
- if (I->getPropertyDecl() != Prop)
- continue;
+ if (!IVar) {
+ const ObjCPropertyDecl *Prop = MD->findPropertyDecl();
+ IVar = findBackingIvar(Prop);
+ if (!IVar)
+ return nullptr;
+
+ // Ignore weak variables, which have special behavior.
+ if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak)
+ return nullptr;
- if (I->getGetterCXXConstructor()) {
- ASTMaker M(Ctx);
- return M.makeReturn(I->getGetterCXXConstructor());
+ // Look to see if Sema has synthesized a body for us. This happens in
+ // Objective-C++ because the return value may be a C++ class type with a
+ // non-trivial copy constructor. We can only do this if we can find the
+ // @synthesize for this property, though (or if we know it's been auto-
+ // synthesized).
+ const ObjCImplementationDecl *ImplDecl =
+ IVar->getContainingInterface()->getImplementation();
+ if (ImplDecl) {
+ for (const auto *I : ImplDecl->property_impls()) {
+ if (I->getPropertyDecl() != Prop)
+ continue;
+
+ if (I->getGetterCXXConstructor()) {
+ ASTMaker M(Ctx);
+ return M.makeReturn(I->getGetterCXXConstructor());
+ }
}
}
- }
- // Sanity check that the property is the same type as the ivar, or a
- // reference to it, and that it is either an object pointer or trivially
- // copyable.
- if (!Ctx.hasSameUnqualifiedType(IVar->getType(),
- Prop->getType().getNonReferenceType()))
- return nullptr;
- if (!IVar->getType()->isObjCLifetimeType() &&
- !IVar->getType().isTriviallyCopyableType(Ctx))
- return nullptr;
+ // Sanity check that the property is the same type as the ivar, or a
+ // reference to it, and that it is either an object pointer or trivially
+ // copyable.
+ if (!Ctx.hasSameUnqualifiedType(IVar->getType(),
+ Prop->getType().getNonReferenceType()))
+ return nullptr;
+ if (!IVar->getType()->isObjCLifetimeType() &&
+ !IVar->getType().isTriviallyCopyableType(Ctx))
+ return nullptr;
+ }
// Generate our body:
// return self->_ivar;
ASTMaker M(Ctx);
- const VarDecl *selfVar = Prop->getGetterMethodDecl()->getSelfDecl();
+ const VarDecl *selfVar = MD->getSelfDecl();
if (!selfVar)
return nullptr;
@@ -791,7 +810,7 @@ static Stmt *createObjCPropertyGetter(ASTContext &Ctx,
selfVar->getType()),
IVar);
- if (!Prop->getType()->isReferenceType())
+ if (!MD->getReturnType()->isReferenceType())
loadedIVar = M.makeLvalueToRvalue(loadedIVar, IVar->getType());
return M.makeReturn(loadedIVar);
@@ -814,10 +833,6 @@ Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) {
return Val.getValue();
Val = nullptr;
- const ObjCPropertyDecl *Prop = D->findPropertyDecl();
- if (!Prop)
- return nullptr;
-
// For now, we only synthesize getters.
// Synthesizing setters would cause false negatives in the
// RetainCountChecker because the method body would bind the parameter
@@ -830,7 +845,17 @@ Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) {
if (D->param_size() != 0)
return nullptr;
- Val = createObjCPropertyGetter(C, Prop);
+ // If the property was defined in an extension, search the extensions for
+ // overrides.
+ const ObjCInterfaceDecl *OID = D->getClassInterface();
+ if (dyn_cast<ObjCInterfaceDecl>(D->getParent()) != OID)
+ for (auto *Ext : OID->known_extensions()) {
+ auto *OMD = Ext->getInstanceMethod(D->getSelector());
+ if (OMD && !OMD->isImplicit())
+ return nullptr;
+ }
+
+ Val = createObjCPropertyGetter(C, D);
return Val.getValue();
}
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index a533a8d97b84..4c1ea8995f9f 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -542,6 +542,7 @@ public:
private:
// Visitors to walk an AST and construct the CFG.
+ CFGBlock *VisitInitListExpr(InitListExpr *ILE, AddStmtChoice asc);
CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc);
CFGBlock *VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc);
CFGBlock *VisitBreakStmt(BreakStmt *B);
@@ -1428,7 +1429,7 @@ void CFGBuilder::findConstructionContexts(
if (Layer->getItem().getKind() ==
ConstructionContextItem::ElidableConstructorKind) {
auto *MTE = cast<MaterializeTemporaryExpr>(Child);
- findConstructionContexts(withExtraLayer(MTE), MTE->GetTemporaryExpr());
+ findConstructionContexts(withExtraLayer(MTE), MTE->getSubExpr());
}
break;
}
@@ -1694,7 +1695,7 @@ static QualType getReferenceInitTemporaryType(const Expr *Init,
// Skip through the temporary-materialization expression.
if (const MaterializeTemporaryExpr *MTE
= dyn_cast<MaterializeTemporaryExpr>(Init)) {
- Init = MTE->GetTemporaryExpr();
+ Init = MTE->getSubExpr();
if (FoundMTE)
*FoundMTE = true;
continue;
@@ -2135,6 +2136,14 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc,
default:
return VisitStmt(S, asc);
+ case Stmt::ImplicitValueInitExprClass:
+ if (BuildOpts.OmitImplicitValueInitializers)
+ return Block;
+ return VisitStmt(S, asc);
+
+ case Stmt::InitListExprClass:
+ return VisitInitListExpr(cast<InitListExpr>(S), asc);
+
case Stmt::AddrLabelExprClass:
return VisitAddrLabelExpr(cast<AddrLabelExpr>(S), asc);
@@ -2341,15 +2350,37 @@ CFGBlock *CFGBuilder::VisitChildren(Stmt *S) {
// Visit the children in their reverse order so that they appear in
// left-to-right (natural) order in the CFG.
reverse_children RChildren(S);
- for (reverse_children::iterator I = RChildren.begin(), E = RChildren.end();
- I != E; ++I) {
- if (Stmt *Child = *I)
+ for (Stmt *Child : RChildren) {
+ if (Child)
if (CFGBlock *R = Visit(Child))
B = R;
}
return B;
}
+CFGBlock *CFGBuilder::VisitInitListExpr(InitListExpr *ILE, AddStmtChoice asc) {
+ if (asc.alwaysAdd(*this, ILE)) {
+ autoCreateBlock();
+ appendStmt(Block, ILE);
+ }
+ CFGBlock *B = Block;
+
+ reverse_children RChildren(ILE);
+ for (Stmt *Child : RChildren) {
+ if (!Child)
+ continue;
+ if (CFGBlock *R = Visit(Child))
+ B = R;
+ if (BuildOpts.AddCXXDefaultInitExprInAggregates) {
+ if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(Child))
+ if (Stmt *Child = DIE->getExpr())
+ if (CFGBlock *R = Visit(Child))
+ B = R;
+ }
+ }
+ return B;
+}
+
CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A,
AddStmtChoice asc) {
AddressTakenLabels.insert(A->getLabel());
@@ -3462,7 +3493,7 @@ CFGBuilder::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE,
AddStmtChoice asc) {
findConstructionContexts(
ConstructionContextLayer::create(cfg->getBumpVectorContext(), MTE),
- MTE->getTemporary());
+ MTE->getSubExpr());
return VisitStmt(MTE, asc);
}
@@ -4649,7 +4680,7 @@ tryAgain:
// Find the expression whose lifetime needs to be extended.
E = const_cast<Expr *>(
cast<MaterializeTemporaryExpr>(E)
- ->GetTemporaryExpr()
+ ->getSubExpr()
->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments));
// Visit the skipped comma operator left-hand sides for other temporaries.
for (const Expr *CommaLHS : CommaLHSs) {
@@ -5879,12 +5910,16 @@ const Expr *CFGBlock::getLastCondition() const {
if (succ_size() < 2)
return nullptr;
+ // FIXME: Is there a better condition expression we can return in this case?
+ if (size() == 0)
+ return nullptr;
+
auto StmtElem = rbegin()->getAs<CFGStmt>();
if (!StmtElem)
return nullptr;
const Stmt *Cond = StmtElem->getStmt();
- if (isa<ObjCForCollectionStmt>(Cond))
+ if (isa<ObjCForCollectionStmt>(Cond) || isa<DeclStmt>(Cond))
return nullptr;
// Only ObjCForCollectionStmt is known not to be a non-Expr terminator, hence
diff --git a/clang/lib/Analysis/CloneDetection.cpp b/clang/lib/Analysis/CloneDetection.cpp
index 30d104165cc5..5fb5840ce293 100644
--- a/clang/lib/Analysis/CloneDetection.cpp
+++ b/clang/lib/Analysis/CloneDetection.cpp
@@ -11,7 +11,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/CloneDetection.h"
-
+#include "clang/AST/Attr.h"
#include "clang/AST/DataCollection.h"
#include "clang/AST/DeclTemplate.h"
#include "llvm/Support/MD5.h"
diff --git a/clang/lib/Analysis/Consumed.cpp b/clang/lib/Analysis/Consumed.cpp
index cde753e8ec57..9560248b173f 100644
--- a/clang/lib/Analysis/Consumed.cpp
+++ b/clang/lib/Analysis/Consumed.cpp
@@ -847,7 +847,7 @@ void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
const MaterializeTemporaryExpr *Temp) {
- forwardInfo(Temp->GetTemporaryExpr(), Temp);
+ forwardInfo(Temp->getSubExpr(), Temp);
}
void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
diff --git a/clang/lib/Analysis/ReachableCode.cpp b/clang/lib/Analysis/ReachableCode.cpp
index 1dab8e309f59..369879ad65f5 100644
--- a/clang/lib/Analysis/ReachableCode.cpp
+++ b/clang/lib/Analysis/ReachableCode.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/StmtCXX.h"
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
+#include "clang/Basic/Builtins.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/BitVector.h"
diff --git a/clang/lib/Analysis/ThreadSafety.cpp b/clang/lib/Analysis/ThreadSafety.cpp
index c60954374ce3..48f4106b6bae 100644
--- a/clang/lib/Analysis/ThreadSafety.cpp
+++ b/clang/lib/Analysis/ThreadSafety.cpp
@@ -2142,6 +2142,9 @@ void BuildLockset::VisitDeclStmt(const DeclStmt *S) {
// handle constructors that involve temporaries
if (auto *EWC = dyn_cast<ExprWithCleanups>(E))
E = EWC->getSubExpr();
+ if (auto *ICE = dyn_cast<ImplicitCastExpr>(E))
+ if (ICE->getCastKind() == CK_NoOp)
+ E = ICE->getSubExpr();
if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E))
E = BTE->getSubExpr();
diff --git a/clang/lib/Analysis/ThreadSafetyCommon.cpp b/clang/lib/Analysis/ThreadSafetyCommon.cpp
index 373dfc77fa9b..1b8c55e56d47 100644
--- a/clang/lib/Analysis/ThreadSafetyCommon.cpp
+++ b/clang/lib/Analysis/ThreadSafetyCommon.cpp
@@ -244,8 +244,7 @@ til::SExpr *SExprBuilder::translate(const Stmt *S, CallingContext *Ctx) {
case Stmt::CXXBindTemporaryExprClass:
return translate(cast<CXXBindTemporaryExpr>(S)->getSubExpr(), Ctx);
case Stmt::MaterializeTemporaryExprClass:
- return translate(cast<MaterializeTemporaryExpr>(S)->GetTemporaryExpr(),
- Ctx);
+ return translate(cast<MaterializeTemporaryExpr>(S)->getSubExpr(), Ctx);
// Collect all literals
case Stmt::CharacterLiteralClass:
diff --git a/clang/lib/Basic/Builtins.cpp b/clang/lib/Basic/Builtins.cpp
index d23c280d4758..0cd89df41b67 100644
--- a/clang/lib/Basic/Builtins.cpp
+++ b/clang/lib/Basic/Builtins.cpp
@@ -47,8 +47,7 @@ void Builtin::Context::InitializeTarget(const TargetInfo &Target,
AuxTSRecords = AuxTarget->getTargetBuiltins();
}
-bool Builtin::Context::isBuiltinFunc(const char *Name) {
- StringRef FuncName(Name);
+bool Builtin::Context::isBuiltinFunc(llvm::StringRef FuncName) {
for (unsigned i = Builtin::NotBuiltin + 1; i != Builtin::FirstTSBuiltin; ++i)
if (FuncName.equals(BuiltinInfo[i].Name))
return strchr(BuiltinInfo[i].Attributes, 'f') != nullptr;
diff --git a/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp
index c82f74413ec1..f258b37f2fa6 100644
--- a/clang/lib/Basic/Diagnostic.cpp
+++ b/clang/lib/Basic/Diagnostic.cpp
@@ -145,19 +145,20 @@ void DiagnosticsEngine::Reset() {
}
void DiagnosticsEngine::SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1,
- StringRef Arg2) {
+ StringRef Arg2, StringRef Arg3) {
if (DelayedDiagID)
return;
DelayedDiagID = DiagID;
DelayedDiagArg1 = Arg1.str();
DelayedDiagArg2 = Arg2.str();
+ DelayedDiagArg3 = Arg3.str();
}
void DiagnosticsEngine::ReportDelayed() {
unsigned ID = DelayedDiagID;
DelayedDiagID = 0;
- Report(ID) << DelayedDiagArg1 << DelayedDiagArg2;
+ Report(ID) << DelayedDiagArg1 << DelayedDiagArg2 << DelayedDiagArg3;
}
void DiagnosticsEngine::DiagStateMap::appendFirst(DiagState *State) {
@@ -981,6 +982,7 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
llvm::raw_svector_ostream(OutStr) << '\'' << II->getName() << '\'';
break;
}
+ case DiagnosticsEngine::ak_addrspace:
case DiagnosticsEngine::ak_qual:
case DiagnosticsEngine::ak_qualtype:
case DiagnosticsEngine::ak_declarationname:
diff --git a/clang/lib/Basic/FileManager.cpp b/clang/lib/Basic/FileManager.cpp
index 88a7a1250837..079a4bbfc82f 100644
--- a/clang/lib/Basic/FileManager.cpp
+++ b/clang/lib/Basic/FileManager.cpp
@@ -221,12 +221,12 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) {
// We've not seen this before. Fill it in.
++NumFileCacheMisses;
- auto &NamedFileEnt = *SeenFileInsertResult.first;
- assert(!NamedFileEnt.second && "should be newly-created");
+ auto *NamedFileEnt = &*SeenFileInsertResult.first;
+ assert(!NamedFileEnt->second && "should be newly-created");
// Get the null-terminated file name as stored as the key of the
// SeenFileEntries map.
- StringRef InterndFileName = NamedFileEnt.first();
+ StringRef InterndFileName = NamedFileEnt->first();
// Look up the directory for the file. When looking up something like
// sys/foo.h we'll discover all of the search directories that have a 'sys'
@@ -236,7 +236,7 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) {
auto DirInfoOrErr = getDirectoryFromFile(*this, Filename, CacheFailure);
if (!DirInfoOrErr) { // Directory doesn't exist, file can't exist.
if (CacheFailure)
- NamedFileEnt.second = DirInfoOrErr.getError();
+ NamedFileEnt->second = DirInfoOrErr.getError();
else
SeenFileEntries.erase(Filename);
@@ -255,7 +255,7 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) {
if (statError) {
// There's no real file at the given path.
if (CacheFailure)
- NamedFileEnt.second = statError;
+ NamedFileEnt->second = statError;
else
SeenFileEntries.erase(Filename);
@@ -268,7 +268,7 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) {
// This occurs when one dir is symlinked to another, for example.
FileEntry &UFE = UniqueRealFiles[Status.getUniqueID()];
- NamedFileEnt.second = &UFE;
+ NamedFileEnt->second = &UFE;
// If the name returned by getStatValue is different than Filename, re-intern
// the name.
@@ -281,7 +281,11 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) {
// In addition to re-interning the name, construct a redirecting seen file
// entry, that will point to the name the filesystem actually wants to use.
StringRef *Redirect = new (CanonicalNameStorage) StringRef(InterndFileName);
- NamedFileEnt.second = Redirect;
+ auto SeenFileInsertResultIt = SeenFileEntries.find(Filename);
+ assert(SeenFileInsertResultIt != SeenFileEntries.end() &&
+ "unexpected SeenFileEntries cache miss");
+ SeenFileInsertResultIt->second = Redirect;
+ NamedFileEnt = &*SeenFileInsertResultIt;
}
if (UFE.isValid()) { // Already have an entry with this inode, return it.
@@ -544,10 +548,9 @@ void FileManager::GetUniqueIDMapping(
}
StringRef FileManager::getCanonicalName(const DirectoryEntry *Dir) {
- // FIXME: use llvm::sys::fs::canonical() when it gets implemented
- llvm::DenseMap<const DirectoryEntry *, llvm::StringRef>::iterator Known
- = CanonicalDirNames.find(Dir);
- if (Known != CanonicalDirNames.end())
+ llvm::DenseMap<const void *, llvm::StringRef>::iterator Known
+ = CanonicalNames.find(Dir);
+ if (Known != CanonicalNames.end())
return Known->second;
StringRef CanonicalName(Dir->getName());
@@ -556,7 +559,23 @@ StringRef FileManager::getCanonicalName(const DirectoryEntry *Dir) {
if (!FS->getRealPath(Dir->getName(), CanonicalNameBuf))
CanonicalName = StringRef(CanonicalNameBuf).copy(CanonicalNameStorage);
- CanonicalDirNames.insert({Dir, CanonicalName});
+ CanonicalNames.insert({Dir, CanonicalName});
+ return CanonicalName;
+}
+
+StringRef FileManager::getCanonicalName(const FileEntry *File) {
+ llvm::DenseMap<const void *, llvm::StringRef>::iterator Known
+ = CanonicalNames.find(File);
+ if (Known != CanonicalNames.end())
+ return Known->second;
+
+ StringRef CanonicalName(File->getName());
+
+ SmallString<4096> CanonicalNameBuf;
+ if (!FS->getRealPath(File->getName(), CanonicalNameBuf))
+ CanonicalName = StringRef(CanonicalNameBuf).copy(CanonicalNameStorage);
+
+ CanonicalNames.insert({File, CanonicalName});
return CanonicalName;
}
diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp
index a52ed8caa121..414ebb52c0c7 100644
--- a/clang/lib/Basic/OpenMPKinds.cpp
+++ b/clang/lib/Basic/OpenMPKinds.cpp
@@ -18,30 +18,49 @@
#include <cassert>
using namespace clang;
+using namespace llvm::omp;
-OpenMPDirectiveKind clang::getOpenMPDirectiveKind(StringRef Str) {
- return llvm::StringSwitch<OpenMPDirectiveKind>(Str)
-#define OPENMP_DIRECTIVE(Name) .Case(#Name, OMPD_##Name)
-#define OPENMP_DIRECTIVE_EXT(Name, Str) .Case(Str, OMPD_##Name)
+OpenMPContextSelectorSetKind
+clang::getOpenMPContextSelectorSet(llvm::StringRef Str) {
+ return llvm::StringSwitch<OpenMPContextSelectorSetKind>(Str)
+#define OPENMP_CONTEXT_SELECTOR_SET(Name) .Case(#Name, OMP_CTX_SET_##Name)
#include "clang/Basic/OpenMPKinds.def"
- .Default(OMPD_unknown);
+ .Default(OMP_CTX_SET_unknown);
}
-const char *clang::getOpenMPDirectiveName(OpenMPDirectiveKind Kind) {
- assert(Kind <= OMPD_unknown);
+llvm::StringRef
+clang::getOpenMPContextSelectorSetName(OpenMPContextSelectorSetKind Kind) {
switch (Kind) {
- case OMPD_unknown:
+ case OMP_CTX_SET_unknown:
+ return "unknown";
+#define OPENMP_CONTEXT_SELECTOR_SET(Name) \
+ case OMP_CTX_SET_##Name: \
+ return #Name;
+#include "clang/Basic/OpenMPKinds.def"
+ break;
+ }
+ llvm_unreachable("Invalid OpenMP context selector set kind");
+}
+
+OpenMPContextSelectorKind clang::getOpenMPContextSelector(llvm::StringRef Str) {
+ return llvm::StringSwitch<OpenMPContextSelectorKind>(Str)
+#define OPENMP_CONTEXT_SELECTOR(Name) .Case(#Name, OMP_CTX_##Name)
+#include "clang/Basic/OpenMPKinds.def"
+ .Default(OMP_CTX_unknown);
+}
+
+llvm::StringRef
+clang::getOpenMPContextSelectorName(OpenMPContextSelectorKind Kind) {
+ switch (Kind) {
+ case OMP_CTX_unknown:
return "unknown";
-#define OPENMP_DIRECTIVE(Name) \
- case OMPD_##Name: \
+#define OPENMP_CONTEXT_SELECTOR(Name) \
+ case OMP_CTX_##Name: \
return #Name;
-#define OPENMP_DIRECTIVE_EXT(Name, Str) \
- case OMPD_##Name: \
- return Str;
#include "clang/Basic/OpenMPKinds.def"
break;
}
- llvm_unreachable("Invalid OpenMP directive kind");
+ llvm_unreachable("Invalid OpenMP context selector kind");
}
OpenMPClauseKind clang::getOpenMPClauseKind(StringRef Str) {
@@ -90,10 +109,10 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind,
#include "clang/Basic/OpenMPKinds.def"
.Default(OMPC_DEFAULT_unknown);
case OMPC_proc_bind:
- return llvm::StringSwitch<OpenMPProcBindClauseKind>(Str)
-#define OPENMP_PROC_BIND_KIND(Name) .Case(#Name, OMPC_PROC_BIND_##Name)
-#include "clang/Basic/OpenMPKinds.def"
- .Default(OMPC_PROC_BIND_unknown);
+ return llvm::StringSwitch<unsigned>(Str)
+#define OMP_PROC_BIND_KIND(Enum, Name, Value) .Case(Name, Value)
+#include "llvm/Frontend/OpenMP/OMPKinds.def"
+ .Default(unsigned(llvm::omp::OMP_PROC_BIND_unknown));
case OMPC_schedule:
return llvm::StringSwitch<unsigned>(Str)
#define OPENMP_SCHEDULE_KIND(Name) \
@@ -156,6 +175,11 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind,
#define OPENMP_DEVICE_TYPE_KIND(Name) .Case(#Name, OMPC_DEVICE_TYPE_##Name)
#include "clang/Basic/OpenMPKinds.def"
.Default(OMPC_DEVICE_TYPE_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_unknown:
case OMPC_threadprivate:
case OMPC_if:
@@ -168,7 +192,6 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind,
case OMPC_collapse:
case OMPC_private:
case OMPC_firstprivate:
- case OMPC_lastprivate:
case OMPC_shared:
case OMPC_reduction:
case OMPC_task_reduction:
@@ -204,6 +227,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind,
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_match:
+ case OMPC_nontemporal:
break;
}
llvm_unreachable("Invalid OpenMP simple clause kind");
@@ -224,12 +248,10 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
llvm_unreachable("Invalid OpenMP 'default' clause type");
case OMPC_proc_bind:
switch (Type) {
- case OMPC_PROC_BIND_unknown:
- return "unknown";
-#define OPENMP_PROC_BIND_KIND(Name) \
- case OMPC_PROC_BIND_##Name: \
- return #Name;
-#include "clang/Basic/OpenMPKinds.def"
+#define OMP_PROC_BIND_KIND(Enum, Name, Value) \
+ case Value: \
+ return Name;
+#include "llvm/Frontend/OpenMP/OMPKinds.def"
}
llvm_unreachable("Invalid OpenMP 'proc_bind' clause type");
case OMPC_schedule:
@@ -350,6 +372,16 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
#include "clang/Basic/OpenMPKinds.def"
}
llvm_unreachable("Invalid OpenMP 'device_type' clause type");
+ case OMPC_lastprivate:
+ switch (Type) {
+ case OMPC_LASTPRIVATE_unknown:
+ return "unknown";
+#define OPENMP_LASTPRIVATE_KIND(Name) \
+ case OMPC_LASTPRIVATE_##Name: \
+ return #Name;
+#include "clang/Basic/OpenMPKinds.def"
+ }
+ llvm_unreachable("Invalid OpenMP 'lastprivate' clause type");
case OMPC_unknown:
case OMPC_threadprivate:
case OMPC_if:
@@ -362,7 +394,6 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
case OMPC_collapse:
case OMPC_private:
case OMPC_firstprivate:
- case OMPC_lastprivate:
case OMPC_shared:
case OMPC_reduction:
case OMPC_task_reduction:
@@ -398,15 +429,20 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_match:
+ case OMPC_nontemporal:
break;
}
llvm_unreachable("Invalid OpenMP simple clause kind");
}
bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
- OpenMPClauseKind CKind) {
- assert(DKind <= OMPD_unknown);
+ OpenMPClauseKind CKind,
+ unsigned OpenMPVersion) {
+ assert(unsigned(DKind) <= unsigned(OMPD_unknown));
assert(CKind <= OMPC_unknown);
+ // Nontemporal clause is not supported in OpenMP < 5.0.
+ if (OpenMPVersion < 50 && CKind == OMPC_nontemporal)
+ return false;
switch (DKind) {
case OMPD_parallel:
switch (CKind) {
@@ -419,6 +455,8 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
}
break;
case OMPD_simd:
+ if (OpenMPVersion < 50 && CKind == OMPC_if)
+ return false;
switch (CKind) {
#define OPENMP_SIMD_CLAUSE(Name) \
case OMPC_##Name: \
@@ -439,6 +477,8 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
}
break;
case OMPD_for_simd:
+ if (OpenMPVersion < 50 && CKind == OMPC_if)
+ return false;
switch (CKind) {
#define OPENMP_FOR_SIMD_CLAUSE(Name) \
case OMPC_##Name: \
@@ -488,6 +528,16 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
break;
}
break;
+ case OMPD_parallel_master:
+ switch (CKind) {
+#define OPENMP_PARALLEL_MASTER_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
case OMPD_parallel_sections:
switch (CKind) {
#define OPENMP_PARALLEL_SECTIONS_CLAUSE(Name) \
@@ -681,6 +731,16 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
break;
}
break;
+ case OMPD_parallel_master_taskloop_simd:
+ switch (CKind) {
+#define OPENMP_PARALLEL_MASTER_TASKLOOP_SIMD_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
case OMPD_critical:
switch (CKind) {
#define OPENMP_CRITICAL_CLAUSE(Name) \
@@ -722,6 +782,8 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
}
break;
case OMPD_distribute_simd:
+ if (OpenMPVersion < 50 && CKind == OMPC_if)
+ return false;
switch (CKind) {
#define OPENMP_DISTRIBUTE_SIMD_CLAUSE(Name) \
case OMPC_##Name: \
@@ -762,6 +824,8 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
}
break;
case OMPD_teams_distribute_simd:
+ if (OpenMPVersion < 50 && CKind == OMPC_if)
+ return false;
switch (CKind) {
#define OPENMP_TEAMS_DISTRIBUTE_SIMD_CLAUSE(Name) \
case OMPC_##Name: \
@@ -903,8 +967,9 @@ bool clang::isOpenMPLoopDirective(OpenMPDirectiveKind DKind) {
DKind == OMPD_parallel_for || DKind == OMPD_parallel_for_simd ||
DKind == OMPD_taskloop || DKind == OMPD_taskloop_simd ||
DKind == OMPD_master_taskloop || DKind == OMPD_master_taskloop_simd ||
- DKind == OMPD_parallel_master_taskloop || DKind == OMPD_distribute ||
- DKind == OMPD_target_parallel_for ||
+ DKind == OMPD_parallel_master_taskloop ||
+ DKind == OMPD_parallel_master_taskloop_simd ||
+ DKind == OMPD_distribute || DKind == OMPD_target_parallel_for ||
DKind == OMPD_distribute_parallel_for ||
DKind == OMPD_distribute_parallel_for_simd ||
DKind == OMPD_distribute_simd ||
@@ -937,7 +1002,8 @@ bool clang::isOpenMPWorksharingDirective(OpenMPDirectiveKind DKind) {
bool clang::isOpenMPTaskLoopDirective(OpenMPDirectiveKind DKind) {
return DKind == OMPD_taskloop || DKind == OMPD_taskloop_simd ||
DKind == OMPD_master_taskloop || DKind == OMPD_master_taskloop_simd ||
- DKind == OMPD_parallel_master_taskloop;
+ DKind == OMPD_parallel_master_taskloop ||
+ DKind == OMPD_parallel_master_taskloop_simd;
}
bool clang::isOpenMPParallelDirective(OpenMPDirectiveKind DKind) {
@@ -951,7 +1017,9 @@ bool clang::isOpenMPParallelDirective(OpenMPDirectiveKind DKind) {
DKind == OMPD_teams_distribute_parallel_for_simd ||
DKind == OMPD_target_teams_distribute_parallel_for ||
DKind == OMPD_target_teams_distribute_parallel_for_simd ||
- DKind == OMPD_parallel_master_taskloop;
+ DKind == OMPD_parallel_master ||
+ DKind == OMPD_parallel_master_taskloop ||
+ DKind == OMPD_parallel_master_taskloop_simd;
}
bool clang::isOpenMPTargetExecutionDirective(OpenMPDirectiveKind DKind) {
@@ -988,6 +1056,7 @@ bool clang::isOpenMPSimdDirective(OpenMPDirectiveKind DKind) {
return DKind == OMPD_simd || DKind == OMPD_for_simd ||
DKind == OMPD_parallel_for_simd || DKind == OMPD_taskloop_simd ||
DKind == OMPD_master_taskloop_simd ||
+ DKind == OMPD_parallel_master_taskloop_simd ||
DKind == OMPD_distribute_parallel_for_simd ||
DKind == OMPD_distribute_simd || DKind == OMPD_target_simd ||
DKind == OMPD_teams_distribute_simd ||
@@ -1047,6 +1116,7 @@ void clang::getOpenMPCaptureRegions(
case OMPD_parallel:
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
+ case OMPD_parallel_master:
case OMPD_parallel_sections:
case OMPD_distribute_parallel_for:
case OMPD_distribute_parallel_for_simd:
@@ -1094,6 +1164,7 @@ void clang::getOpenMPCaptureRegions(
CaptureRegions.push_back(OMPD_taskloop);
break;
case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_master_taskloop_simd:
CaptureRegions.push_back(OMPD_parallel);
CaptureRegions.push_back(OMPD_taskloop);
break;
diff --git a/clang/lib/Basic/SanitizerBlacklist.cpp b/clang/lib/Basic/SanitizerBlacklist.cpp
index aec35c7d9864..4f71349350fd 100644
--- a/clang/lib/Basic/SanitizerBlacklist.cpp
+++ b/clang/lib/Basic/SanitizerBlacklist.cpp
@@ -16,7 +16,9 @@ using namespace clang;
SanitizerBlacklist::SanitizerBlacklist(
const std::vector<std::string> &BlacklistPaths, SourceManager &SM)
- : SSCL(SanitizerSpecialCaseList::createOrDie(BlacklistPaths)), SM(SM) {}
+ : SSCL(SanitizerSpecialCaseList::createOrDie(
+ BlacklistPaths, SM.getFileManager().getVirtualFileSystem())),
+ SM(SM) {}
bool SanitizerBlacklist::isBlacklistedGlobal(SanitizerMask Mask,
StringRef GlobalName,
diff --git a/clang/lib/Basic/SanitizerSpecialCaseList.cpp b/clang/lib/Basic/SanitizerSpecialCaseList.cpp
index 5fb0f9660b15..5bf8d39ffd95 100644
--- a/clang/lib/Basic/SanitizerSpecialCaseList.cpp
+++ b/clang/lib/Basic/SanitizerSpecialCaseList.cpp
@@ -16,10 +16,11 @@ using namespace clang;
std::unique_ptr<SanitizerSpecialCaseList>
SanitizerSpecialCaseList::create(const std::vector<std::string> &Paths,
+ llvm::vfs::FileSystem &VFS,
std::string &Error) {
std::unique_ptr<clang::SanitizerSpecialCaseList> SSCL(
new SanitizerSpecialCaseList());
- if (SSCL->createInternal(Paths, Error)) {
+ if (SSCL->createInternal(Paths, VFS, Error)) {
SSCL->createSanitizerSections();
return SSCL;
}
@@ -27,9 +28,10 @@ SanitizerSpecialCaseList::create(const std::vector<std::string> &Paths,
}
std::unique_ptr<SanitizerSpecialCaseList>
-SanitizerSpecialCaseList::createOrDie(const std::vector<std::string> &Paths) {
+SanitizerSpecialCaseList::createOrDie(const std::vector<std::string> &Paths,
+ llvm::vfs::FileSystem &VFS) {
std::string Error;
- if (auto SSCL = create(Paths, Error))
+ if (auto SSCL = create(Paths, VFS, Error))
return SSCL;
llvm::report_fatal_error(Error);
}
diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp
index 58b95289eaf2..73f2ae96d4a3 100644
--- a/clang/lib/Basic/SourceManager.cpp
+++ b/clang/lib/Basic/SourceManager.cpp
@@ -95,6 +95,29 @@ void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B, bool DoNotFree) {
Buffer.setInt((B && DoNotFree) ? DoNotFreeFlag : 0);
}
+const char *ContentCache::getInvalidBOM(StringRef BufStr) {
+ // If the buffer is valid, check to see if it has a UTF Byte Order Mark
+ // (BOM). We only support UTF-8 with and without a BOM right now. See
+ // http://en.wikipedia.org/wiki/Byte_order_mark for more information.
+ const char *InvalidBOM =
+ llvm::StringSwitch<const char *>(BufStr)
+ .StartsWith(llvm::StringLiteral::withInnerNUL("\x00\x00\xFE\xFF"),
+ "UTF-32 (BE)")
+ .StartsWith(llvm::StringLiteral::withInnerNUL("\xFF\xFE\x00\x00"),
+ "UTF-32 (LE)")
+ .StartsWith("\xFE\xFF", "UTF-16 (BE)")
+ .StartsWith("\xFF\xFE", "UTF-16 (LE)")
+ .StartsWith("\x2B\x2F\x76", "UTF-7")
+ .StartsWith("\xF7\x64\x4C", "UTF-1")
+ .StartsWith("\xDD\x73\x66\x73", "UTF-EBCDIC")
+ .StartsWith("\x0E\xFE\xFF", "SCSU")
+ .StartsWith("\xFB\xEE\x28", "BOCU-1")
+ .StartsWith("\x84\x31\x95\x33", "GB-18030")
+ .Default(nullptr);
+
+ return InvalidBOM;
+}
+
const llvm::MemoryBuffer *ContentCache::getBuffer(DiagnosticsEngine &Diag,
FileManager &FM,
SourceLocation Loc,
@@ -190,20 +213,7 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(DiagnosticsEngine &Diag,
// (BOM). We only support UTF-8 with and without a BOM right now. See
// http://en.wikipedia.org/wiki/Byte_order_mark for more information.
StringRef BufStr = Buffer.getPointer()->getBuffer();
- const char *InvalidBOM = llvm::StringSwitch<const char *>(BufStr)
- .StartsWith(llvm::StringLiteral::withInnerNUL("\x00\x00\xFE\xFF"),
- "UTF-32 (BE)")
- .StartsWith(llvm::StringLiteral::withInnerNUL("\xFF\xFE\x00\x00"),
- "UTF-32 (LE)")
- .StartsWith("\xFE\xFF", "UTF-16 (BE)")
- .StartsWith("\xFF\xFE", "UTF-16 (LE)")
- .StartsWith("\x2B\x2F\x76", "UTF-7")
- .StartsWith("\xF7\x64\x4C", "UTF-1")
- .StartsWith("\xDD\x73\x66\x73", "UTF-EBCDIC")
- .StartsWith("\x0E\xFE\xFF", "SCSU")
- .StartsWith("\xFB\xEE\x28", "BOCU-1")
- .StartsWith("\x84\x31\x95\x33", "GB-18030")
- .Default(nullptr);
+ const char *InvalidBOM = getInvalidBOM(BufStr);
if (InvalidBOM) {
Diag.Report(Loc, diag::err_unsupported_bom)
@@ -1240,23 +1250,18 @@ static void ComputeLineNumbers(DiagnosticsEngine &Diag, ContentCache *FI,
const unsigned char *Buf = (const unsigned char *)Buffer->getBufferStart();
const unsigned char *End = (const unsigned char *)Buffer->getBufferEnd();
+ const std::size_t BufLen = End - Buf;
unsigned I = 0;
- while (true) {
- // Skip over the contents of the line.
- while (Buf[I] != '\n' && Buf[I] != '\r' && Buf[I] != '\0')
- ++I;
-
- if (Buf[I] == '\n' || Buf[I] == '\r') {
+ while (I < BufLen) {
+ if (Buf[I] == '\n') {
+ LineOffsets.push_back(I + 1);
+ } else if (Buf[I] == '\r') {
// If this is \r\n, skip both characters.
- if (Buf[I] == '\r' && Buf[I+1] == '\n')
+ if (I + 1 < BufLen && Buf[I + 1] == '\n')
++I;
- ++I;
- LineOffsets.push_back(I);
- } else {
- // Otherwise, this is a NUL. If end of file, exit.
- if (Buf+I == End) break;
- ++I;
+ LineOffsets.push_back(I + 1);
}
+ ++I;
}
// Copy the offsets into the FileInfo structure.
diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp
index 63a64ed2931a..c063f8ca4472 100644
--- a/clang/lib/Basic/Targets.cpp
+++ b/clang/lib/Basic/Targets.cpp
@@ -122,6 +122,11 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple,
case llvm::Triple::lanai:
return new LanaiTargetInfo(Triple, Opts);
+ case llvm::Triple::aarch64_32:
+ if (Triple.isOSDarwin())
+ return new DarwinAArch64TargetInfo(Triple, Opts);
+
+ return nullptr;
case llvm::Triple::aarch64:
if (Triple.isOSDarwin())
return new DarwinAArch64TargetInfo(Triple, Opts);
@@ -378,6 +383,8 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple,
switch (os) {
case llvm::Triple::FreeBSD:
return new FreeBSDTargetInfo<RISCV64TargetInfo>(Triple, Opts);
+ case llvm::Triple::Fuchsia:
+ return new FuchsiaTargetInfo<RISCV64TargetInfo>(Triple, Opts);
case llvm::Triple::Linux:
return new LinuxTargetInfo<RISCV64TargetInfo>(Triple, Opts);
default:
diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index c86cc63e3d84..cba3e3ada7ea 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -15,6 +15,8 @@
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/AArch64TargetParser.h"
using namespace clang;
using namespace clang::targets;
@@ -51,7 +53,11 @@ AArch64TargetInfo::AArch64TargetInfo(const llvm::Triple &Triple,
HasLegalHalfType = true;
HasFloat16 = true;
- LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
+ if (Triple.isArch64Bit())
+ LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
+ else
+ LongWidth = LongAlign = PointerWidth = PointerAlign = 32;
+
MaxVectorAlign = 128;
MaxAtomicInlineWidth = 128;
MaxAtomicPromoteWidth = 128;
@@ -103,6 +109,28 @@ bool AArch64TargetInfo::setABI(const std::string &Name) {
return true;
}
+bool AArch64TargetInfo::validateBranchProtection(StringRef Spec,
+ BranchProtectionInfo &BPI,
+ StringRef &Err) const {
+ llvm::AArch64::ParsedBranchProtection PBP;
+ if (!llvm::AArch64::parseBranchProtection(Spec, PBP, Err))
+ return false;
+
+ BPI.SignReturnAddr =
+ llvm::StringSwitch<CodeGenOptions::SignReturnAddressScope>(PBP.Scope)
+ .Case("non-leaf", CodeGenOptions::SignReturnAddressScope::NonLeaf)
+ .Case("all", CodeGenOptions::SignReturnAddressScope::All)
+ .Default(CodeGenOptions::SignReturnAddressScope::None);
+
+ if (PBP.Key == "a_key")
+ BPI.SignKey = CodeGenOptions::SignReturnAddressKeyValue::AKey;
+ else
+ BPI.SignKey = CodeGenOptions::SignReturnAddressKeyValue::BKey;
+
+ BPI.BranchTargetEnforcement = PBP.BranchTargetEnforcement;
+ return true;
+}
+
bool AArch64TargetInfo::isValidCPUName(StringRef Name) const {
return Name == "generic" ||
llvm::AArch64::parseCPUArch(Name) != llvm::AArch64::ArchKind::INVALID;
@@ -130,6 +158,7 @@ void AArch64TargetInfo::getTargetDefinesARMV82A(const LangOptions &Opts,
void AArch64TargetInfo::getTargetDefinesARMV83A(const LangOptions &Opts,
MacroBuilder &Builder) const {
+ Builder.defineMacro("__ARM_FEATURE_COMPLEX", "1");
Builder.defineMacro("__ARM_FEATURE_JCVT", "1");
// Also include the Armv8.2 defines
getTargetDefinesARMV82A(Opts, Builder);
@@ -160,7 +189,7 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__ELF__");
// Target properties.
- if (!getTriple().isOSWindows()) {
+ if (!getTriple().isOSWindows() && getTriple().isArch64Bit()) {
Builder.defineMacro("_LP64");
Builder.defineMacro("__LP64__");
}
@@ -506,14 +535,19 @@ int AArch64TargetInfo::getEHDataRegisterNumber(unsigned RegNo) const {
return -1;
}
+bool AArch64TargetInfo::hasInt128Type() const { return true; }
+
AArch64leTargetInfo::AArch64leTargetInfo(const llvm::Triple &Triple,
const TargetOptions &Opts)
: AArch64TargetInfo(Triple, Opts) {}
void AArch64leTargetInfo::setDataLayout() {
- if (getTriple().isOSBinFormatMachO())
- resetDataLayout("e-m:o-i64:64-i128:128-n32:64-S128");
- else
+ if (getTriple().isOSBinFormatMachO()) {
+ if(getTriple().isArch32Bit())
+ resetDataLayout("e-m:o-p:32:32-i64:64-i128:128-n32:64-S128");
+ else
+ resetDataLayout("e-m:o-i64:64-i128:128-n32:64-S128");
+ } else
resetDataLayout("e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128");
}
@@ -631,19 +665,34 @@ DarwinAArch64TargetInfo::DarwinAArch64TargetInfo(const llvm::Triple &Triple,
const TargetOptions &Opts)
: DarwinTargetInfo<AArch64leTargetInfo>(Triple, Opts) {
Int64Type = SignedLongLong;
+ if (getTriple().isArch32Bit())
+ IntMaxType = SignedLongLong;
+
+ WCharType = SignedInt;
UseSignedCharForObjCBool = false;
LongDoubleWidth = LongDoubleAlign = SuitableAlign = 64;
LongDoubleFormat = &llvm::APFloat::IEEEdouble();
- TheCXXABI.set(TargetCXXABI::iOS64);
+ UseZeroLengthBitfieldAlignment = false;
+
+ if (getTriple().isArch32Bit()) {
+ UseBitFieldTypeAlignment = false;
+ ZeroLengthBitfieldBoundary = 32;
+ UseZeroLengthBitfieldAlignment = true;
+ TheCXXABI.set(TargetCXXABI::WatchOS);
+ } else
+ TheCXXABI.set(TargetCXXABI::iOS64);
}
void DarwinAArch64TargetInfo::getOSDefines(const LangOptions &Opts,
const llvm::Triple &Triple,
MacroBuilder &Builder) const {
Builder.defineMacro("__AARCH64_SIMD__");
- Builder.defineMacro("__ARM64_ARCH_8__");
+ if (Triple.isArch32Bit())
+ Builder.defineMacro("__ARM64_ARCH_8_32__");
+ else
+ Builder.defineMacro("__ARM64_ARCH_8__");
Builder.defineMacro("__ARM_NEON__");
Builder.defineMacro("__LITTLE_ENDIAN__");
Builder.defineMacro("__REGISTER_PREFIX__", "");
diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h
index b6aa07780edd..5e78237743c9 100644
--- a/clang/lib/Basic/Targets/AArch64.h
+++ b/clang/lib/Basic/Targets/AArch64.h
@@ -49,6 +49,9 @@ public:
StringRef getABI() const override;
bool setABI(const std::string &Name) override;
+ bool validateBranchProtection(StringRef, BranchProtectionInfo &,
+ StringRef &) const override;
+
bool isValidCPUName(StringRef Name) const override;
void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
bool setCPU(const std::string &Name) override;
@@ -97,6 +100,8 @@ public:
}
int getEHDataRegisterNumber(unsigned RegNo) const override;
+
+ bool hasInt128Type() const override;
};
class LLVM_LIBRARY_VISIBILITY AArch64leTargetInfo : public AArch64TargetInfo {
diff --git a/clang/lib/Basic/Targets/AMDGPU.cpp b/clang/lib/Basic/Targets/AMDGPU.cpp
index 481630c0fa45..135ad3f97ce1 100644
--- a/clang/lib/Basic/Targets/AMDGPU.cpp
+++ b/clang/lib/Basic/Targets/AMDGPU.cpp
@@ -47,7 +47,10 @@ const LangASMap AMDGPUTargetInfo::AMDGPUDefIsGenMap = {
Generic, // opencl_generic
Global, // cuda_device
Constant, // cuda_constant
- Local // cuda_shared
+ Local, // cuda_shared
+ Generic, // ptr32_sptr
+ Generic, // ptr32_uptr
+ Generic // ptr64
};
const LangASMap AMDGPUTargetInfo::AMDGPUDefIsPrivMap = {
@@ -59,7 +62,11 @@ const LangASMap AMDGPUTargetInfo::AMDGPUDefIsPrivMap = {
Generic, // opencl_generic
Global, // cuda_device
Constant, // cuda_constant
- Local // cuda_shared
+ Local, // cuda_shared
+ Generic, // ptr32_sptr
+ Generic, // ptr32_uptr
+ Generic // ptr64
+
};
} // namespace targets
} // namespace clang
diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp
index 437a77afdc99..be088e81cffe 100644
--- a/clang/lib/Basic/Targets/ARM.cpp
+++ b/clang/lib/Basic/Targets/ARM.cpp
@@ -580,6 +580,13 @@ void ARMTargetInfo::getTargetDefinesARMV82A(const LangOptions &Opts,
getTargetDefinesARMV81A(Opts, Builder);
}
+void ARMTargetInfo::getTargetDefinesARMV83A(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ // Also include the ARMv8.2-A defines
+ Builder.defineMacro("__ARM_FEATURE_COMPLEX", "1");
+ getTargetDefinesARMV82A(Opts, Builder);
+}
+
void ARMTargetInfo::getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
// Target identification.
@@ -809,6 +816,11 @@ void ARMTargetInfo::getTargetDefines(const LangOptions &Opts,
case llvm::ARM::ArchKind::ARMV8_2A:
getTargetDefinesARMV82A(Opts, Builder);
break;
+ case llvm::ARM::ArchKind::ARMV8_3A:
+ case llvm::ARM::ArchKind::ARMV8_4A:
+ case llvm::ARM::ArchKind::ARMV8_5A:
+ getTargetDefinesARMV83A(Opts, Builder);
+ break;
}
}
diff --git a/clang/lib/Basic/Targets/ARM.h b/clang/lib/Basic/Targets/ARM.h
index ce87a6265934..9696a4404589 100644
--- a/clang/lib/Basic/Targets/ARM.h
+++ b/clang/lib/Basic/Targets/ARM.h
@@ -148,9 +148,10 @@ public:
void getTargetDefinesARMV81A(const LangOptions &Opts,
MacroBuilder &Builder) const;
-
void getTargetDefinesARMV82A(const LangOptions &Opts,
MacroBuilder &Builder) const;
+ void getTargetDefinesARMV83A(const LangOptions &Opts,
+ MacroBuilder &Builder) const;
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override;
diff --git a/clang/lib/Basic/Targets/BPF.h b/clang/lib/Basic/Targets/BPF.h
index 117f81430bf4..b2f1831e960e 100644
--- a/clang/lib/Basic/Targets/BPF.h
+++ b/clang/lib/Basic/Targets/BPF.h
@@ -76,6 +76,8 @@ public:
return None;
}
+ bool allowDebugInfoForExternalVar() const override { return true; }
+
CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
switch (CC) {
default:
diff --git a/clang/lib/Basic/Targets/Hexagon.cpp b/clang/lib/Basic/Targets/Hexagon.cpp
index be23fd2536e0..fcb94b93d69d 100644
--- a/clang/lib/Basic/Targets/Hexagon.cpp
+++ b/clang/lib/Basic/Targets/Hexagon.cpp
@@ -100,7 +100,10 @@ const char *const HexagonTargetInfo::GCCRegNames[] = {
"r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17",
"r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26",
"r27", "r28", "r29", "r30", "r31", "p0", "p1", "p2", "p3",
- "sa0", "lc0", "sa1", "lc1", "m0", "m1", "usr", "ugp"
+ "sa0", "lc0", "sa1", "lc1", "m0", "m1", "usr", "ugp",
+ "r1:0", "r3:2", "r5:4", "r7:6", "r9:8", "r11:10", "r13:12", "r15:14",
+ "r17:16", "r19:18", "r21:20", "r23:22", "r25:24", "r27:26", "r29:28",
+ "r31:30"
};
ArrayRef<const char *> HexagonTargetInfo::getGCCRegNames() const {
diff --git a/clang/lib/Basic/Targets/Mips.cpp b/clang/lib/Basic/Targets/Mips.cpp
index 2cafbe87a996..ead5e91f7c8f 100644
--- a/clang/lib/Basic/Targets/Mips.cpp
+++ b/clang/lib/Basic/Targets/Mips.cpp
@@ -39,6 +39,7 @@ bool MipsTargetInfo::processorSupportsGPR64() const {
.Case("mips64r5", true)
.Case("mips64r6", true)
.Case("octeon", true)
+ .Case("octeon+", true)
.Default(false);
return false;
}
@@ -47,7 +48,7 @@ static constexpr llvm::StringLiteral ValidCPUNames[] = {
{"mips1"}, {"mips2"}, {"mips3"}, {"mips4"}, {"mips5"},
{"mips32"}, {"mips32r2"}, {"mips32r3"}, {"mips32r5"}, {"mips32r6"},
{"mips64"}, {"mips64r2"}, {"mips64r3"}, {"mips64r5"}, {"mips64r6"},
- {"octeon"}, {"p5600"}};
+ {"octeon"}, {"octeon+"}, {"p5600"}};
bool MipsTargetInfo::isValidCPUName(StringRef Name) const {
return llvm::find(ValidCPUNames, Name) != std::end(ValidCPUNames);
@@ -61,7 +62,7 @@ void MipsTargetInfo::fillValidCPUList(
unsigned MipsTargetInfo::getISARev() const {
return llvm::StringSwitch<unsigned>(getCPU())
.Cases("mips32", "mips64", 1)
- .Cases("mips32r2", "mips64r2", 2)
+ .Cases("mips32r2", "mips64r2", "octeon", "octeon+", 2)
.Cases("mips32r3", "mips64r3", 3)
.Cases("mips32r5", "mips64r5", 5)
.Cases("mips32r6", "mips64r6", 6)
@@ -187,7 +188,13 @@ void MipsTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("_MIPS_SZLONG", Twine(getLongWidth()));
Builder.defineMacro("_MIPS_ARCH", "\"" + CPU + "\"");
- Builder.defineMacro("_MIPS_ARCH_" + StringRef(CPU).upper());
+ if (CPU == "octeon+")
+ Builder.defineMacro("_MIPS_ARCH_OCTEONP");
+ else
+ Builder.defineMacro("_MIPS_ARCH_" + StringRef(CPU).upper());
+
+ 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.
@@ -206,7 +213,10 @@ void MipsTargetInfo::getTargetDefines(const LangOptions &Opts,
bool MipsTargetInfo::hasFeature(StringRef Feature) const {
return llvm::StringSwitch<bool>(Feature)
.Case("mips", true)
+ .Case("dsp", DspRev >= DSP1)
+ .Case("dspr2", DspRev >= DSP2)
.Case("fp64", FPMode == FP64)
+ .Case("msa", HasMSA)
.Default(false);
}
diff --git a/clang/lib/Basic/Targets/Mips.h b/clang/lib/Basic/Targets/Mips.h
index 474cda84a40e..224ec0783edf 100644
--- a/clang/lib/Basic/Targets/Mips.h
+++ b/clang/lib/Basic/Targets/Mips.h
@@ -180,6 +180,8 @@ public:
CPU = getCPU();
if (CPU == "octeon")
Features["mips64r2"] = Features["cnmips"] = true;
+ else if (CPU == "octeon+")
+ Features["mips64r2"] = Features["cnmips"] = Features["cnmipsp"] = true;
else
Features[CPU] = true;
return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h
index 2cdd37ca1b07..63780789c474 100644
--- a/clang/lib/Basic/Targets/NVPTX.h
+++ b/clang/lib/Basic/Targets/NVPTX.h
@@ -33,6 +33,9 @@ static const unsigned NVPTXAddrSpaceMap[] = {
1, // cuda_device
4, // cuda_constant
3, // cuda_shared
+ 0, // ptr32_sptr
+ 0, // ptr32_uptr
+ 0 // ptr64
};
/// The DWARF address class. Taken from
diff --git a/clang/lib/Basic/Targets/OSTargets.cpp b/clang/lib/Basic/Targets/OSTargets.cpp
index 72fdb0e7dde8..d4ffffc64ba8 100644
--- a/clang/lib/Basic/Targets/OSTargets.cpp
+++ b/clang/lib/Basic/Targets/OSTargets.cpp
@@ -180,7 +180,7 @@ static void addVisualCDefines(const LangOptions &Opts, MacroBuilder &Builder) {
if (Opts.isCompatibleWithMSVC(LangOptions::MSVC2015)) {
if (Opts.CPlusPlus2a)
- Builder.defineMacro("_MSVC_LANG", "201704L");
+ Builder.defineMacro("_MSVC_LANG", "201705L");
else if (Opts.CPlusPlus17)
Builder.defineMacro("_MSVC_LANG", "201703L");
else if (Opts.CPlusPlus14)
diff --git a/clang/lib/Basic/Targets/OSTargets.h b/clang/lib/Basic/Targets/OSTargets.h
index cc72a0a39f30..70fac030bc5d 100644
--- a/clang/lib/Basic/Targets/OSTargets.h
+++ b/clang/lib/Basic/Targets/OSTargets.h
@@ -538,6 +538,7 @@ protected:
Builder.defineMacro("__KPRINTF_ATTRIBUTE__");
DefineStd(Builder, "unix", Opts);
Builder.defineMacro("__ELF__");
+ Builder.defineMacro("__SCE__");
Builder.defineMacro("__ORBIS__");
}
@@ -808,6 +809,7 @@ public:
FuchsiaTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
: OSTargetInfo<Target>(Triple, Opts) {
this->MCountName = "__mcount";
+ this->TheCXXABI.set(TargetCXXABI::Fuchsia);
}
};
diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp
index a40991048873..1877d4a5ef70 100644
--- a/clang/lib/Basic/Targets/PPC.cpp
+++ b/clang/lib/Basic/Targets/PPC.cpp
@@ -157,6 +157,10 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("_ARCH_A2Q");
Builder.defineMacro("_ARCH_QP");
}
+ if (ArchDefs & ArchDefineE500)
+ Builder.defineMacro("__NO_LWSYNC__");
+ if (ArchDefs & ArchDefineFuture)
+ Builder.defineMacro("_ARCH_PWR_FUTURE");
if (getTriple().getVendor() == llvm::Triple::BGQ) {
Builder.defineMacro("__bg__");
@@ -312,6 +316,18 @@ bool PPCTargetInfo::initFeatureMap(
.Case("pwr8", true)
.Default(false);
+ Features["spe"] = llvm::StringSwitch<bool>(CPU)
+ .Case("8548", true)
+ .Case("e500", true)
+ .Default(false);
+
+ // Future CPU should include all of the features of Power 9 as well as any
+ // additional features (yet to be determined) specific to it.
+ if (CPU == "future") {
+ initFeatureMap(Features, Diags, "pwr9", FeaturesVec);
+ addFutureSpecificFeatures(Features);
+ }
+
if (!ppcUserFeaturesCheck(Diags, FeaturesVec))
return false;
@@ -325,6 +341,12 @@ bool PPCTargetInfo::initFeatureMap(
return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
}
+// Add features specific to the "Future" CPU.
+void PPCTargetInfo::addFutureSpecificFeatures(
+ llvm::StringMap<bool> &Features) const {
+ return;
+}
+
bool PPCTargetInfo::hasFeature(StringRef Feature) const {
return llvm::StringSwitch<bool>(Feature)
.Case("powerpc", true)
@@ -449,16 +471,17 @@ ArrayRef<TargetInfo::AddlRegName> PPCTargetInfo::getGCCAddlRegNames() const {
}
static constexpr llvm::StringLiteral ValidCPUNames[] = {
- {"generic"}, {"440"}, {"450"}, {"601"}, {"602"},
- {"603"}, {"603e"}, {"603ev"}, {"604"}, {"604e"},
- {"620"}, {"630"}, {"g3"}, {"7400"}, {"g4"},
- {"7450"}, {"g4+"}, {"750"}, {"970"}, {"g5"},
- {"a2"}, {"a2q"}, {"e500mc"}, {"e5500"}, {"power3"},
- {"pwr3"}, {"power4"}, {"pwr4"}, {"power5"}, {"pwr5"},
- {"power5x"}, {"pwr5x"}, {"power6"}, {"pwr6"}, {"power6x"},
- {"pwr6x"}, {"power7"}, {"pwr7"}, {"power8"}, {"pwr8"},
- {"power9"}, {"pwr9"}, {"powerpc"}, {"ppc"}, {"powerpc64"},
- {"ppc64"}, {"powerpc64le"}, {"ppc64le"},
+ {"generic"}, {"440"}, {"450"}, {"601"}, {"602"},
+ {"603"}, {"603e"}, {"603ev"}, {"604"}, {"604e"},
+ {"620"}, {"630"}, {"g3"}, {"7400"}, {"g4"},
+ {"7450"}, {"g4+"}, {"750"}, {"8548"}, {"970"},
+ {"g5"}, {"a2"}, {"a2q"}, {"e500"}, {"e500mc"},
+ {"e5500"}, {"power3"}, {"pwr3"}, {"power4"}, {"pwr4"},
+ {"power5"}, {"pwr5"}, {"power5x"}, {"pwr5x"}, {"power6"},
+ {"pwr6"}, {"power6x"}, {"pwr6x"}, {"power7"}, {"pwr7"},
+ {"power8"}, {"pwr8"}, {"power9"}, {"pwr9"}, {"powerpc"},
+ {"ppc"}, {"powerpc64"}, {"ppc64"}, {"powerpc64le"}, {"ppc64le"},
+ {"future"}
};
bool PPCTargetInfo::isValidCPUName(StringRef Name) const {
diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h
index 6c6421c28e23..270aa7ff9181 100644
--- a/clang/lib/Basic/Targets/PPC.h
+++ b/clang/lib/Basic/Targets/PPC.h
@@ -43,8 +43,10 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
ArchDefinePwr7 = 1 << 11,
ArchDefinePwr8 = 1 << 12,
ArchDefinePwr9 = 1 << 13,
- ArchDefineA2 = 1 << 14,
- ArchDefineA2q = 1 << 15
+ ArchDefineFuture = 1 << 14,
+ ArchDefineA2 = 1 << 15,
+ ArchDefineA2q = 1 << 16,
+ ArchDefineE500 = 1 << 17
} ArchDefineTypes;
@@ -85,8 +87,7 @@ public:
// Note: GCC recognizes the following additional cpus:
// 401, 403, 405, 405fp, 440fp, 464, 464fp, 476, 476fp, 505, 740, 801,
- // 821, 823, 8540, 8548, e300c2, e300c3, e500mc64, e6500, 860, cell,
- // titan, rs64.
+ // 821, 823, 8540, e300c2, e300c3, e500mc64, e6500, 860, cell, titan, rs64.
bool isValidCPUName(StringRef Name) const override;
void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
@@ -145,6 +146,12 @@ public:
ArchDefinePwr9 | ArchDefinePwr8 | ArchDefinePwr7 |
ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 |
ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("future",
+ ArchDefineFuture | ArchDefinePwr9 | ArchDefinePwr8 |
+ ArchDefinePwr7 | ArchDefinePwr6 | ArchDefinePwr5x |
+ ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr |
+ ArchDefinePpcsq)
+ .Cases("8548", "e500", ArchDefineE500)
.Default(ArchDefineNone);
}
return CPUKnown;
@@ -164,6 +171,8 @@ public:
StringRef CPU,
const std::vector<std::string> &FeaturesVec) const override;
+ void addFutureSpecificFeatures(llvm::StringMap<bool> &Features) const;
+
bool handleTargetFeatures(std::vector<std::string> &Features,
DiagnosticsEngine &Diags) override;
@@ -380,7 +389,7 @@ public:
ABI = "elfv2";
} else {
resetDataLayout("E-m:e-i64:64-n32:64");
- ABI = Triple.getEnvironment() == llvm::Triple::ELFv2 ? "elfv2" : "elfv1";
+ ABI = "elfv1";
}
if (Triple.getOS() == llvm::Triple::AIX)
diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h
index 802ccf8b671e..279d1866a428 100644
--- a/clang/lib/Basic/Targets/SPIR.h
+++ b/clang/lib/Basic/Targets/SPIR.h
@@ -30,7 +30,10 @@ static const unsigned SPIRAddrSpaceMap[] = {
4, // opencl_generic
0, // cuda_device
0, // cuda_constant
- 0 // cuda_shared
+ 0, // cuda_shared
+ 0, // ptr32_sptr
+ 0, // ptr32_uptr
+ 0 // ptr64
};
class LLVM_LIBRARY_VISIBILITY SPIRTargetInfo : public TargetInfo {
diff --git a/clang/lib/Basic/Targets/TCE.h b/clang/lib/Basic/Targets/TCE.h
index 967ef5c59ee5..9cbf2a3688a2 100644
--- a/clang/lib/Basic/Targets/TCE.h
+++ b/clang/lib/Basic/Targets/TCE.h
@@ -39,7 +39,10 @@ static const unsigned TCEOpenCLAddrSpaceMap[] = {
0, // opencl_generic
0, // cuda_device
0, // cuda_constant
- 0 // cuda_shared
+ 0, // cuda_shared
+ 0, // ptr32_sptr
+ 0, // ptr32_uptr
+ 0, // ptr64
};
class LLVM_LIBRARY_VISIBILITY TCETargetInfo : public TargetInfo {
diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp
index 311ae6e17028..d099d3742f0b 100644
--- a/clang/lib/Basic/Targets/X86.cpp
+++ b/clang/lib/Basic/Targets/X86.cpp
@@ -131,13 +131,6 @@ bool X86TargetInfo::initFeatureMap(
case CK_Lakemont:
break;
- case CK_PentiumMMX:
- case CK_Pentium2:
- case CK_K6:
- case CK_WinChipC6:
- setFeatureEnabledImpl(Features, "mmx", true);
- break;
-
case CK_Cooperlake:
// CPX inherits all CLX features plus AVX512BF16
setFeatureEnabledImpl(Features, "avx512bf16", true);
@@ -253,7 +246,14 @@ SkylakeCommon:
case CK_Pentium3:
case CK_C3_2:
setFeatureEnabledImpl(Features, "sse", true);
+ LLVM_FALLTHROUGH;
+ case CK_Pentium2:
setFeatureEnabledImpl(Features, "fxsr", true);
+ LLVM_FALLTHROUGH;
+ case CK_PentiumMMX:
+ case CK_K6:
+ case CK_WinChipC6:
+ setFeatureEnabledImpl(Features, "mmx", true);
break;
case CK_Tremont:
@@ -291,6 +291,7 @@ SkylakeCommon:
setFeatureEnabledImpl(Features, "fxsr", true);
setFeatureEnabledImpl(Features, "cx16", true);
setFeatureEnabledImpl(Features, "sahf", true);
+ setFeatureEnabledImpl(Features, "mmx", true);
break;
case CK_KNM:
@@ -321,6 +322,7 @@ SkylakeCommon:
setFeatureEnabledImpl(Features, "xsave", true);
setFeatureEnabledImpl(Features, "movbe", true);
setFeatureEnabledImpl(Features, "sahf", true);
+ setFeatureEnabledImpl(Features, "mmx", true);
break;
case CK_K6_2:
@@ -369,6 +371,7 @@ SkylakeCommon:
setFeatureEnabledImpl(Features, "cx16", true);
setFeatureEnabledImpl(Features, "fxsr", true);
setFeatureEnabledImpl(Features, "sahf", true);
+ setFeatureEnabledImpl(Features, "mmx", true);
break;
case CK_ZNVER2:
@@ -390,6 +393,7 @@ SkylakeCommon:
setFeatureEnabledImpl(Features, "fsgsbase", true);
setFeatureEnabledImpl(Features, "fxsr", true);
setFeatureEnabledImpl(Features, "lzcnt", true);
+ setFeatureEnabledImpl(Features, "mmx", true);
setFeatureEnabledImpl(Features, "mwaitx", true);
setFeatureEnabledImpl(Features, "movbe", true);
setFeatureEnabledImpl(Features, "pclmul", true);
@@ -433,6 +437,7 @@ SkylakeCommon:
setFeatureEnabledImpl(Features, "fxsr", true);
setFeatureEnabledImpl(Features, "xsave", true);
setFeatureEnabledImpl(Features, "sahf", true);
+ setFeatureEnabledImpl(Features, "mmx", true);
break;
}
if (!TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec))
@@ -1726,21 +1731,24 @@ bool X86TargetInfo::validateAsmConstraint(
}
}
-bool X86TargetInfo::validateOutputSize(StringRef Constraint,
+bool X86TargetInfo::validateOutputSize(const llvm::StringMap<bool> &FeatureMap,
+ StringRef Constraint,
unsigned Size) const {
// Strip off constraint modifiers.
while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&')
Constraint = Constraint.substr(1);
- return validateOperandSize(Constraint, Size);
+ return validateOperandSize(FeatureMap, Constraint, Size);
}
-bool X86TargetInfo::validateInputSize(StringRef Constraint,
+bool X86TargetInfo::validateInputSize(const llvm::StringMap<bool> &FeatureMap,
+ StringRef Constraint,
unsigned Size) const {
- return validateOperandSize(Constraint, Size);
+ return validateOperandSize(FeatureMap, Constraint, Size);
}
-bool X86TargetInfo::validateOperandSize(StringRef Constraint,
+bool X86TargetInfo::validateOperandSize(const llvm::StringMap<bool> &FeatureMap,
+ StringRef Constraint,
unsigned Size) const {
switch (Constraint[0]) {
default:
@@ -1765,7 +1773,7 @@ bool X86TargetInfo::validateOperandSize(StringRef Constraint,
case 'z':
case '0':
// XMM0
- if (SSELevel >= SSE1)
+ if (FeatureMap.lookup("sse"))
return Size <= 128U;
return false;
case 'i':
@@ -1779,10 +1787,10 @@ bool X86TargetInfo::validateOperandSize(StringRef Constraint,
LLVM_FALLTHROUGH;
case 'v':
case 'x':
- if (SSELevel >= AVX512F)
+ if (FeatureMap.lookup("avx512f"))
// 512-bit zmm registers can be used if target supports AVX512F.
return Size <= 512U;
- else if (SSELevel >= AVX)
+ else if (FeatureMap.lookup("avx"))
// 256-bit ymm registers can be used if target supports AVX.
return Size <= 256U;
return Size <= 128U;
diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h
index cad869f71230..5b5e284e5141 100644
--- a/clang/lib/Basic/Targets/X86.h
+++ b/clang/lib/Basic/Targets/X86.h
@@ -22,6 +22,21 @@
namespace clang {
namespace targets {
+static const unsigned X86AddrSpaceMap[] = {
+ 0, // Default
+ 0, // opencl_global
+ 0, // opencl_local
+ 0, // opencl_constant
+ 0, // opencl_private
+ 0, // opencl_generic
+ 0, // cuda_device
+ 0, // cuda_constant
+ 0, // cuda_shared
+ 270, // ptr32_sptr
+ 271, // ptr32_uptr
+ 272 // ptr64
+};
+
// X86 target abstract base class; x86-32 and x86-64 are very close, so
// most of the implementation can be shared.
class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
@@ -45,6 +60,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
AMD3DNowAthlon
} MMX3DNowLevel = NoMMX3DNow;
enum XOPEnum { NoXOP, SSE4A, FMA4, XOP } XOPLevel = NoXOP;
+ enum AddrSpace { ptr32_sptr = 270, ptr32_uptr = 271, ptr64 = 272 };
bool HasAES = false;
bool HasVAES = false;
@@ -130,6 +146,7 @@ public:
X86TargetInfo(const llvm::Triple &Triple, const TargetOptions &)
: TargetInfo(Triple) {
LongDoubleFormat = &llvm::APFloat::x87DoubleExtended();
+ AddrSpaceMap = &X86AddrSpaceMap;
}
const char *getLongDoubleMangling() const override {
@@ -177,9 +194,11 @@ public:
return false;
}
- bool validateOutputSize(StringRef Constraint, unsigned Size) const override;
+ bool validateOutputSize(const llvm::StringMap<bool> &FeatureMap,
+ StringRef Constraint, unsigned Size) const override;
- bool validateInputSize(StringRef Constraint, unsigned Size) const override;
+ bool validateInputSize(const llvm::StringMap<bool> &FeatureMap,
+ StringRef Constraint, unsigned Size) const override;
virtual bool
checkCFProtectionReturnSupported(DiagnosticsEngine &Diags) const override {
@@ -191,8 +210,8 @@ public:
return true;
};
-
- virtual bool validateOperandSize(StringRef Constraint, unsigned Size) const;
+ virtual bool validateOperandSize(const llvm::StringMap<bool> &FeatureMap,
+ StringRef Constraint, unsigned Size) const;
std::string convertConstraint(const char *&Constraint) const override;
const char *getClobbers() const override {
@@ -328,6 +347,18 @@ public:
void setSupportedOpenCLOpts() override {
getSupportedOpenCLOpts().supportAll();
}
+
+ uint64_t getPointerWidthV(unsigned AddrSpace) const override {
+ if (AddrSpace == ptr32_sptr || AddrSpace == ptr32_uptr)
+ return 32;
+ if (AddrSpace == ptr64)
+ return 64;
+ return PointerWidth;
+ }
+
+ uint64_t getPointerAlignV(unsigned AddrSpace) const override {
+ return getPointerWidthV(AddrSpace);
+ }
};
// X86-32 generic target
@@ -368,7 +399,8 @@ public:
return -1;
}
- bool validateOperandSize(StringRef Constraint, unsigned Size) const override {
+ bool validateOperandSize(const llvm::StringMap<bool> &FeatureMap,
+ StringRef Constraint, unsigned Size) const override {
switch (Constraint[0]) {
default:
break;
@@ -386,7 +418,7 @@ public:
return Size <= 64;
}
- return X86TargetInfo::validateOperandSize(Constraint, Size);
+ return X86TargetInfo::validateOperandSize(FeatureMap, Constraint, Size);
}
void setMaxAtomicWidth() override {
diff --git a/clang/lib/Basic/Version.cpp b/clang/lib/Basic/Version.cpp
index d6564582e772..c69d13b2f689 100644
--- a/clang/lib/Basic/Version.cpp
+++ b/clang/lib/Basic/Version.cpp
@@ -127,11 +127,6 @@ std::string getClangToolFullVersion(StringRef ToolName) {
OS << ToolName << " version " CLANG_VERSION_STRING " "
<< getClangFullRepositoryVersion();
- // If vendor supplied, include the base LLVM version as well.
-#ifdef CLANG_VENDOR
- OS << " (based on " << BACKEND_PACKAGE_STRING << ")";
-#endif
-
return OS.str();
}
diff --git a/clang/lib/Basic/XRayLists.cpp b/clang/lib/Basic/XRayLists.cpp
index eb549436710a..222a28f79cc5 100644
--- a/clang/lib/Basic/XRayLists.cpp
+++ b/clang/lib/Basic/XRayLists.cpp
@@ -17,10 +17,13 @@ XRayFunctionFilter::XRayFunctionFilter(
ArrayRef<std::string> AlwaysInstrumentPaths,
ArrayRef<std::string> NeverInstrumentPaths,
ArrayRef<std::string> AttrListPaths, SourceManager &SM)
- : AlwaysInstrument(
- llvm::SpecialCaseList::createOrDie(AlwaysInstrumentPaths)),
- NeverInstrument(llvm::SpecialCaseList::createOrDie(NeverInstrumentPaths)),
- AttrList(llvm::SpecialCaseList::createOrDie(AttrListPaths)), SM(SM) {}
+ : AlwaysInstrument(llvm::SpecialCaseList::createOrDie(
+ AlwaysInstrumentPaths, SM.getFileManager().getVirtualFileSystem())),
+ NeverInstrument(llvm::SpecialCaseList::createOrDie(
+ NeverInstrumentPaths, SM.getFileManager().getVirtualFileSystem())),
+ AttrList(llvm::SpecialCaseList::createOrDie(
+ AttrListPaths, SM.getFileManager().getVirtualFileSystem())),
+ SM(SM) {}
XRayFunctionFilter::ImbueAttribute
XRayFunctionFilter::shouldImbueFunction(StringRef FunctionName) const {
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 75a54d8f3c8a..0bfcab88a3a9 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -75,6 +75,10 @@
using namespace clang;
using namespace llvm;
+#define HANDLE_EXTENSION(Ext) \
+ llvm::PassPluginLibraryInfo get##Ext##PluginInfo();
+#include "llvm/Support/Extension.def"
+
namespace {
// Default filename used for profile generation.
@@ -339,15 +343,6 @@ static void addDataFlowSanitizerPass(const PassManagerBuilder &Builder,
static TargetLibraryInfoImpl *createTLII(llvm::Triple &TargetTriple,
const CodeGenOptions &CodeGenOpts) {
TargetLibraryInfoImpl *TLII = new TargetLibraryInfoImpl(TargetTriple);
- if (!CodeGenOpts.SimplifyLibCalls)
- TLII->disableAllFunctions();
- else {
- // Disable individual libc/libm calls in TargetLibraryInfo.
- LibFunc F;
- for (auto &FuncName : CodeGenOpts.getNoBuiltinFuncs())
- if (TLII->getLibFunc(FuncName, F))
- TLII->setUnavailable(F);
- }
switch (CodeGenOpts.getVecLib()) {
case CodeGenOptions::Accelerate:
@@ -407,14 +402,14 @@ getCodeModel(const CodeGenOptions &CodeGenOpts) {
return static_cast<llvm::CodeModel::Model>(CodeModel);
}
-static TargetMachine::CodeGenFileType getCodeGenFileType(BackendAction Action) {
+static CodeGenFileType getCodeGenFileType(BackendAction Action) {
if (Action == Backend_EmitObj)
- return TargetMachine::CGFT_ObjectFile;
+ return CGFT_ObjectFile;
else if (Action == Backend_EmitMCNull)
- return TargetMachine::CGFT_Null;
+ return CGFT_Null;
else {
assert(Action == Backend_EmitAssembly && "Invalid action!");
- return TargetMachine::CGFT_AssemblyFile;
+ return CGFT_AssemblyFile;
}
}
@@ -479,12 +474,14 @@ static void initTargetOptions(llvm::TargetOptions &Options,
Options.FunctionSections = CodeGenOpts.FunctionSections;
Options.DataSections = CodeGenOpts.DataSections;
Options.UniqueSectionNames = CodeGenOpts.UniqueSectionNames;
+ Options.TLSSize = CodeGenOpts.TLSSize;
Options.EmulatedTLS = CodeGenOpts.EmulatedTLS;
Options.ExplicitEmulatedTLS = CodeGenOpts.ExplicitEmulatedTLS;
Options.DebuggerTuning = CodeGenOpts.getDebuggerTuning();
Options.EmitStackSizeSection = CodeGenOpts.StackSizeSection;
Options.EmitAddrsig = CodeGenOpts.Addrsig;
Options.EnableDebugEntryValues = CodeGenOpts.EnableDebugEntryValues;
+ Options.ForceDwarfFrameSection = CodeGenOpts.ForceDwarfFrameSection;
Options.MCOptions.SplitDwarfFile = CodeGenOpts.SplitDwarfFile;
Options.MCOptions.MCRelaxAll = CodeGenOpts.RelaxAll;
@@ -493,7 +490,6 @@ static void initTargetOptions(llvm::TargetOptions &Options,
Options.MCOptions.MCNoExecStack = CodeGenOpts.NoExecStack;
Options.MCOptions.MCIncrementalLinkerCompatible =
CodeGenOpts.IncrementalLinkerCompatible;
- Options.MCOptions.MCPIECopyRelocations = CodeGenOpts.PIECopyRelocations;
Options.MCOptions.MCFatalWarnings = CodeGenOpts.FatalWarnings;
Options.MCOptions.MCNoWarn = CodeGenOpts.NoWarn;
Options.MCOptions.AsmVerbose = CodeGenOpts.AsmVerbose;
@@ -787,7 +783,7 @@ bool EmitAssemblyHelper::AddEmitPasses(legacy::PassManager &CodeGenPasses,
// Normal mode, emit a .s or .o file by running the code generator. Note,
// this also adds codegenerator level optimization passes.
- TargetMachine::CodeGenFileType CGFT = getCodeGenFileType(Action);
+ CodeGenFileType CGFT = getCodeGenFileType(Action);
// Add ObjC ARC final-cleanup optimizations. This is done as part of the
// "codegen" passes so that it isn't run multiple times when there is
@@ -895,7 +891,7 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action,
{
PrettyStackTraceString CrashInfo("Per-function optimization");
- llvm::TimeTraceScope TimeScope("PerFunctionPasses", StringRef(""));
+ llvm::TimeTraceScope TimeScope("PerFunctionPasses");
PerFunctionPasses.doInitialization();
for (Function &F : *TheModule)
@@ -906,13 +902,13 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action,
{
PrettyStackTraceString CrashInfo("Per-module optimization passes");
- llvm::TimeTraceScope TimeScope("PerModulePasses", StringRef(""));
+ llvm::TimeTraceScope TimeScope("PerModulePasses");
PerModulePasses.run(*TheModule);
}
{
PrettyStackTraceString CrashInfo("Code generation");
- llvm::TimeTraceScope TimeScope("CodeGenPasses", StringRef(""));
+ llvm::TimeTraceScope TimeScope("CodeGenPasses");
CodeGenPasses.run(*TheModule);
}
@@ -1085,6 +1081,9 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
<< PluginFN << toString(PassPlugin.takeError());
}
}
+#define HANDLE_EXTENSION(Ext) \
+ get##Ext##PluginInfo().RegisterPassBuilderCallbacks(PB);
+#include "llvm/Support/Extension.def"
LoopAnalysisManager LAM(CodeGenOpts.DebugPassManager);
FunctionAnalysisManager FAM(CodeGenOpts.DebugPassManager);
@@ -1439,6 +1438,12 @@ static void runThinLTOBackend(ModuleSummaryIndex *CombinedIndex, Module *M,
Conf.OptLevel = CGOpts.OptimizationLevel;
initTargetOptions(Conf.Options, CGOpts, TOpts, LOpts, HeaderOpts);
Conf.SampleProfile = std::move(SampleProfile);
+ Conf.PTO.LoopUnrolling = CGOpts.UnrollLoops;
+ // For historical reasons, loop interleaving is set to mirror setting for loop
+ // unrolling.
+ Conf.PTO.LoopInterleaving = CGOpts.UnrollLoops;
+ Conf.PTO.LoopVectorization = CGOpts.VectorizeLoop;
+ Conf.PTO.SLPVectorization = CGOpts.VectorizeSLP;
// Context sensitive profile.
if (CGOpts.hasProfileCSIRInstr()) {
@@ -1498,7 +1503,7 @@ void clang::EmitBackendOutput(DiagnosticsEngine &Diags,
BackendAction Action,
std::unique_ptr<raw_pwrite_stream> OS) {
- llvm::TimeTraceScope TimeScope("Backend", StringRef(""));
+ llvm::TimeTraceScope TimeScope("Backend");
std::unique_ptr<llvm::Module> EmptyModule;
if (!CGOpts.ThinLTOIndexFile.empty()) {
@@ -1557,129 +1562,14 @@ void clang::EmitBackendOutput(DiagnosticsEngine &Diags,
}
}
-static const char* getSectionNameForBitcode(const Triple &T) {
- switch (T.getObjectFormat()) {
- case Triple::MachO:
- return "__LLVM,__bitcode";
- case Triple::COFF:
- case Triple::ELF:
- case Triple::Wasm:
- case Triple::UnknownObjectFormat:
- return ".llvmbc";
- case Triple::XCOFF:
- llvm_unreachable("XCOFF is not yet implemented");
- break;
- }
- llvm_unreachable("Unimplemented ObjectFormatType");
-}
-
-static const char* getSectionNameForCommandline(const Triple &T) {
- switch (T.getObjectFormat()) {
- case Triple::MachO:
- return "__LLVM,__cmdline";
- case Triple::COFF:
- case Triple::ELF:
- case Triple::Wasm:
- case Triple::UnknownObjectFormat:
- return ".llvmcmd";
- case Triple::XCOFF:
- llvm_unreachable("XCOFF is not yet implemented");
- break;
- }
- llvm_unreachable("Unimplemented ObjectFormatType");
-}
-
// With -fembed-bitcode, save a copy of the llvm IR as data in the
// __LLVM,__bitcode section.
void clang::EmbedBitcode(llvm::Module *M, const CodeGenOptions &CGOpts,
llvm::MemoryBufferRef Buf) {
if (CGOpts.getEmbedBitcode() == CodeGenOptions::Embed_Off)
return;
-
- // Save llvm.compiler.used and remote it.
- SmallVector<Constant*, 2> UsedArray;
- SmallPtrSet<GlobalValue*, 4> UsedGlobals;
- Type *UsedElementType = Type::getInt8Ty(M->getContext())->getPointerTo(0);
- GlobalVariable *Used = collectUsedGlobalVariables(*M, UsedGlobals, true);
- for (auto *GV : UsedGlobals) {
- if (GV->getName() != "llvm.embedded.module" &&
- GV->getName() != "llvm.cmdline")
- UsedArray.push_back(
- ConstantExpr::getPointerBitCastOrAddrSpaceCast(GV, UsedElementType));
- }
- if (Used)
- Used->eraseFromParent();
-
- // Embed the bitcode for the llvm module.
- std::string Data;
- ArrayRef<uint8_t> ModuleData;
- Triple T(M->getTargetTriple());
- // Create a constant that contains the bitcode.
- // In case of embedding a marker, ignore the input Buf and use the empty
- // ArrayRef. It is also legal to create a bitcode marker even Buf is empty.
- if (CGOpts.getEmbedBitcode() != CodeGenOptions::Embed_Marker) {
- if (!isBitcode((const unsigned char *)Buf.getBufferStart(),
- (const unsigned char *)Buf.getBufferEnd())) {
- // If the input is LLVM Assembly, bitcode is produced by serializing
- // the module. Use-lists order need to be perserved in this case.
- llvm::raw_string_ostream OS(Data);
- llvm::WriteBitcodeToFile(*M, OS, /* ShouldPreserveUseListOrder */ true);
- ModuleData =
- ArrayRef<uint8_t>((const uint8_t *)OS.str().data(), OS.str().size());
- } else
- // If the input is LLVM bitcode, write the input byte stream directly.
- ModuleData = ArrayRef<uint8_t>((const uint8_t *)Buf.getBufferStart(),
- Buf.getBufferSize());
- }
- llvm::Constant *ModuleConstant =
- llvm::ConstantDataArray::get(M->getContext(), ModuleData);
- llvm::GlobalVariable *GV = new llvm::GlobalVariable(
- *M, ModuleConstant->getType(), true, llvm::GlobalValue::PrivateLinkage,
- ModuleConstant);
- GV->setSection(getSectionNameForBitcode(T));
- UsedArray.push_back(
- ConstantExpr::getPointerBitCastOrAddrSpaceCast(GV, UsedElementType));
- if (llvm::GlobalVariable *Old =
- M->getGlobalVariable("llvm.embedded.module", true)) {
- assert(Old->hasOneUse() &&
- "llvm.embedded.module can only be used once in llvm.compiler.used");
- GV->takeName(Old);
- Old->eraseFromParent();
- } else {
- GV->setName("llvm.embedded.module");
- }
-
- // Skip if only bitcode needs to be embedded.
- if (CGOpts.getEmbedBitcode() != CodeGenOptions::Embed_Bitcode) {
- // Embed command-line options.
- ArrayRef<uint8_t> CmdData(const_cast<uint8_t *>(CGOpts.CmdArgs.data()),
- CGOpts.CmdArgs.size());
- llvm::Constant *CmdConstant =
- llvm::ConstantDataArray::get(M->getContext(), CmdData);
- GV = new llvm::GlobalVariable(*M, CmdConstant->getType(), true,
- llvm::GlobalValue::PrivateLinkage,
- CmdConstant);
- GV->setSection(getSectionNameForCommandline(T));
- UsedArray.push_back(
- ConstantExpr::getPointerBitCastOrAddrSpaceCast(GV, UsedElementType));
- if (llvm::GlobalVariable *Old =
- M->getGlobalVariable("llvm.cmdline", true)) {
- assert(Old->hasOneUse() &&
- "llvm.cmdline can only be used once in llvm.compiler.used");
- GV->takeName(Old);
- Old->eraseFromParent();
- } else {
- GV->setName("llvm.cmdline");
- }
- }
-
- if (UsedArray.empty())
- return;
-
- // Recreate llvm.compiler.used.
- ArrayType *ATy = ArrayType::get(UsedElementType, UsedArray.size());
- auto *NewUsed = new GlobalVariable(
- *M, ATy, false, llvm::GlobalValue::AppendingLinkage,
- llvm::ConstantArray::get(ATy, UsedArray), "llvm.compiler.used");
- NewUsed->setSection("llvm.metadata");
+ llvm::EmbedBitcodeInModule(
+ *M, Buf, CGOpts.getEmbedBitcode() != CodeGenOptions::Embed_Marker,
+ CGOpts.getEmbedBitcode() != CodeGenOptions::Embed_Bitcode,
+ &CGOpts.CmdArgs);
}
diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp
index 505916350750..149982d82790 100644
--- a/clang/lib/CodeGen/CGAtomic.cpp
+++ b/clang/lib/CodeGen/CGAtomic.cpp
@@ -139,7 +139,7 @@ namespace {
const LValue &getAtomicLValue() const { return LVal; }
llvm::Value *getAtomicPointer() const {
if (LVal.isSimple())
- return LVal.getPointer();
+ return LVal.getPointer(CGF);
else if (LVal.isBitField())
return LVal.getBitFieldPointer();
else if (LVal.isVectorElt())
@@ -343,14 +343,14 @@ bool AtomicInfo::requiresMemSetZero(llvm::Type *type) const {
bool AtomicInfo::emitMemSetZeroIfNecessary() const {
assert(LVal.isSimple());
- llvm::Value *addr = LVal.getPointer();
+ llvm::Value *addr = LVal.getPointer(CGF);
if (!requiresMemSetZero(addr->getType()->getPointerElementType()))
return false;
CGF.Builder.CreateMemSet(
addr, llvm::ConstantInt::get(CGF.Int8Ty, 0),
CGF.getContext().toCharUnitsFromBits(AtomicSizeInBits).getQuantity(),
- LVal.getAlignment().getQuantity());
+ LVal.getAlignment().getAsAlign());
return true;
}
@@ -488,13 +488,36 @@ static void emitAtomicCmpXchgFailureSet(CodeGenFunction &CGF, AtomicExpr *E,
CGF.Builder.SetInsertPoint(ContBB);
}
+/// Duplicate the atomic min/max operation in conventional IR for the builtin
+/// variants that return the new rather than the original value.
+static llvm::Value *EmitPostAtomicMinMax(CGBuilderTy &Builder,
+ AtomicExpr::AtomicOp Op,
+ bool IsSigned,
+ llvm::Value *OldVal,
+ llvm::Value *RHS) {
+ llvm::CmpInst::Predicate Pred;
+ switch (Op) {
+ default:
+ llvm_unreachable("Unexpected min/max operation");
+ case AtomicExpr::AO__atomic_max_fetch:
+ Pred = IsSigned ? llvm::CmpInst::ICMP_SGT : llvm::CmpInst::ICMP_UGT;
+ break;
+ case AtomicExpr::AO__atomic_min_fetch:
+ Pred = IsSigned ? llvm::CmpInst::ICMP_SLT : llvm::CmpInst::ICMP_ULT;
+ break;
+ }
+ llvm::Value *Cmp = Builder.CreateICmp(Pred, OldVal, RHS, "tst");
+ return Builder.CreateSelect(Cmp, OldVal, RHS, "newval");
+}
+
static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
Address Ptr, Address Val1, Address Val2,
llvm::Value *IsWeak, llvm::Value *FailureOrder,
uint64_t Size, llvm::AtomicOrdering Order,
llvm::SyncScope::ID Scope) {
llvm::AtomicRMWInst::BinOp Op = llvm::AtomicRMWInst::Add;
- llvm::Instruction::BinaryOps PostOp = (llvm::Instruction::BinaryOps)0;
+ bool PostOpMinMax = false;
+ unsigned PostOp = 0;
switch (E->getOp()) {
case AtomicExpr::AO__c11_atomic_init:
@@ -588,12 +611,20 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
Op = llvm::AtomicRMWInst::Sub;
break;
+ case AtomicExpr::AO__atomic_min_fetch:
+ PostOpMinMax = true;
+ LLVM_FALLTHROUGH;
+ case AtomicExpr::AO__c11_atomic_fetch_min:
case AtomicExpr::AO__opencl_atomic_fetch_min:
case AtomicExpr::AO__atomic_fetch_min:
Op = E->getValueType()->isSignedIntegerType() ? llvm::AtomicRMWInst::Min
: llvm::AtomicRMWInst::UMin;
break;
+ case AtomicExpr::AO__atomic_max_fetch:
+ PostOpMinMax = true;
+ LLVM_FALLTHROUGH;
+ case AtomicExpr::AO__c11_atomic_fetch_max:
case AtomicExpr::AO__opencl_atomic_fetch_max:
case AtomicExpr::AO__atomic_fetch_max:
Op = E->getValueType()->isSignedIntegerType() ? llvm::AtomicRMWInst::Max
@@ -643,8 +674,13 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
// For __atomic_*_fetch operations, perform the operation again to
// determine the value which was written.
llvm::Value *Result = RMWI;
- if (PostOp)
- Result = CGF.Builder.CreateBinOp(PostOp, RMWI, LoadVal1);
+ if (PostOpMinMax)
+ Result = EmitPostAtomicMinMax(CGF.Builder, E->getOp(),
+ E->getValueType()->isSignedIntegerType(),
+ RMWI, LoadVal1);
+ else if (PostOp)
+ Result = CGF.Builder.CreateBinOp((llvm::Instruction::BinaryOps)PostOp, RMWI,
+ LoadVal1);
if (E->getOp() == AtomicExpr::AO__atomic_nand_fetch)
Result = CGF.Builder.CreateNot(Result);
CGF.Builder.CreateStore(Result, Dest);
@@ -853,6 +889,8 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
case AtomicExpr::AO__c11_atomic_fetch_and:
case AtomicExpr::AO__c11_atomic_fetch_or:
case AtomicExpr::AO__c11_atomic_fetch_xor:
+ case AtomicExpr::AO__c11_atomic_fetch_max:
+ case AtomicExpr::AO__c11_atomic_fetch_min:
case AtomicExpr::AO__opencl_atomic_fetch_and:
case AtomicExpr::AO__opencl_atomic_fetch_or:
case AtomicExpr::AO__opencl_atomic_fetch_xor:
@@ -866,8 +904,10 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
case AtomicExpr::AO__atomic_or_fetch:
case AtomicExpr::AO__atomic_xor_fetch:
case AtomicExpr::AO__atomic_nand_fetch:
- case AtomicExpr::AO__atomic_fetch_min:
+ case AtomicExpr::AO__atomic_max_fetch:
+ case AtomicExpr::AO__atomic_min_fetch:
case AtomicExpr::AO__atomic_fetch_max:
+ case AtomicExpr::AO__atomic_fetch_min:
Val1 = EmitValToTemp(*this, E->getVal1());
break;
}
@@ -916,14 +956,18 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
case AtomicExpr::AO__opencl_atomic_fetch_min:
case AtomicExpr::AO__opencl_atomic_fetch_max:
case AtomicExpr::AO__atomic_fetch_xor:
+ case AtomicExpr::AO__c11_atomic_fetch_max:
+ case AtomicExpr::AO__c11_atomic_fetch_min:
case AtomicExpr::AO__atomic_add_fetch:
case AtomicExpr::AO__atomic_and_fetch:
case AtomicExpr::AO__atomic_nand_fetch:
case AtomicExpr::AO__atomic_or_fetch:
case AtomicExpr::AO__atomic_sub_fetch:
case AtomicExpr::AO__atomic_xor_fetch:
- case AtomicExpr::AO__atomic_fetch_min:
case AtomicExpr::AO__atomic_fetch_max:
+ case AtomicExpr::AO__atomic_fetch_min:
+ case AtomicExpr::AO__atomic_max_fetch:
+ case AtomicExpr::AO__atomic_min_fetch:
// For these, only library calls for certain sizes exist.
UseOptimizedLibcall = true;
break;
@@ -991,6 +1035,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
QualType RetTy;
bool HaveRetTy = false;
llvm::Instruction::BinaryOps PostOp = (llvm::Instruction::BinaryOps)0;
+ bool PostOpMinMax = false;
switch (E->getOp()) {
case AtomicExpr::AO__c11_atomic_init:
case AtomicExpr::AO__opencl_atomic_init:
@@ -1112,6 +1157,10 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
MemTy, E->getExprLoc(), sizeChars);
break;
+ case AtomicExpr::AO__atomic_min_fetch:
+ PostOpMinMax = true;
+ LLVM_FALLTHROUGH;
+ case AtomicExpr::AO__c11_atomic_fetch_min:
case AtomicExpr::AO__atomic_fetch_min:
case AtomicExpr::AO__opencl_atomic_fetch_min:
LibCallName = E->getValueType()->isSignedIntegerType()
@@ -1120,6 +1169,10 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
LoweredMemTy, E->getExprLoc(), sizeChars);
break;
+ case AtomicExpr::AO__atomic_max_fetch:
+ PostOpMinMax = true;
+ LLVM_FALLTHROUGH;
+ case AtomicExpr::AO__c11_atomic_fetch_max:
case AtomicExpr::AO__atomic_fetch_max:
case AtomicExpr::AO__opencl_atomic_fetch_max:
LibCallName = E->getValueType()->isSignedIntegerType()
@@ -1171,7 +1224,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
// PostOp is only needed for the atomic_*_fetch operations, and
// thus is only needed for and implemented in the
// UseOptimizedLibcall codepath.
- assert(UseOptimizedLibcall || !PostOp);
+ assert(UseOptimizedLibcall || (!PostOp && !PostOpMinMax));
RValue Res = emitAtomicLibcall(*this, LibCallName, RetTy, Args);
// The value is returned directly from the libcall.
@@ -1182,7 +1235,12 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
// provided an out-param.
if (UseOptimizedLibcall && Res.getScalarVal()) {
llvm::Value *ResVal = Res.getScalarVal();
- if (PostOp) {
+ if (PostOpMinMax) {
+ llvm::Value *LoadVal1 = Args[1].getRValue(*this).getScalarVal();
+ ResVal = EmitPostAtomicMinMax(Builder, E->getOp(),
+ E->getValueType()->isSignedIntegerType(),
+ ResVal, LoadVal1);
+ } else if (PostOp) {
llvm::Value *LoadVal1 = Args[1].getRValue(*this).getScalarVal();
ResVal = Builder.CreateBinOp(PostOp, ResVal, LoadVal1);
}
@@ -1570,7 +1628,7 @@ Address AtomicInfo::materializeRValue(RValue rvalue) const {
LValue TempLV = CGF.MakeAddrLValue(CreateTempAlloca(), getAtomicType());
AtomicInfo Atomics(CGF, TempLV);
Atomics.emitCopyIntoMemory(rvalue);
- return TempLV.getAddress();
+ return TempLV.getAddress(CGF);
}
llvm::Value *AtomicInfo::convertRValueToInt(RValue RVal) const {
@@ -1917,8 +1975,8 @@ void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest,
// If this is an aggregate r-value, it should agree in type except
// maybe for address-space qualification.
assert(!rvalue.isAggregate() ||
- rvalue.getAggregateAddress().getElementType()
- == dest.getAddress().getElementType());
+ rvalue.getAggregateAddress().getElementType() ==
+ dest.getAddress(*this).getElementType());
AtomicInfo atomics(*this, dest);
LValue LVal = atomics.getAtomicLValue();
@@ -1985,10 +2043,10 @@ std::pair<RValue, llvm::Value *> CodeGenFunction::EmitAtomicCompareExchange(
// maybe for address-space qualification.
assert(!Expected.isAggregate() ||
Expected.getAggregateAddress().getElementType() ==
- Obj.getAddress().getElementType());
+ Obj.getAddress(*this).getElementType());
assert(!Desired.isAggregate() ||
Desired.getAggregateAddress().getElementType() ==
- Obj.getAddress().getElementType());
+ Obj.getAddress(*this).getElementType());
AtomicInfo Atomics(*this, Obj);
return Atomics.EmitAtomicCompareExchange(Expected, Desired, Success, Failure,
@@ -2028,13 +2086,11 @@ void CodeGenFunction::EmitAtomicInit(Expr *init, LValue dest) {
}
// Evaluate the expression directly into the destination.
- AggValueSlot slot = AggValueSlot::forLValue(dest,
- AggValueSlot::IsNotDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- AggValueSlot::DoesNotOverlap,
- Zeroed ? AggValueSlot::IsZeroed :
- AggValueSlot::IsNotZeroed);
+ AggValueSlot slot = AggValueSlot::forLValue(
+ dest, *this, AggValueSlot::IsNotDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased,
+ AggValueSlot::DoesNotOverlap,
+ Zeroed ? AggValueSlot::IsZeroed : AggValueSlot::IsNotZeroed);
EmitAggExpr(init, slot);
return;
diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp
index f90d9439af25..11f54d1f7fb2 100644
--- a/clang/lib/CodeGen/CGBlocks.cpp
+++ b/clang/lib/CodeGen/CGBlocks.cpp
@@ -19,6 +19,7 @@
#include "CodeGenModule.h"
#include "ConstantEmitter.h"
#include "TargetInfo.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclObjC.h"
#include "clang/CodeGen/ConstantInitBuilder.h"
#include "llvm/ADT/SmallSet.h"
@@ -1076,7 +1077,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
/*RefersToEnclosingVariableOrCapture*/ CI.isNested(),
type.getNonReferenceType(), VK_LValue,
SourceLocation());
- src = EmitDeclRefLValue(&declRef).getAddress();
+ src = EmitDeclRefLValue(&declRef).getAddress(*this);
};
// For byrefs, we just write the pointer to the byref struct into
@@ -1482,8 +1483,7 @@ void CodeGenFunction::setBlockContextParameter(const ImplicitParamDecl *D,
Address alloc = CreateMemTemp(D->getType(), D->getName() + ".addr");
Builder.CreateStore(arg, alloc);
if (CGDebugInfo *DI = getDebugInfo()) {
- if (CGM.getCodeGenOpts().getDebugInfo() >=
- codegenoptions::LimitedDebugInfo) {
+ if (CGM.getCodeGenOpts().hasReducedDebugInfo()) {
DI->setLocation(D->getLocation());
DI->EmitDeclareOfBlockLiteralArgVariable(
*BlockInfo, D->getName(), argNum,
@@ -1655,8 +1655,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
const VarDecl *variable = CI.getVariable();
DI->EmitLocation(Builder, variable->getLocation());
- if (CGM.getCodeGenOpts().getDebugInfo() >=
- codegenoptions::LimitedDebugInfo) {
+ if (CGM.getCodeGenOpts().hasReducedDebugInfo()) {
const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
if (capture.isConstant()) {
auto addr = LocalDeclMap.find(variable)->second;
diff --git a/clang/lib/CodeGen/CGBuilder.h b/clang/lib/CodeGen/CGBuilder.h
index 68c8c641139f..107c9275431c 100644
--- a/clang/lib/CodeGen/CGBuilder.h
+++ b/clang/lib/CodeGen/CGBuilder.h
@@ -107,7 +107,7 @@ public:
llvm::StoreInst *CreateStore(llvm::Value *Val, Address Addr,
bool IsVolatile = false) {
return CreateAlignedStore(Val, Addr.getPointer(),
- Addr.getAlignment().getQuantity(), IsVolatile);
+ Addr.getAlignment().getAsAlign(), IsVolatile);
}
using CGBuilderBaseTy::CreateAlignedStore;
@@ -273,22 +273,22 @@ public:
using CGBuilderBaseTy::CreateMemCpy;
llvm::CallInst *CreateMemCpy(Address Dest, Address Src, llvm::Value *Size,
bool IsVolatile = false) {
- return CreateMemCpy(Dest.getPointer(), Dest.getAlignment().getQuantity(),
- Src.getPointer(), Src.getAlignment().getQuantity(),
- Size,IsVolatile);
+ return CreateMemCpy(Dest.getPointer(), Dest.getAlignment().getAsAlign(),
+ Src.getPointer(), Src.getAlignment().getAsAlign(), Size,
+ IsVolatile);
}
llvm::CallInst *CreateMemCpy(Address Dest, Address Src, uint64_t Size,
bool IsVolatile = false) {
- return CreateMemCpy(Dest.getPointer(), Dest.getAlignment().getQuantity(),
- Src.getPointer(), Src.getAlignment().getQuantity(),
- Size, IsVolatile);
+ return CreateMemCpy(Dest.getPointer(), Dest.getAlignment().getAsAlign(),
+ Src.getPointer(), Src.getAlignment().getAsAlign(), Size,
+ IsVolatile);
}
using CGBuilderBaseTy::CreateMemMove;
llvm::CallInst *CreateMemMove(Address Dest, Address Src, llvm::Value *Size,
bool IsVolatile = false) {
- return CreateMemMove(Dest.getPointer(), Dest.getAlignment().getQuantity(),
- Src.getPointer(), Src.getAlignment().getQuantity(),
+ return CreateMemMove(Dest.getPointer(), Dest.getAlignment().getAsAlign(),
+ Src.getPointer(), Src.getAlignment().getAsAlign(),
Size, IsVolatile);
}
@@ -296,7 +296,7 @@ public:
llvm::CallInst *CreateMemSet(Address Dest, llvm::Value *Value,
llvm::Value *Size, bool IsVolatile = false) {
return CreateMemSet(Dest.getPointer(), Value, Size,
- Dest.getAlignment().getQuantity(), IsVolatile);
+ Dest.getAlignment().getAsAlign(), IsVolatile);
}
using CGBuilderBaseTy::CreatePreserveStructAccessIndex;
@@ -309,7 +309,7 @@ public:
const llvm::StructLayout *Layout = DL.getStructLayout(ElTy);
auto Offset = CharUnits::fromQuantity(Layout->getElementOffset(Index));
- return Address(CreatePreserveStructAccessIndex(Addr.getPointer(),
+ return Address(CreatePreserveStructAccessIndex(ElTy, Addr.getPointer(),
Index, FieldIndex, DbgInfo),
Addr.getAlignment().alignmentAtOffset(Offset));
}
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index f9871b233149..09fd3087b494 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -20,6 +20,7 @@
#include "PatternInit.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/OSLog.h"
#include "clang/Basic/TargetBuiltins.h"
@@ -30,6 +31,17 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/IntrinsicsAArch64.h"
+#include "llvm/IR/IntrinsicsAMDGPU.h"
+#include "llvm/IR/IntrinsicsARM.h"
+#include "llvm/IR/IntrinsicsBPF.h"
+#include "llvm/IR/IntrinsicsHexagon.h"
+#include "llvm/IR/IntrinsicsNVPTX.h"
+#include "llvm/IR/IntrinsicsPowerPC.h"
+#include "llvm/IR/IntrinsicsR600.h"
+#include "llvm/IR/IntrinsicsS390.h"
+#include "llvm/IR/IntrinsicsWebAssembly.h"
+#include "llvm/IR/IntrinsicsX86.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ScopedPrinter.h"
@@ -45,7 +57,8 @@ 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, unsigned AlignmentInBytes) {
+static void initializeAlloca(CodeGenFunction &CGF, AllocaInst *AI, Value *Size,
+ Align AlignmentInBytes) {
ConstantInt *Byte;
switch (CGF.getLangOpts().getTrivialAutoVarInit()) {
case LangOptions::TrivialAutoVarInitKind::Uninitialized:
@@ -347,6 +360,58 @@ static Value *EmitISOVolatileStore(CodeGenFunction &CGF, const CallExpr *E) {
}
// Emit a simple mangled intrinsic that has 1 argument and a return type
+// matching the argument type. Depending on mode, this may be a constrained
+// floating-point intrinsic.
+static Value *emitUnaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF,
+ const CallExpr *E, unsigned IntrinsicID,
+ unsigned ConstrainedIntrinsicID) {
+ llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0));
+
+ if (CGF.Builder.getIsFPConstrained()) {
+ Function *F = CGF.CGM.getIntrinsic(ConstrainedIntrinsicID, Src0->getType());
+ return CGF.Builder.CreateConstrainedFPCall(F, { Src0 });
+ } else {
+ Function *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType());
+ return CGF.Builder.CreateCall(F, Src0);
+ }
+}
+
+// Emit an intrinsic that has 2 operands of the same type as its result.
+// Depending on mode, this may be a constrained floating-point intrinsic.
+static Value *emitBinaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF,
+ const CallExpr *E, unsigned IntrinsicID,
+ unsigned ConstrainedIntrinsicID) {
+ llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0));
+ llvm::Value *Src1 = CGF.EmitScalarExpr(E->getArg(1));
+
+ if (CGF.Builder.getIsFPConstrained()) {
+ Function *F = CGF.CGM.getIntrinsic(ConstrainedIntrinsicID, Src0->getType());
+ return CGF.Builder.CreateConstrainedFPCall(F, { Src0, Src1 });
+ } else {
+ Function *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType());
+ return CGF.Builder.CreateCall(F, { Src0, Src1 });
+ }
+}
+
+// Emit an intrinsic that has 3 operands of the same type as its result.
+// Depending on mode, this may be a constrained floating-point intrinsic.
+static Value *emitTernaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF,
+ const CallExpr *E, unsigned IntrinsicID,
+ unsigned ConstrainedIntrinsicID) {
+ llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0));
+ llvm::Value *Src1 = CGF.EmitScalarExpr(E->getArg(1));
+ llvm::Value *Src2 = CGF.EmitScalarExpr(E->getArg(2));
+
+ if (CGF.Builder.getIsFPConstrained()) {
+ Function *F = CGF.CGM.getIntrinsic(ConstrainedIntrinsicID, Src0->getType());
+ return CGF.Builder.CreateConstrainedFPCall(F, { Src0, Src1, Src2 });
+ } else {
+ Function *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType());
+ return CGF.Builder.CreateCall(F, { Src0, Src1, Src2 });
+ }
+}
+
+// Emit a simple mangled intrinsic that has 1 argument and a return type
// matching the argument type.
static Value *emitUnaryBuiltin(CodeGenFunction &CGF,
const CallExpr *E,
@@ -392,15 +457,22 @@ static Value *emitFPIntBuiltin(CodeGenFunction &CGF,
}
// Emit an intrinsic that has overloaded integer result and fp operand.
-static Value *emitFPToIntRoundBuiltin(CodeGenFunction &CGF,
- const CallExpr *E,
- unsigned IntrinsicID) {
- llvm::Type *ResultType = CGF.ConvertType(E->getType());
- llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0));
+static Value *
+emitMaybeConstrainedFPToIntRoundBuiltin(CodeGenFunction &CGF, const CallExpr *E,
+ unsigned IntrinsicID,
+ unsigned ConstrainedIntrinsicID) {
+ llvm::Type *ResultType = CGF.ConvertType(E->getType());
+ llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0));
- Function *F = CGF.CGM.getIntrinsic(IntrinsicID,
- {ResultType, Src0->getType()});
- return CGF.Builder.CreateCall(F, Src0);
+ if (CGF.Builder.getIsFPConstrained()) {
+ Function *F = CGF.CGM.getIntrinsic(ConstrainedIntrinsicID,
+ {ResultType, Src0->getType()});
+ return CGF.Builder.CreateConstrainedFPCall(F, {Src0});
+ } else {
+ Function *F =
+ CGF.CGM.getIntrinsic(IntrinsicID, {ResultType, Src0->getType()});
+ return CGF.Builder.CreateCall(F, Src0);
+ }
}
/// EmitFAbs - Emit a call to @llvm.fabs().
@@ -749,8 +821,7 @@ static llvm::Value *EmitBitTestIntrinsic(CodeGenFunction &CGF,
// X86 has special BT, BTC, BTR, and BTS instructions that handle the array
// indexing operation internally. Use them if possible.
- llvm::Triple::ArchType Arch = CGF.getTarget().getTriple().getArch();
- if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64)
+ if (CGF.getTarget().getTriple().isX86())
return EmitX86BitTestIntrinsic(CGF, BT, E, BitBase, BitPos);
// Otherwise, use generic code to load one byte and test the bit. Use all but
@@ -1558,7 +1629,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_ceilf:
case Builtin::BI__builtin_ceilf16:
case Builtin::BI__builtin_ceill:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::ceil));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::ceil,
+ Intrinsic::experimental_constrained_ceil));
case Builtin::BIcopysign:
case Builtin::BIcopysignf:
@@ -1577,7 +1650,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_cosf:
case Builtin::BI__builtin_cosf16:
case Builtin::BI__builtin_cosl:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::cos));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::cos,
+ Intrinsic::experimental_constrained_cos));
case Builtin::BIexp:
case Builtin::BIexpf:
@@ -1586,7 +1661,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_expf:
case Builtin::BI__builtin_expf16:
case Builtin::BI__builtin_expl:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::exp));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::exp,
+ Intrinsic::experimental_constrained_exp));
case Builtin::BIexp2:
case Builtin::BIexp2f:
@@ -1595,7 +1672,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_exp2f:
case Builtin::BI__builtin_exp2f16:
case Builtin::BI__builtin_exp2l:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::exp2));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::exp2,
+ Intrinsic::experimental_constrained_exp2));
case Builtin::BIfabs:
case Builtin::BIfabsf:
@@ -1614,7 +1693,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_floorf:
case Builtin::BI__builtin_floorf16:
case Builtin::BI__builtin_floorl:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::floor));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::floor,
+ Intrinsic::experimental_constrained_floor));
case Builtin::BIfma:
case Builtin::BIfmaf:
@@ -1623,7 +1704,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_fmaf:
case Builtin::BI__builtin_fmaf16:
case Builtin::BI__builtin_fmal:
- return RValue::get(emitTernaryBuiltin(*this, E, Intrinsic::fma));
+ return RValue::get(emitTernaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::fma,
+ Intrinsic::experimental_constrained_fma));
case Builtin::BIfmax:
case Builtin::BIfmaxf:
@@ -1632,7 +1715,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_fmaxf:
case Builtin::BI__builtin_fmaxf16:
case Builtin::BI__builtin_fmaxl:
- return RValue::get(emitBinaryBuiltin(*this, E, Intrinsic::maxnum));
+ return RValue::get(emitBinaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::maxnum,
+ Intrinsic::experimental_constrained_maxnum));
case Builtin::BIfmin:
case Builtin::BIfminf:
@@ -1641,7 +1726,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_fminf:
case Builtin::BI__builtin_fminf16:
case Builtin::BI__builtin_fminl:
- return RValue::get(emitBinaryBuiltin(*this, E, Intrinsic::minnum));
+ return RValue::get(emitBinaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::minnum,
+ Intrinsic::experimental_constrained_minnum));
// fmod() is a special-case. It maps to the frem instruction rather than an
// LLVM intrinsic.
@@ -1664,7 +1751,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_logf:
case Builtin::BI__builtin_logf16:
case Builtin::BI__builtin_logl:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::log));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::log,
+ Intrinsic::experimental_constrained_log));
case Builtin::BIlog10:
case Builtin::BIlog10f:
@@ -1673,7 +1762,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_log10f:
case Builtin::BI__builtin_log10f16:
case Builtin::BI__builtin_log10l:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::log10));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::log10,
+ Intrinsic::experimental_constrained_log10));
case Builtin::BIlog2:
case Builtin::BIlog2f:
@@ -1682,7 +1773,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_log2f:
case Builtin::BI__builtin_log2f16:
case Builtin::BI__builtin_log2l:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::log2));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::log2,
+ Intrinsic::experimental_constrained_log2));
case Builtin::BInearbyint:
case Builtin::BInearbyintf:
@@ -1690,7 +1783,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_nearbyint:
case Builtin::BI__builtin_nearbyintf:
case Builtin::BI__builtin_nearbyintl:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::nearbyint));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::nearbyint,
+ Intrinsic::experimental_constrained_nearbyint));
case Builtin::BIpow:
case Builtin::BIpowf:
@@ -1699,7 +1794,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_powf:
case Builtin::BI__builtin_powf16:
case Builtin::BI__builtin_powl:
- return RValue::get(emitBinaryBuiltin(*this, E, Intrinsic::pow));
+ return RValue::get(emitBinaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::pow,
+ Intrinsic::experimental_constrained_pow));
case Builtin::BIrint:
case Builtin::BIrintf:
@@ -1708,7 +1805,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_rintf:
case Builtin::BI__builtin_rintf16:
case Builtin::BI__builtin_rintl:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::rint));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::rint,
+ Intrinsic::experimental_constrained_rint));
case Builtin::BIround:
case Builtin::BIroundf:
@@ -1717,7 +1816,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_roundf:
case Builtin::BI__builtin_roundf16:
case Builtin::BI__builtin_roundl:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::round));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::round,
+ Intrinsic::experimental_constrained_round));
case Builtin::BIsin:
case Builtin::BIsinf:
@@ -1726,7 +1827,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_sinf:
case Builtin::BI__builtin_sinf16:
case Builtin::BI__builtin_sinl:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::sin));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::sin,
+ Intrinsic::experimental_constrained_sin));
case Builtin::BIsqrt:
case Builtin::BIsqrtf:
@@ -1735,7 +1838,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_sqrtf:
case Builtin::BI__builtin_sqrtf16:
case Builtin::BI__builtin_sqrtl:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::sqrt));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::sqrt,
+ Intrinsic::experimental_constrained_sqrt));
case Builtin::BItrunc:
case Builtin::BItruncf:
@@ -1744,7 +1849,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_truncf:
case Builtin::BI__builtin_truncf16:
case Builtin::BI__builtin_truncl:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::trunc));
+ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E,
+ Intrinsic::trunc,
+ Intrinsic::experimental_constrained_trunc));
case Builtin::BIlround:
case Builtin::BIlroundf:
@@ -1752,7 +1859,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_lround:
case Builtin::BI__builtin_lroundf:
case Builtin::BI__builtin_lroundl:
- return RValue::get(emitFPToIntRoundBuiltin(*this, E, Intrinsic::lround));
+ return RValue::get(emitMaybeConstrainedFPToIntRoundBuiltin(
+ *this, E, Intrinsic::lround,
+ Intrinsic::experimental_constrained_lround));
case Builtin::BIllround:
case Builtin::BIllroundf:
@@ -1760,7 +1869,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_llround:
case Builtin::BI__builtin_llroundf:
case Builtin::BI__builtin_llroundl:
- return RValue::get(emitFPToIntRoundBuiltin(*this, E, Intrinsic::llround));
+ return RValue::get(emitMaybeConstrainedFPToIntRoundBuiltin(
+ *this, E, Intrinsic::llround,
+ Intrinsic::experimental_constrained_llround));
case Builtin::BIlrint:
case Builtin::BIlrintf:
@@ -1768,7 +1879,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_lrint:
case Builtin::BI__builtin_lrintf:
case Builtin::BI__builtin_lrintl:
- return RValue::get(emitFPToIntRoundBuiltin(*this, E, Intrinsic::lrint));
+ return RValue::get(emitMaybeConstrainedFPToIntRoundBuiltin(
+ *this, E, Intrinsic::lrint,
+ Intrinsic::experimental_constrained_lrint));
case Builtin::BIllrint:
case Builtin::BIllrintf:
@@ -1776,7 +1889,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_llrint:
case Builtin::BI__builtin_llrintf:
case Builtin::BI__builtin_llrintl:
- return RValue::get(emitFPToIntRoundBuiltin(*this, E, Intrinsic::llrint));
+ return RValue::get(emitMaybeConstrainedFPToIntRoundBuiltin(
+ *this, E, Intrinsic::llrint,
+ Intrinsic::experimental_constrained_llrint));
default:
break;
@@ -1822,16 +1937,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
}
case Builtin::BI__builtin_conj:
case Builtin::BI__builtin_conjf:
- case Builtin::BI__builtin_conjl: {
+ case Builtin::BI__builtin_conjl:
+ case Builtin::BIconj:
+ case Builtin::BIconjf:
+ case Builtin::BIconjl: {
ComplexPairTy ComplexVal = EmitComplexExpr(E->getArg(0));
Value *Real = ComplexVal.first;
Value *Imag = ComplexVal.second;
- Value *Zero =
- Imag->getType()->isFPOrFPVectorTy()
- ? llvm::ConstantFP::getZeroValueForNegation(Imag->getType())
- : llvm::Constant::getNullValue(Imag->getType());
-
- Imag = Builder.CreateFSub(Zero, Imag, "sub");
+ Imag = Builder.CreateFNeg(Imag, "neg");
return RValue::getComplex(std::make_pair(Real, Imag));
}
case Builtin::BI__builtin_creal:
@@ -2178,13 +2291,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_powi:
case Builtin::BI__builtin_powif:
- case Builtin::BI__builtin_powil: {
- Value *Base = EmitScalarExpr(E->getArg(0));
- Value *Exponent = EmitScalarExpr(E->getArg(1));
- llvm::Type *ArgType = Base->getType();
- Function *F = CGM.getIntrinsic(Intrinsic::powi, ArgType);
- return RValue::get(Builder.CreateCall(F, {Base, Exponent}));
- }
+ case Builtin::BI__builtin_powil:
+ return RValue::get(emitBinaryMaybeConstrainedFPBuiltin(
+ *this, E, Intrinsic::powi, Intrinsic::experimental_constrained_powi));
case Builtin::BI__builtin_isgreater:
case Builtin::BI__builtin_isgreaterequal:
@@ -2358,12 +2467,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Value *Size = EmitScalarExpr(E->getArg(0));
const TargetInfo &TI = getContext().getTargetInfo();
// The alignment of the alloca should correspond to __BIGGEST_ALIGNMENT__.
- unsigned SuitableAlignmentInBytes =
+ const Align SuitableAlignmentInBytes =
CGM.getContext()
.toCharUnitsFromBits(TI.getSuitableAlign())
- .getQuantity();
+ .getAsAlign();
AllocaInst *AI = Builder.CreateAlloca(Builder.getInt8Ty(), Size);
- AI->setAlignment(MaybeAlign(SuitableAlignmentInBytes));
+ AI->setAlignment(SuitableAlignmentInBytes);
initializeAlloca(*this, AI, Size, SuitableAlignmentInBytes);
return RValue::get(AI);
}
@@ -2373,10 +2482,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Value *AlignmentInBitsValue = EmitScalarExpr(E->getArg(1));
auto *AlignmentInBitsCI = cast<ConstantInt>(AlignmentInBitsValue);
unsigned AlignmentInBits = AlignmentInBitsCI->getZExtValue();
- unsigned AlignmentInBytes =
- CGM.getContext().toCharUnitsFromBits(AlignmentInBits).getQuantity();
+ const Align AlignmentInBytes =
+ CGM.getContext().toCharUnitsFromBits(AlignmentInBits).getAsAlign();
AllocaInst *AI = Builder.CreateAlloca(Builder.getInt8Ty(), Size);
- AI->setAlignment(MaybeAlign(AlignmentInBytes));
+ AI->setAlignment(AlignmentInBytes);
initializeAlloca(*this, AI, Size, AlignmentInBytes);
return RValue::get(AI);
}
@@ -2391,7 +2500,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(nullptr);
}
case Builtin::BImemcpy:
- case Builtin::BI__builtin_memcpy: {
+ case Builtin::BI__builtin_memcpy:
+ case Builtin::BImempcpy:
+ case Builtin::BI__builtin_mempcpy: {
Address Dest = EmitPointerWithAlignment(E->getArg(0));
Address Src = EmitPointerWithAlignment(E->getArg(1));
Value *SizeVal = EmitScalarExpr(E->getArg(2));
@@ -2400,7 +2511,11 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
EmitNonNullArgCheck(RValue::get(Src.getPointer()), E->getArg(1)->getType(),
E->getArg(1)->getExprLoc(), FD, 1);
Builder.CreateMemCpy(Dest, Src, SizeVal, false);
- return RValue::get(Dest.getPointer());
+ if (BuiltinID == Builtin::BImempcpy ||
+ BuiltinID == Builtin::BI__builtin_mempcpy)
+ return RValue::get(Builder.CreateInBoundsGEP(Dest.getPointer(), SizeVal));
+ else
+ return RValue::get(Dest.getPointer());
}
case Builtin::BI__builtin_char_memchr:
@@ -3367,7 +3482,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(Carry);
}
case Builtin::BI__builtin_addressof:
- return RValue::get(EmitLValue(E->getArg(0)).getPointer());
+ return RValue::get(EmitLValue(E->getArg(0)).getPointer(*this));
case Builtin::BI__builtin_operator_new:
return EmitBuiltinNewDeleteCall(
E->getCallee()->getType()->castAs<FunctionProtoType>(), E, false);
@@ -3375,6 +3490,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return EmitBuiltinNewDeleteCall(
E->getCallee()->getType()->castAs<FunctionProtoType>(), E, true);
+ case Builtin::BI__builtin_is_aligned:
+ return EmitBuiltinIsAligned(E);
+ case Builtin::BI__builtin_align_up:
+ return EmitBuiltinAlignTo(E, true);
+ case Builtin::BI__builtin_align_down:
+ return EmitBuiltinAlignTo(E, false);
+
case Builtin::BI__noop:
// __noop always evaluates to an integer literal zero.
return RValue::get(ConstantInt::get(IntTy, 0));
@@ -3750,8 +3872,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
llvm::Value *Queue = EmitScalarExpr(E->getArg(0));
llvm::Value *Flags = EmitScalarExpr(E->getArg(1));
LValue NDRangeL = EmitAggExprToLValue(E->getArg(2));
- llvm::Value *Range = NDRangeL.getAddress().getPointer();
- llvm::Type *RangeTy = NDRangeL.getAddress().getType();
+ llvm::Value *Range = NDRangeL.getAddress(*this).getPointer();
+ llvm::Type *RangeTy = NDRangeL.getAddress(*this).getType();
if (NumArgs == 4) {
// The most basic form of the call with parameters:
@@ -3770,7 +3892,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Builder.CreatePointerCast(Info.BlockArg, GenericVoidPtrTy);
AttrBuilder B;
- B.addByValAttr(NDRangeL.getAddress().getElementType());
+ B.addByValAttr(NDRangeL.getAddress(*this).getElementType());
llvm::AttributeList ByValAttrSet =
llvm::AttributeList::get(CGM.getModule().getContext(), 3U, B);
@@ -3955,7 +4077,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
llvm::Type *GenericVoidPtrTy = Builder.getInt8PtrTy(
getContext().getTargetAddressSpace(LangAS::opencl_generic));
LValue NDRangeL = EmitAggExprToLValue(E->getArg(0));
- llvm::Value *NDRange = NDRangeL.getAddress().getPointer();
+ llvm::Value *NDRange = NDRangeL.getAddress(*this).getPointer();
auto Info =
CGM.getOpenCLRuntime().emitOpenCLEnqueuedBlock(*this, E->getArg(1));
Value *Kernel = Builder.CreatePointerCast(Info.Kernel, GenericVoidPtrTy);
@@ -4217,9 +4339,29 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(V);
}
- // See if we have a target specific builtin that needs to be lowered.
- if (Value *V = EmitTargetBuiltinExpr(BuiltinID, E))
- return RValue::get(V);
+ // Some target-specific builtins can have aggregate return values, e.g.
+ // __builtin_arm_mve_vld2q_u32. So if the result is an aggregate, force
+ // ReturnValue to be non-null, so that the target-specific emission code can
+ // always just emit into it.
+ TypeEvaluationKind EvalKind = getEvaluationKind(E->getType());
+ if (EvalKind == TEK_Aggregate && ReturnValue.isNull()) {
+ Address DestPtr = CreateMemTemp(E->getType(), "agg.tmp");
+ ReturnValue = ReturnValueSlot(DestPtr, false);
+ }
+
+ // Now see if we can emit a target-specific builtin.
+ if (Value *V = EmitTargetBuiltinExpr(BuiltinID, E, ReturnValue)) {
+ switch (EvalKind) {
+ case TEK_Scalar:
+ return RValue::get(V);
+ case TEK_Aggregate:
+ return RValue::getAggregate(ReturnValue.getValue(),
+ ReturnValue.isVolatile());
+ case TEK_Complex:
+ llvm_unreachable("No current target builtin returns complex");
+ }
+ llvm_unreachable("Bad evaluation kind in EmitBuiltinExpr");
+ }
ErrorUnsupported(E, "builtin function");
@@ -4229,14 +4371,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
static Value *EmitTargetArchBuiltinExpr(CodeGenFunction *CGF,
unsigned BuiltinID, const CallExpr *E,
+ ReturnValueSlot ReturnValue,
llvm::Triple::ArchType Arch) {
switch (Arch) {
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumb:
case llvm::Triple::thumbeb:
- return CGF->EmitARMBuiltinExpr(BuiltinID, E, Arch);
+ return CGF->EmitARMBuiltinExpr(BuiltinID, E, ReturnValue, Arch);
case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_32:
case llvm::Triple::aarch64_be:
return CGF->EmitAArch64BuiltinExpr(BuiltinID, E, Arch);
case llvm::Triple::bpfeb:
@@ -4268,15 +4412,16 @@ static Value *EmitTargetArchBuiltinExpr(CodeGenFunction *CGF,
}
Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID,
- const CallExpr *E) {
+ const CallExpr *E,
+ ReturnValueSlot ReturnValue) {
if (getContext().BuiltinInfo.isAuxBuiltinID(BuiltinID)) {
assert(getContext().getAuxTargetInfo() && "Missing aux target info");
return EmitTargetArchBuiltinExpr(
this, getContext().BuiltinInfo.getAuxBuiltinID(BuiltinID), E,
- getContext().getAuxTargetInfo()->getTriple().getArch());
+ ReturnValue, getContext().getAuxTargetInfo()->getTriple().getArch());
}
- return EmitTargetArchBuiltinExpr(this, BuiltinID, E,
+ return EmitTargetArchBuiltinExpr(this, BuiltinID, E, ReturnValue,
getTarget().getTriple().getArch());
}
@@ -4451,6 +4596,10 @@ static const NeonIntrinsicInfo ARMSIMDIntrinsicMap [] = {
NEONMAP1(vaesmcq_v, arm_neon_aesmc, 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(vcage_v, arm_neon_vacge, 0),
NEONMAP1(vcageq_v, arm_neon_vacge, 0),
NEONMAP1(vcagt_v, arm_neon_vacgt, 0),
@@ -4618,10 +4767,10 @@ static const NeonIntrinsicInfo ARMSIMDIntrinsicMap [] = {
NEONMAP2(vpmin_v, arm_neon_vpminu, arm_neon_vpmins, Add1ArgType | UnsignedAlts),
NEONMAP1(vqabs_v, arm_neon_vqabs, Add1ArgType),
NEONMAP1(vqabsq_v, arm_neon_vqabs, Add1ArgType),
- NEONMAP2(vqadd_v, arm_neon_vqaddu, arm_neon_vqadds, Add1ArgType | UnsignedAlts),
- NEONMAP2(vqaddq_v, arm_neon_vqaddu, arm_neon_vqadds, Add1ArgType | UnsignedAlts),
- NEONMAP2(vqdmlal_v, arm_neon_vqdmull, arm_neon_vqadds, 0),
- NEONMAP2(vqdmlsl_v, arm_neon_vqdmull, arm_neon_vqsubs, 0),
+ NEONMAP2(vqadd_v, uadd_sat, sadd_sat, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vqaddq_v, uadd_sat, sadd_sat, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vqdmlal_v, arm_neon_vqdmull, sadd_sat, 0),
+ NEONMAP2(vqdmlsl_v, arm_neon_vqdmull, ssub_sat, 0),
NEONMAP1(vqdmulh_v, arm_neon_vqdmulh, Add1ArgType),
NEONMAP1(vqdmulhq_v, arm_neon_vqdmulh, Add1ArgType),
NEONMAP1(vqdmull_v, arm_neon_vqdmull, Add1ArgType),
@@ -4639,8 +4788,8 @@ static const NeonIntrinsicInfo ARMSIMDIntrinsicMap [] = {
NEONMAP2(vqshlq_v, arm_neon_vqshiftu, arm_neon_vqshifts, Add1ArgType | UnsignedAlts),
NEONMAP1(vqshlu_n_v, arm_neon_vqshiftsu, 0),
NEONMAP1(vqshluq_n_v, arm_neon_vqshiftsu, 0),
- NEONMAP2(vqsub_v, arm_neon_vqsubu, arm_neon_vqsubs, Add1ArgType | UnsignedAlts),
- NEONMAP2(vqsubq_v, arm_neon_vqsubu, arm_neon_vqsubs, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vqsub_v, usub_sat, ssub_sat, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vqsubq_v, usub_sat, ssub_sat, Add1ArgType | UnsignedAlts),
NEONMAP1(vraddhn_v, arm_neon_vraddhn, Add1ArgType),
NEONMAP2(vrecpe_v, arm_neon_vrecpe, arm_neon_vrecpe, 0),
NEONMAP2(vrecpeq_v, arm_neon_vrecpe, arm_neon_vrecpe, 0),
@@ -4724,6 +4873,10 @@ static const NeonIntrinsicInfo AArch64SIMDIntrinsicMap[] = {
NEONMAP1(vaeseq_v, aarch64_crypto_aese, 0),
NEONMAP1(vaesimcq_v, aarch64_crypto_aesimc, 0),
NEONMAP1(vaesmcq_v, aarch64_crypto_aesmc, 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(vcage_v, aarch64_neon_facge, 0),
NEONMAP1(vcageq_v, aarch64_neon_facge, 0),
NEONMAP1(vcagt_v, aarch64_neon_facgt, 0),
@@ -5453,6 +5606,11 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) };
return EmitNeonCall(CGM.getIntrinsic(LLVMIntrinsic, Tys), Ops, NameHint);
}
+ case NEON::BI__builtin_neon_vcvtx_f32_v: {
+ llvm::Type *Tys[2] = { VTy->getTruncatedElementVectorType(VTy), Ty};
+ return EmitNeonCall(CGM.getIntrinsic(LLVMIntrinsic, Tys), Ops, NameHint);
+
+ }
case NEON::BI__builtin_neon_vext_v:
case NEON::BI__builtin_neon_vextq_v: {
int CV = cast<ConstantInt>(Ops[2])->getSExtValue();
@@ -5668,7 +5826,8 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
llvm::Type *PTy = llvm::PointerType::getUnqual(VTy->getVectorElementType());
// TODO: Currently in AArch32 mode the pointer operand comes first, whereas
// in AArch64 it comes last. We may want to stick to one or another.
- if (Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::aarch64_be) {
+ if (Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::aarch64_be ||
+ Arch == llvm::Triple::aarch64_32) {
llvm::Type *Tys[2] = { VTy, PTy };
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());
return EmitNeonCall(CGM.getIntrinsic(LLVMIntrinsic, Tys), Ops, "");
@@ -6004,6 +6163,7 @@ static bool HasExtraNeonArgument(unsigned BuiltinID) {
Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
const CallExpr *E,
+ ReturnValueSlot ReturnValue,
llvm::Triple::ArchType Arch) {
if (auto Hint = GetValueForARMHint(BuiltinID))
return Hint;
@@ -6052,6 +6212,16 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
CGM.getIntrinsic(Intrinsic::bitreverse, Arg->getType()), Arg, "rbit");
}
+ if (BuiltinID == ARM::BI__builtin_arm_cls) {
+ llvm::Value *Arg = EmitScalarExpr(E->getArg(0));
+ return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::arm_cls), Arg, "cls");
+ }
+ if (BuiltinID == ARM::BI__builtin_arm_cls64) {
+ llvm::Value *Arg = EmitScalarExpr(E->getArg(0));
+ return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::arm_cls64), Arg,
+ "cls");
+ }
+
if (BuiltinID == ARM::BI__clear_cache) {
assert(E->getNumArgs() == 2 && "__clear_cache takes 2 arguments");
const FunctionDecl *FD = E->getDirectCallee();
@@ -6320,6 +6490,10 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
return EmitSpecialRegisterBuiltin(*this, E, RegisterType, ValueType, IsRead);
}
+ // Deal with MVE builtins
+ if (Value *Result = EmitARMMVEBuiltinExpr(BuiltinID, E, ReturnValue, Arch))
+ return Result;
+
// Find out if any arguments are required to be integer constant
// expressions.
unsigned ICEArguments = 0;
@@ -6769,6 +6943,152 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
}
}
+template<typename Integer>
+static Integer GetIntegerConstantValue(const Expr *E, ASTContext &Context) {
+ llvm::APSInt IntVal;
+ bool IsConst = E->isIntegerConstantExpr(IntVal, Context);
+ assert(IsConst && "Sema should have checked this was a constant");
+ (void)IsConst;
+ return IntVal.getExtValue();
+}
+
+static llvm::Value *SignOrZeroExtend(CGBuilderTy &Builder, llvm::Value *V,
+ llvm::Type *T, bool Unsigned) {
+ // Helper function called by Tablegen-constructed ARM MVE builtin codegen,
+ // which finds it convenient to specify signed/unsigned as a boolean flag.
+ return Unsigned ? Builder.CreateZExt(V, T) : Builder.CreateSExt(V, T);
+}
+
+static llvm::Value *MVEImmediateShr(CGBuilderTy &Builder, llvm::Value *V,
+ uint32_t Shift, bool Unsigned) {
+ // MVE helper function for integer shift right. This must handle signed vs
+ // unsigned, and also deal specially with the case where the shift count is
+ // equal to the lane size. In LLVM IR, an LShr with that parameter would be
+ // undefined behavior, but in MVE it's legal, so we must convert it to code
+ // that is not undefined in IR.
+ unsigned LaneBits =
+ V->getType()->getVectorElementType()->getPrimitiveSizeInBits();
+ if (Shift == LaneBits) {
+ // An unsigned shift of the full lane size always generates zero, so we can
+ // simply emit a zero vector. A signed shift of the full lane size does the
+ // same thing as shifting by one bit fewer.
+ if (Unsigned)
+ return llvm::Constant::getNullValue(V->getType());
+ else
+ --Shift;
+ }
+ return Unsigned ? Builder.CreateLShr(V, Shift) : Builder.CreateAShr(V, Shift);
+}
+
+static llvm::Value *ARMMVEVectorSplat(CGBuilderTy &Builder, llvm::Value *V) {
+ // MVE-specific helper function for a vector splat, which infers the element
+ // count of the output vector by knowing that MVE vectors are all 128 bits
+ // wide.
+ unsigned Elements = 128 / V->getType()->getPrimitiveSizeInBits();
+ return Builder.CreateVectorSplat(Elements, V);
+}
+
+Value *CodeGenFunction::EmitARMMVEBuiltinExpr(unsigned BuiltinID,
+ const CallExpr *E,
+ ReturnValueSlot ReturnValue,
+ llvm::Triple::ArchType Arch) {
+ enum class CustomCodeGen { VLD24, VST24 } CustomCodeGenType;
+ Intrinsic::ID IRIntr;
+ unsigned NumVectors;
+
+ // Code autogenerated by Tablegen will handle all the simple builtins.
+ switch (BuiltinID) {
+ #include "clang/Basic/arm_mve_builtin_cg.inc"
+
+ // If we didn't match an MVE builtin id at all, go back to the
+ // main EmitARMBuiltinExpr.
+ default:
+ return nullptr;
+ }
+
+ // Anything that breaks from that switch is an MVE builtin that
+ // needs handwritten code to generate.
+
+ switch (CustomCodeGenType) {
+
+ case CustomCodeGen::VLD24: {
+ llvm::SmallVector<Value *, 4> Ops;
+ llvm::SmallVector<llvm::Type *, 4> Tys;
+
+ auto MvecCType = E->getType();
+ auto MvecLType = ConvertType(MvecCType);
+ assert(MvecLType->isStructTy() &&
+ "Return type for vld[24]q should be a struct");
+ assert(MvecLType->getStructNumElements() == 1 &&
+ "Return-type struct for vld[24]q should have one element");
+ auto MvecLTypeInner = MvecLType->getStructElementType(0);
+ assert(MvecLTypeInner->isArrayTy() &&
+ "Return-type struct for vld[24]q should contain an array");
+ assert(MvecLTypeInner->getArrayNumElements() == NumVectors &&
+ "Array member of return-type struct vld[24]q has wrong length");
+ auto VecLType = MvecLTypeInner->getArrayElementType();
+
+ Tys.push_back(VecLType);
+
+ auto Addr = E->getArg(0);
+ Ops.push_back(EmitScalarExpr(Addr));
+ Tys.push_back(ConvertType(Addr->getType()));
+
+ Function *F = CGM.getIntrinsic(IRIntr, makeArrayRef(Tys));
+ Value *LoadResult = Builder.CreateCall(F, Ops);
+ Value *MvecOut = UndefValue::get(MvecLType);
+ for (unsigned i = 0; i < NumVectors; ++i) {
+ Value *Vec = Builder.CreateExtractValue(LoadResult, i);
+ MvecOut = Builder.CreateInsertValue(MvecOut, Vec, {0, i});
+ }
+
+ if (ReturnValue.isNull())
+ return MvecOut;
+ else
+ return Builder.CreateStore(MvecOut, ReturnValue.getValue());
+ }
+
+ case CustomCodeGen::VST24: {
+ llvm::SmallVector<Value *, 4> Ops;
+ llvm::SmallVector<llvm::Type *, 4> Tys;
+
+ auto Addr = E->getArg(0);
+ Ops.push_back(EmitScalarExpr(Addr));
+ Tys.push_back(ConvertType(Addr->getType()));
+
+ auto MvecCType = E->getArg(1)->getType();
+ auto MvecLType = ConvertType(MvecCType);
+ assert(MvecLType->isStructTy() && "Data type for vst2q should be a struct");
+ assert(MvecLType->getStructNumElements() == 1 &&
+ "Data-type struct for vst2q should have one element");
+ auto MvecLTypeInner = MvecLType->getStructElementType(0);
+ assert(MvecLTypeInner->isArrayTy() &&
+ "Data-type struct for vst2q should contain an array");
+ assert(MvecLTypeInner->getArrayNumElements() == NumVectors &&
+ "Array member of return-type struct vld[24]q has wrong length");
+ auto VecLType = MvecLTypeInner->getArrayElementType();
+
+ Tys.push_back(VecLType);
+
+ AggValueSlot MvecSlot = CreateAggTemp(MvecCType);
+ EmitAggExpr(E->getArg(1), MvecSlot);
+ auto Mvec = Builder.CreateLoad(MvecSlot.getAddress());
+ for (unsigned i = 0; i < NumVectors; i++)
+ Ops.push_back(Builder.CreateExtractValue(Mvec, {0, i}));
+
+ Function *F = CGM.getIntrinsic(IRIntr, makeArrayRef(Tys));
+ Value *ToReturn = nullptr;
+ for (unsigned i = 0; i < NumVectors; i++) {
+ Ops.push_back(llvm::ConstantInt::get(Int32Ty, i));
+ ToReturn = Builder.CreateCall(F, Ops);
+ Ops.pop_back();
+ }
+ return ToReturn;
+ }
+ }
+ llvm_unreachable("unknown custom codegen type.");
+}
+
static Value *EmitAArch64TblBuiltinExpr(CodeGenFunction &CGF, unsigned BuiltinID,
const CallExpr *E,
SmallVectorImpl<Value *> &Ops,
@@ -7000,6 +7320,17 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
CGM.getIntrinsic(Intrinsic::bitreverse, Arg->getType()), Arg, "rbit");
}
+ if (BuiltinID == AArch64::BI__builtin_arm_cls) {
+ llvm::Value *Arg = EmitScalarExpr(E->getArg(0));
+ return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::aarch64_cls), Arg,
+ "cls");
+ }
+ if (BuiltinID == AArch64::BI__builtin_arm_cls64) {
+ llvm::Value *Arg = EmitScalarExpr(E->getArg(0));
+ return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::aarch64_cls64), Arg,
+ "cls");
+ }
+
if (BuiltinID == AArch64::BI__builtin_arm_jcvt) {
assert((getContext().getTypeSize(E->getType()) == 32) &&
"__jcvt of unusual size!");
@@ -9311,14 +9642,14 @@ Value *CodeGenFunction::EmitBPFBuiltinExpr(unsigned BuiltinID,
if (!getDebugInfo()) {
CGM.Error(E->getExprLoc(), "using builtin_preserve_field_info() without -g");
return IsBitField ? EmitLValue(Arg).getBitFieldPointer()
- : EmitLValue(Arg).getPointer();
+ : EmitLValue(Arg).getPointer(*this);
}
// Enable underlying preserve_*_access_index() generation.
bool OldIsInPreservedAIRegion = IsInPreservedAIRegion;
IsInPreservedAIRegion = true;
Value *FieldAddr = IsBitField ? EmitLValue(Arg).getBitFieldPointer()
- : EmitLValue(Arg).getPointer();
+ : EmitLValue(Arg).getPointer(*this);
IsInPreservedAIRegion = OldIsInPreservedAIRegion;
ConstantInt *C = cast<ConstantInt>(EmitScalarExpr(E->getArg(1)));
@@ -12175,7 +12506,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
case X86::BI__stosb: {
// We treat __stosb as a volatile memset - it may not generate "rep stosb"
// instruction, but it will create a memset that won't be optimized away.
- return Builder.CreateMemSet(Ops[0], Ops[1], Ops[2], 1, true);
+ return Builder.CreateMemSet(Ops[0], Ops[1], Ops[2], Align::None(), true);
}
case X86::BI__ud2:
// llvm.trap makes a ud2a instruction on x86.
@@ -12993,9 +13324,8 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
Value *X = EmitScalarExpr(E->getArg(0));
Value *Y = EmitScalarExpr(E->getArg(1));
Value *Z = EmitScalarExpr(E->getArg(2));
- Value *Zero = llvm::ConstantFP::getZeroValueForNegation(ResultType);
Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType);
- return Builder.CreateCall(F, {X, Y, Builder.CreateFSub(Zero, Z, "sub")});
+ return Builder.CreateCall(F, {X, Y, Builder.CreateFNeg(Z, "neg")});
}
case SystemZ::BI__builtin_s390_vfnmasb:
case SystemZ::BI__builtin_s390_vfnmadb: {
@@ -13003,9 +13333,8 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
Value *X = EmitScalarExpr(E->getArg(0));
Value *Y = EmitScalarExpr(E->getArg(1));
Value *Z = EmitScalarExpr(E->getArg(2));
- Value *Zero = llvm::ConstantFP::getZeroValueForNegation(ResultType);
Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType);
- return Builder.CreateFSub(Zero, Builder.CreateCall(F, {X, Y, Z}), "sub");
+ return Builder.CreateFNeg(Builder.CreateCall(F, {X, Y, Z}), "neg");
}
case SystemZ::BI__builtin_s390_vfnmssb:
case SystemZ::BI__builtin_s390_vfnmsdb: {
@@ -13013,10 +13342,9 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
Value *X = EmitScalarExpr(E->getArg(0));
Value *Y = EmitScalarExpr(E->getArg(1));
Value *Z = EmitScalarExpr(E->getArg(2));
- Value *Zero = llvm::ConstantFP::getZeroValueForNegation(ResultType);
Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType);
- Value *NegZ = Builder.CreateFSub(Zero, Z, "sub");
- return Builder.CreateFSub(Zero, Builder.CreateCall(F, {X, Y, NegZ}));
+ Value *NegZ = Builder.CreateFNeg(Z, "neg");
+ return Builder.CreateFNeg(Builder.CreateCall(F, {X, Y, NegZ}));
}
case SystemZ::BI__builtin_s390_vflpsb:
case SystemZ::BI__builtin_s390_vflpdb: {
@@ -13029,9 +13357,8 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
case SystemZ::BI__builtin_s390_vflndb: {
llvm::Type *ResultType = ConvertType(E->getType());
Value *X = EmitScalarExpr(E->getArg(0));
- Value *Zero = llvm::ConstantFP::getZeroValueForNegation(ResultType);
Function *F = CGM.getIntrinsic(Intrinsic::fabs, ResultType);
- return Builder.CreateFSub(Zero, Builder.CreateCall(F, X), "sub");
+ return Builder.CreateFNeg(Builder.CreateCall(F, X), "neg");
}
case SystemZ::BI__builtin_s390_vfisb:
case SystemZ::BI__builtin_s390_vfidb: {
@@ -13933,6 +14260,96 @@ CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID, const CallExpr *E) {
}
}
+namespace {
+struct BuiltinAlignArgs {
+ llvm::Value *Src = nullptr;
+ llvm::Type *SrcType = nullptr;
+ llvm::Value *Alignment = nullptr;
+ llvm::Value *Mask = nullptr;
+ llvm::IntegerType *IntType = nullptr;
+
+ BuiltinAlignArgs(const CallExpr *E, CodeGenFunction &CGF) {
+ QualType AstType = E->getArg(0)->getType();
+ if (AstType->isArrayType())
+ Src = CGF.EmitArrayToPointerDecay(E->getArg(0)).getPointer();
+ else
+ Src = CGF.EmitScalarExpr(E->getArg(0));
+ SrcType = Src->getType();
+ if (SrcType->isPointerTy()) {
+ IntType = IntegerType::get(
+ CGF.getLLVMContext(),
+ CGF.CGM.getDataLayout().getIndexTypeSizeInBits(SrcType));
+ } else {
+ assert(SrcType->isIntegerTy());
+ IntType = cast<llvm::IntegerType>(SrcType);
+ }
+ Alignment = CGF.EmitScalarExpr(E->getArg(1));
+ Alignment = CGF.Builder.CreateZExtOrTrunc(Alignment, IntType, "alignment");
+ auto *One = llvm::ConstantInt::get(IntType, 1);
+ Mask = CGF.Builder.CreateSub(Alignment, One, "mask");
+ }
+};
+} // namespace
+
+/// Generate (x & (y-1)) == 0.
+RValue CodeGenFunction::EmitBuiltinIsAligned(const CallExpr *E) {
+ BuiltinAlignArgs Args(E, *this);
+ llvm::Value *SrcAddress = Args.Src;
+ if (Args.SrcType->isPointerTy())
+ SrcAddress =
+ Builder.CreateBitOrPointerCast(Args.Src, Args.IntType, "src_addr");
+ return RValue::get(Builder.CreateICmpEQ(
+ Builder.CreateAnd(SrcAddress, Args.Mask, "set_bits"),
+ llvm::Constant::getNullValue(Args.IntType), "is_aligned"));
+}
+
+/// Generate (x & ~(y-1)) to align down or ((x+(y-1)) & ~(y-1)) to align up.
+/// Note: For pointer types we can avoid ptrtoint/inttoptr pairs by using the
+/// llvm.ptrmask instrinsic (with a GEP before in the align_up case).
+/// TODO: actually use ptrmask once most optimization passes know about it.
+RValue CodeGenFunction::EmitBuiltinAlignTo(const CallExpr *E, bool AlignUp) {
+ BuiltinAlignArgs Args(E, *this);
+ llvm::Value *SrcAddr = Args.Src;
+ if (Args.Src->getType()->isPointerTy())
+ SrcAddr = Builder.CreatePtrToInt(Args.Src, Args.IntType, "intptr");
+ llvm::Value *SrcForMask = SrcAddr;
+ if (AlignUp) {
+ // When aligning up we have to first add the mask to ensure we go over the
+ // next alignment value and then align down to the next valid multiple.
+ // By adding the mask, we ensure that align_up on an already aligned
+ // value will not change the value.
+ SrcForMask = Builder.CreateAdd(SrcForMask, Args.Mask, "over_boundary");
+ }
+ // Invert the mask to only clear the lower bits.
+ llvm::Value *InvertedMask = Builder.CreateNot(Args.Mask, "inverted_mask");
+ llvm::Value *Result =
+ Builder.CreateAnd(SrcForMask, InvertedMask, "aligned_result");
+ if (Args.Src->getType()->isPointerTy()) {
+ /// TODO: Use ptrmask instead of ptrtoint+gep once it is optimized well.
+ // Result = Builder.CreateIntrinsic(
+ // Intrinsic::ptrmask, {Args.SrcType, SrcForMask->getType(), Args.IntType},
+ // {SrcForMask, NegatedMask}, nullptr, "aligned_result");
+ Result->setName("aligned_intptr");
+ llvm::Value *Difference = Builder.CreateSub(Result, SrcAddr, "diff");
+ // The result must point to the same underlying allocation. This means we
+ // can use an inbounds GEP to enable better optimization.
+ Value *Base = EmitCastToVoidPtr(Args.Src);
+ if (getLangOpts().isSignedOverflowDefined())
+ Result = Builder.CreateGEP(Base, Difference, "aligned_result");
+ else
+ Result = EmitCheckedInBoundsGEP(Base, Difference,
+ /*SignedIndices=*/true,
+ /*isSubtraction=*/!AlignUp,
+ E->getExprLoc(), "aligned_result");
+ Result = Builder.CreatePointerCast(Result, Args.SrcType);
+ // Emit an alignment assumption to ensure that the new alignment is
+ // propagated to loads/stores, etc.
+ EmitAlignmentAssumption(Result, E, E->getExprLoc(), Args.Alignment);
+ }
+ assert(Result->getType() == Args.SrcType);
+ return RValue::get(Result);
+}
+
Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
switch (BuiltinID) {
@@ -14181,6 +14598,14 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
Function *Callee = CGM.getIntrinsic(IntNo, ConvertType(E->getType()));
return Builder.CreateCall(Callee, {LHS, RHS});
}
+ case WebAssembly::BI__builtin_wasm_avgr_u_i8x16:
+ case WebAssembly::BI__builtin_wasm_avgr_u_i16x8: {
+ Value *LHS = EmitScalarExpr(E->getArg(0));
+ Value *RHS = EmitScalarExpr(E->getArg(1));
+ Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_avgr_unsigned,
+ ConvertType(E->getType()));
+ return Builder.CreateCall(Callee, {LHS, RHS});
+ }
case WebAssembly::BI__builtin_wasm_bitselect: {
Value *V1 = EmitScalarExpr(E->getArg(0));
Value *V2 = EmitScalarExpr(E->getArg(1));
@@ -14189,6 +14614,12 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
ConvertType(E->getType()));
return Builder.CreateCall(Callee, {V1, V2, C});
}
+ case WebAssembly::BI__builtin_wasm_dot_s_i32x4_i16x8: {
+ Value *LHS = EmitScalarExpr(E->getArg(0));
+ Value *RHS = EmitScalarExpr(E->getArg(1));
+ Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_dot);
+ return Builder.CreateCall(Callee, {LHS, RHS});
+ }
case WebAssembly::BI__builtin_wasm_any_true_i8x16:
case WebAssembly::BI__builtin_wasm_any_true_i16x8:
case WebAssembly::BI__builtin_wasm_any_true_i32x4:
diff --git a/clang/lib/CodeGen/CGCXX.cpp b/clang/lib/CodeGen/CGCXX.cpp
index 7e5fe0fd6b1d..1928e0df3809 100644
--- a/clang/lib/CodeGen/CGCXX.cpp
+++ b/clang/lib/CodeGen/CGCXX.cpp
@@ -12,10 +12,11 @@
// We might split this into multiple files if it gets too unwieldy
-#include "CodeGenModule.h"
#include "CGCXXABI.h"
#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
diff --git a/clang/lib/CodeGen/CGCXXABI.cpp b/clang/lib/CodeGen/CGCXXABI.cpp
index 23dae2b61d04..7ada4032b3ee 100644
--- a/clang/lib/CodeGen/CGCXXABI.cpp
+++ b/clang/lib/CodeGen/CGCXXABI.cpp
@@ -13,6 +13,7 @@
#include "CGCXXABI.h"
#include "CGCleanup.h"
+#include "clang/AST/Attr.h"
using namespace clang;
using namespace CodeGen;
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index b74f6f942426..e4803fde230f 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -19,6 +19,7 @@
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "TargetInfo.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -28,7 +29,6 @@
#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/CodeGen/SwiftCallingConv.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/CallingConv.h"
@@ -36,6 +36,7 @@
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
+#include "llvm/Transforms/Utils/Local.h"
using namespace clang;
using namespace CodeGen;
@@ -1020,13 +1021,13 @@ void CodeGenFunction::ExpandTypeFromArgs(
auto Exp = getTypeExpansion(Ty, getContext());
if (auto CAExp = dyn_cast<ConstantArrayExpansion>(Exp.get())) {
- forConstantArrayExpansion(*this, CAExp, LV.getAddress(),
- [&](Address EltAddr) {
- LValue LV = MakeAddrLValue(EltAddr, CAExp->EltTy);
- ExpandTypeFromArgs(CAExp->EltTy, LV, AI);
- });
+ forConstantArrayExpansion(
+ *this, CAExp, LV.getAddress(*this), [&](Address EltAddr) {
+ LValue LV = MakeAddrLValue(EltAddr, CAExp->EltTy);
+ ExpandTypeFromArgs(CAExp->EltTy, LV, AI);
+ });
} else if (auto RExp = dyn_cast<RecordExpansion>(Exp.get())) {
- Address This = LV.getAddress();
+ Address This = LV.getAddress(*this);
for (const CXXBaseSpecifier *BS : RExp->Bases) {
// Perform a single step derived-to-base conversion.
Address Base =
@@ -1047,8 +1048,13 @@ void CodeGenFunction::ExpandTypeFromArgs(
auto imagValue = *AI++;
EmitStoreOfComplex(ComplexPairTy(realValue, imagValue), LV, /*init*/ true);
} else {
+ // Call EmitStoreOfScalar except when the lvalue is a bitfield to emit a
+ // primitive store.
assert(isa<NoExpansion>(Exp.get()));
- EmitStoreThroughLValue(RValue::get(*AI++), LV);
+ if (LV.isBitField())
+ EmitStoreThroughLValue(RValue::get(*AI++), LV);
+ else
+ EmitStoreOfScalar(*AI++, LV);
}
}
@@ -1057,7 +1063,7 @@ void CodeGenFunction::ExpandTypeToArgs(
SmallVectorImpl<llvm::Value *> &IRCallArgs, unsigned &IRCallArgPos) {
auto Exp = getTypeExpansion(Ty, getContext());
if (auto CAExp = dyn_cast<ConstantArrayExpansion>(Exp.get())) {
- Address Addr = Arg.hasLValue() ? Arg.getKnownLValue().getAddress()
+ Address Addr = Arg.hasLValue() ? Arg.getKnownLValue().getAddress(*this)
: Arg.getKnownRValue().getAggregateAddress();
forConstantArrayExpansion(
*this, CAExp, Addr, [&](Address EltAddr) {
@@ -1068,7 +1074,7 @@ void CodeGenFunction::ExpandTypeToArgs(
IRCallArgPos);
});
} else if (auto RExp = dyn_cast<RecordExpansion>(Exp.get())) {
- Address This = Arg.hasLValue() ? Arg.getKnownLValue().getAddress()
+ Address This = Arg.hasLValue() ? Arg.getKnownLValue().getAddress(*this)
: Arg.getKnownRValue().getAggregateAddress();
for (const CXXBaseSpecifier *BS : RExp->Bases) {
// Perform a single step derived-to-base conversion.
@@ -1305,6 +1311,15 @@ static void CreateCoercedStore(llvm::Value *Src,
DstTy = Dst.getType()->getElementType();
}
+ llvm::PointerType *SrcPtrTy = llvm::dyn_cast<llvm::PointerType>(SrcTy);
+ llvm::PointerType *DstPtrTy = llvm::dyn_cast<llvm::PointerType>(DstTy);
+ if (SrcPtrTy && DstPtrTy &&
+ SrcPtrTy->getAddressSpace() != DstPtrTy->getAddressSpace()) {
+ Src = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Src, DstTy);
+ CGF.Builder.CreateStore(Src, Dst, DstIsVolatile);
+ return;
+ }
+
// If the source and destination are integer or pointer types, just do an
// extension or truncation to the desired type.
if ((isa<llvm::IntegerType>(SrcTy) || isa<llvm::PointerType>(SrcTy)) &&
@@ -1732,8 +1747,9 @@ void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone,
if (CodeGenOpts.NullPointerIsValid)
FuncAttrs.addAttribute("null-pointer-is-valid", "true");
- if (!CodeGenOpts.FPDenormalMode.empty())
- FuncAttrs.addAttribute("denormal-fp-math", CodeGenOpts.FPDenormalMode);
+ if (CodeGenOpts.FPDenormalMode != llvm::DenormalMode::Invalid)
+ FuncAttrs.addAttribute("denormal-fp-math",
+ llvm::denormalModeName(CodeGenOpts.FPDenormalMode));
FuncAttrs.addAttribute("no-trapping-math",
llvm::toStringRef(CodeGenOpts.NoTrappingMath));
@@ -1853,11 +1869,30 @@ void CodeGenModule::ConstructAttributeList(
if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
AddAttributesFromFunctionProtoType(
getContext(), FuncAttrs, Fn->getType()->getAs<FunctionProtoType>());
- // Don't use [[noreturn]] or _Noreturn for a call to a virtual function.
- // These attributes are not inherited by overloads.
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn);
- if (Fn->isNoReturn() && !(AttrOnCallSite && MD && MD->isVirtual()))
- FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
+ const bool IsVirtualCall = MD && MD->isVirtual();
+ // Don't use [[noreturn]], _Noreturn or [[no_builtin]] for a call to a
+ // virtual function. These attributes are not inherited by overloads.
+ if (!(AttrOnCallSite && IsVirtualCall)) {
+ if (Fn->isNoReturn())
+ FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
+
+ const auto *NBA = Fn->getAttr<NoBuiltinAttr>();
+ bool HasWildcard = NBA && llvm::is_contained(NBA->builtinNames(), "*");
+ if (getLangOpts().NoBuiltin || HasWildcard)
+ FuncAttrs.addAttribute("no-builtins");
+ else {
+ auto AddNoBuiltinAttr = [&FuncAttrs](StringRef BuiltinName) {
+ SmallString<32> AttributeName;
+ AttributeName += "no-builtin-";
+ AttributeName += BuiltinName;
+ FuncAttrs.addAttribute(AttributeName);
+ };
+ llvm::for_each(getLangOpts().NoBuiltinFuncs, AddNoBuiltinAttr);
+ if (NBA)
+ llvm::for_each(NBA->builtinNames(), AddNoBuiltinAttr);
+ }
+ }
}
// 'const', 'pure' and 'noalias' attributed functions are also nounwind.
@@ -3112,7 +3147,7 @@ static bool isProvablyNull(llvm::Value *addr) {
static void emitWriteback(CodeGenFunction &CGF,
const CallArgList::Writeback &writeback) {
const LValue &srcLV = writeback.Source;
- Address srcAddr = srcLV.getAddress();
+ Address srcAddr = srcLV.getAddress(CGF);
assert(!isProvablyNull(srcAddr.getPointer()) &&
"shouldn't have writeback for provably null argument");
@@ -3220,7 +3255,7 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
CRE->getSubExpr()->getType()->castAs<PointerType>()->getPointeeType();
srcLV = CGF.MakeAddrLValue(srcAddr, srcAddrType);
}
- Address srcAddr = srcLV.getAddress();
+ Address srcAddr = srcLV.getAddress(CGF);
// The dest and src types don't necessarily match in LLVM terms
// because of the crazy ObjC compatibility rules.
@@ -3534,7 +3569,7 @@ RValue CallArg::getRValue(CodeGenFunction &CGF) const {
CGF.EmitAggregateCopy(Copy, LV, Ty, AggValueSlot::DoesNotOverlap,
LV.isVolatile());
IsUsed = true;
- return RValue::getAggregate(Copy.getAddress());
+ return RValue::getAggregate(Copy.getAddress(CGF));
}
void CallArg::copyInto(CodeGenFunction &CGF, Address Addr) const {
@@ -3544,7 +3579,7 @@ void CallArg::copyInto(CodeGenFunction &CGF, Address Addr) const {
else if (!HasLV && RV.isComplex())
CGF.EmitStoreOfComplex(RV.getComplexVal(), Dst, /*init=*/true);
else {
- auto Addr = HasLV ? LV.getAddress() : RV.getAggregateAddress();
+ auto Addr = HasLV ? LV.getAddress(CGF) : RV.getAggregateAddress();
LValue SrcLV = CGF.MakeAddrLValue(Addr, Ty);
// We assume that call args are never copied into subobjects.
CGF.EmitAggregateCopy(Dst, SrcLV, Ty, AggValueSlot::DoesNotOverlap,
@@ -3907,7 +3942,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
if (I->isAggregate()) {
// Replace the placeholder with the appropriate argument slot GEP.
Address Addr = I->hasLValue()
- ? I->getKnownLValue().getAddress()
+ ? I->getKnownLValue().getAddress(*this)
: I->getKnownRValue().getAggregateAddress();
llvm::Instruction *Placeholder =
cast<llvm::Instruction>(Addr.getPointer());
@@ -3952,7 +3987,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// 3. If the argument is byval, but RV is not located in default
// or alloca address space.
Address Addr = I->hasLValue()
- ? I->getKnownLValue().getAddress()
+ ? I->getKnownLValue().getAddress(*this)
: I->getKnownRValue().getAggregateAddress();
llvm::Value *V = Addr.getPointer();
CharUnits Align = ArgInfo.getIndirectAlign();
@@ -3973,9 +4008,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
auto LV = I->getKnownLValue();
auto AS = LV.getAddressSpace();
- if ((!ArgInfo.getIndirectByVal() &&
- (LV.getAlignment() >=
- getContext().getTypeAlignInChars(I->Ty)))) {
+ if (!ArgInfo.getIndirectByVal() ||
+ (LV.getAlignment() < getContext().getTypeAlignInChars(I->Ty))) {
NeedCopy = true;
}
if (!getLangOpts().OpenCL) {
@@ -4039,7 +4073,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
V = I->getKnownRValue().getScalarVal();
else
V = Builder.CreateLoad(
- I->hasLValue() ? I->getKnownLValue().getAddress()
+ I->hasLValue() ? I->getKnownLValue().getAddress(*this)
: I->getKnownRValue().getAggregateAddress());
// Implement swifterror by copying into a new swifterror argument.
@@ -4082,7 +4116,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
Src = CreateMemTemp(I->Ty, "coerce");
I->copyInto(*this, Src);
} else {
- Src = I->hasLValue() ? I->getKnownLValue().getAddress()
+ Src = I->hasLValue() ? I->getKnownLValue().getAddress(*this)
: I->getKnownRValue().getAggregateAddress();
}
@@ -4137,7 +4171,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
Address addr = Address::invalid();
Address AllocaAddr = Address::invalid();
if (I->isAggregate()) {
- addr = I->hasLValue() ? I->getKnownLValue().getAddress()
+ addr = I->hasLValue() ? I->getKnownLValue().getAddress(*this)
: I->getKnownRValue().getAggregateAddress();
} else {
@@ -4305,6 +4339,13 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
Callee.getAbstractInfo(), Attrs, CallingConv,
/*AttrOnCallSite=*/true);
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl))
+ if (FD->usesFPIntrin())
+ // All calls within a strictfp function are marked strictfp
+ Attrs =
+ Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::StrictFP);
+
// Apply some call-site-specific attributes.
// TODO: work this into building the attribute set.
@@ -4354,6 +4395,13 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
SmallVector<llvm::OperandBundleDef, 1> BundleList =
getBundlesForFunclet(CalleePtr);
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl))
+ if (FD->usesFPIntrin())
+ // All calls within a strictfp function are marked strictfp
+ Attrs =
+ Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::StrictFP);
+
// Emit the actual call/invoke instruction.
llvm::CallBase *CI;
if (!InvokeDest) {
@@ -4367,6 +4415,17 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
if (callOrInvoke)
*callOrInvoke = CI;
+ // If this is within a function that has the guard(nocf) attribute and is an
+ // indirect call, add the "guard_nocf" attribute to this call to indicate that
+ // Control Flow Guard checks should not be added, even if the call is inlined.
+ if (const auto *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl)) {
+ if (const auto *A = FD->getAttr<CFGuardAttr>()) {
+ if (A->getGuard() == CFGuardAttr::GuardArg::nocf && !CI->getCalledFunction())
+ Attrs = Attrs.addAttribute(
+ getLLVMContext(), llvm::AttributeList::FunctionIndex, "guard_nocf");
+ }
+ }
+
// Apply the attributes and calling convention.
CI->setAttributes(Attrs);
CI->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
diff --git a/clang/lib/CodeGen/CGCall.h b/clang/lib/CodeGen/CGCall.h
index cc11ded704ab..34558be5adb1 100644
--- a/clang/lib/CodeGen/CGCall.h
+++ b/clang/lib/CodeGen/CGCall.h
@@ -29,14 +29,14 @@ class AttributeList;
class Function;
class Type;
class Value;
-}
+} // namespace llvm
namespace clang {
- class ASTContext;
- class Decl;
- class FunctionDecl;
- class ObjCMethodDecl;
- class VarDecl;
+class ASTContext;
+class Decl;
+class FunctionDecl;
+class ObjCMethodDecl;
+class VarDecl;
namespace CodeGen {
@@ -60,331 +60,327 @@ public:
return CalleeProtoTy;
}
const GlobalDecl getCalleeDecl() const { return CalleeDecl; }
- };
-
- /// All available information about a concrete callee.
- class CGCallee {
- enum class SpecialKind : uintptr_t {
- Invalid,
- Builtin,
- PseudoDestructor,
- Virtual,
+};
- Last = Virtual
- };
+/// All available information about a concrete callee.
+class CGCallee {
+ enum class SpecialKind : uintptr_t {
+ Invalid,
+ Builtin,
+ PseudoDestructor,
+ Virtual,
- struct BuiltinInfoStorage {
- const FunctionDecl *Decl;
- unsigned ID;
- };
- struct PseudoDestructorInfoStorage {
- const CXXPseudoDestructorExpr *Expr;
- };
- struct VirtualInfoStorage {
- const CallExpr *CE;
- GlobalDecl MD;
- Address Addr;
- llvm::FunctionType *FTy;
- };
+ Last = Virtual
+ };
- SpecialKind KindOrFunctionPointer;
- union {
- CGCalleeInfo AbstractInfo;
- BuiltinInfoStorage BuiltinInfo;
- PseudoDestructorInfoStorage PseudoDestructorInfo;
- VirtualInfoStorage VirtualInfo;
- };
+ struct BuiltinInfoStorage {
+ const FunctionDecl *Decl;
+ unsigned ID;
+ };
+ struct PseudoDestructorInfoStorage {
+ const CXXPseudoDestructorExpr *Expr;
+ };
+ struct VirtualInfoStorage {
+ const CallExpr *CE;
+ GlobalDecl MD;
+ Address Addr;
+ llvm::FunctionType *FTy;
+ };
- explicit CGCallee(SpecialKind kind) : KindOrFunctionPointer(kind) {}
+ SpecialKind KindOrFunctionPointer;
+ union {
+ CGCalleeInfo AbstractInfo;
+ BuiltinInfoStorage BuiltinInfo;
+ PseudoDestructorInfoStorage PseudoDestructorInfo;
+ VirtualInfoStorage VirtualInfo;
+ };
- CGCallee(const FunctionDecl *builtinDecl, unsigned builtinID)
- : KindOrFunctionPointer(SpecialKind::Builtin) {
- BuiltinInfo.Decl = builtinDecl;
- BuiltinInfo.ID = builtinID;
- }
+ explicit CGCallee(SpecialKind kind) : KindOrFunctionPointer(kind) {}
- public:
- CGCallee() : KindOrFunctionPointer(SpecialKind::Invalid) {}
+ CGCallee(const FunctionDecl *builtinDecl, unsigned builtinID)
+ : KindOrFunctionPointer(SpecialKind::Builtin) {
+ BuiltinInfo.Decl = builtinDecl;
+ BuiltinInfo.ID = builtinID;
+ }
- /// Construct a callee. Call this constructor directly when this
- /// isn't a direct call.
- CGCallee(const CGCalleeInfo &abstractInfo, llvm::Value *functionPtr)
- : KindOrFunctionPointer(SpecialKind(uintptr_t(functionPtr))) {
- AbstractInfo = abstractInfo;
- assert(functionPtr && "configuring callee without function pointer");
- assert(functionPtr->getType()->isPointerTy());
- assert(functionPtr->getType()->getPointerElementType()->isFunctionTy());
- }
+public:
+ CGCallee() : KindOrFunctionPointer(SpecialKind::Invalid) {}
- static CGCallee forBuiltin(unsigned builtinID,
- const FunctionDecl *builtinDecl) {
- CGCallee result(SpecialKind::Builtin);
- result.BuiltinInfo.Decl = builtinDecl;
- result.BuiltinInfo.ID = builtinID;
- return result;
- }
+ /// Construct a callee. Call this constructor directly when this
+ /// isn't a direct call.
+ CGCallee(const CGCalleeInfo &abstractInfo, llvm::Value *functionPtr)
+ : KindOrFunctionPointer(SpecialKind(uintptr_t(functionPtr))) {
+ AbstractInfo = abstractInfo;
+ assert(functionPtr && "configuring callee without function pointer");
+ assert(functionPtr->getType()->isPointerTy());
+ assert(functionPtr->getType()->getPointerElementType()->isFunctionTy());
+ }
- static CGCallee forPseudoDestructor(const CXXPseudoDestructorExpr *E) {
- CGCallee result(SpecialKind::PseudoDestructor);
- result.PseudoDestructorInfo.Expr = E;
- return result;
- }
+ static CGCallee forBuiltin(unsigned builtinID,
+ const FunctionDecl *builtinDecl) {
+ CGCallee result(SpecialKind::Builtin);
+ result.BuiltinInfo.Decl = builtinDecl;
+ result.BuiltinInfo.ID = builtinID;
+ return result;
+ }
- static CGCallee forDirect(llvm::Constant *functionPtr,
- const CGCalleeInfo &abstractInfo = CGCalleeInfo()) {
- return CGCallee(abstractInfo, functionPtr);
- }
+ static CGCallee forPseudoDestructor(const CXXPseudoDestructorExpr *E) {
+ CGCallee result(SpecialKind::PseudoDestructor);
+ result.PseudoDestructorInfo.Expr = E;
+ return result;
+ }
- static CGCallee
- forDirect(llvm::FunctionCallee functionPtr,
- const CGCalleeInfo &abstractInfo = CGCalleeInfo()) {
- return CGCallee(abstractInfo, functionPtr.getCallee());
- }
+ static CGCallee forDirect(llvm::Constant *functionPtr,
+ const CGCalleeInfo &abstractInfo = CGCalleeInfo()) {
+ return CGCallee(abstractInfo, functionPtr);
+ }
- static CGCallee forVirtual(const CallExpr *CE, GlobalDecl MD, Address Addr,
- llvm::FunctionType *FTy) {
- CGCallee result(SpecialKind::Virtual);
- result.VirtualInfo.CE = CE;
- result.VirtualInfo.MD = MD;
- result.VirtualInfo.Addr = Addr;
- result.VirtualInfo.FTy = FTy;
- return result;
- }
+ static CGCallee forDirect(llvm::FunctionCallee functionPtr,
+ const CGCalleeInfo &abstractInfo = CGCalleeInfo()) {
+ return CGCallee(abstractInfo, functionPtr.getCallee());
+ }
- bool isBuiltin() const {
- return KindOrFunctionPointer == SpecialKind::Builtin;
- }
- const FunctionDecl *getBuiltinDecl() const {
- assert(isBuiltin());
- return BuiltinInfo.Decl;
- }
- unsigned getBuiltinID() const {
- assert(isBuiltin());
- return BuiltinInfo.ID;
- }
+ static CGCallee forVirtual(const CallExpr *CE, GlobalDecl MD, Address Addr,
+ llvm::FunctionType *FTy) {
+ CGCallee result(SpecialKind::Virtual);
+ result.VirtualInfo.CE = CE;
+ result.VirtualInfo.MD = MD;
+ result.VirtualInfo.Addr = Addr;
+ result.VirtualInfo.FTy = FTy;
+ return result;
+ }
- bool isPseudoDestructor() const {
- return KindOrFunctionPointer == SpecialKind::PseudoDestructor;
- }
- const CXXPseudoDestructorExpr *getPseudoDestructorExpr() const {
- assert(isPseudoDestructor());
- return PseudoDestructorInfo.Expr;
- }
+ bool isBuiltin() const {
+ return KindOrFunctionPointer == SpecialKind::Builtin;
+ }
+ const FunctionDecl *getBuiltinDecl() const {
+ assert(isBuiltin());
+ return BuiltinInfo.Decl;
+ }
+ unsigned getBuiltinID() const {
+ assert(isBuiltin());
+ return BuiltinInfo.ID;
+ }
- bool isOrdinary() const {
- return uintptr_t(KindOrFunctionPointer) > uintptr_t(SpecialKind::Last);
- }
- CGCalleeInfo getAbstractInfo() const {
- if (isVirtual())
- return VirtualInfo.MD;
- assert(isOrdinary());
- return AbstractInfo;
- }
- llvm::Value *getFunctionPointer() const {
- assert(isOrdinary());
- return reinterpret_cast<llvm::Value*>(uintptr_t(KindOrFunctionPointer));
- }
- void setFunctionPointer(llvm::Value *functionPtr) {
- assert(isOrdinary());
- KindOrFunctionPointer = SpecialKind(uintptr_t(functionPtr));
- }
+ bool isPseudoDestructor() const {
+ return KindOrFunctionPointer == SpecialKind::PseudoDestructor;
+ }
+ const CXXPseudoDestructorExpr *getPseudoDestructorExpr() const {
+ assert(isPseudoDestructor());
+ return PseudoDestructorInfo.Expr;
+ }
- bool isVirtual() const {
- return KindOrFunctionPointer == SpecialKind::Virtual;
- }
- const CallExpr *getVirtualCallExpr() const {
- assert(isVirtual());
- return VirtualInfo.CE;
- }
- GlobalDecl getVirtualMethodDecl() const {
- assert(isVirtual());
+ bool isOrdinary() const {
+ return uintptr_t(KindOrFunctionPointer) > uintptr_t(SpecialKind::Last);
+ }
+ CGCalleeInfo getAbstractInfo() const {
+ if (isVirtual())
return VirtualInfo.MD;
- }
- Address getThisAddress() const {
- assert(isVirtual());
- return VirtualInfo.Addr;
- }
- llvm::FunctionType *getVirtualFunctionType() const {
- assert(isVirtual());
- return VirtualInfo.FTy;
- }
+ assert(isOrdinary());
+ return AbstractInfo;
+ }
+ llvm::Value *getFunctionPointer() const {
+ assert(isOrdinary());
+ return reinterpret_cast<llvm::Value *>(uintptr_t(KindOrFunctionPointer));
+ }
+ void setFunctionPointer(llvm::Value *functionPtr) {
+ assert(isOrdinary());
+ KindOrFunctionPointer = SpecialKind(uintptr_t(functionPtr));
+ }
- /// If this is a delayed callee computation of some sort, prepare
- /// a concrete callee.
- CGCallee prepareConcreteCallee(CodeGenFunction &CGF) const;
- };
+ bool isVirtual() const {
+ return KindOrFunctionPointer == SpecialKind::Virtual;
+ }
+ const CallExpr *getVirtualCallExpr() const {
+ assert(isVirtual());
+ return VirtualInfo.CE;
+ }
+ GlobalDecl getVirtualMethodDecl() const {
+ assert(isVirtual());
+ return VirtualInfo.MD;
+ }
+ Address getThisAddress() const {
+ assert(isVirtual());
+ return VirtualInfo.Addr;
+ }
+ llvm::FunctionType *getVirtualFunctionType() const {
+ assert(isVirtual());
+ return VirtualInfo.FTy;
+ }
- struct CallArg {
- private:
- union {
- RValue RV;
- LValue LV; /// The argument is semantically a load from this l-value.
- };
- bool HasLV;
+ /// If this is a delayed callee computation of some sort, prepare
+ /// a concrete callee.
+ CGCallee prepareConcreteCallee(CodeGenFunction &CGF) const;
+};
- /// A data-flow flag to make sure getRValue and/or copyInto are not
- /// called twice for duplicated IR emission.
- mutable bool IsUsed;
+struct CallArg {
+private:
+ union {
+ RValue RV;
+ LValue LV; /// The argument is semantically a load from this l-value.
+ };
+ bool HasLV;
- public:
- QualType Ty;
- CallArg(RValue rv, QualType ty)
- : RV(rv), HasLV(false), IsUsed(false), Ty(ty) {}
- CallArg(LValue lv, QualType ty)
- : LV(lv), HasLV(true), IsUsed(false), Ty(ty) {}
- bool hasLValue() const { return HasLV; }
- QualType getType() const { return Ty; }
+ /// A data-flow flag to make sure getRValue and/or copyInto are not
+ /// called twice for duplicated IR emission.
+ mutable bool IsUsed;
- /// \returns an independent RValue. If the CallArg contains an LValue,
- /// a temporary copy is returned.
- RValue getRValue(CodeGenFunction &CGF) const;
+public:
+ QualType Ty;
+ CallArg(RValue rv, QualType ty)
+ : RV(rv), HasLV(false), IsUsed(false), Ty(ty) {}
+ CallArg(LValue lv, QualType ty)
+ : LV(lv), HasLV(true), IsUsed(false), Ty(ty) {}
+ bool hasLValue() const { return HasLV; }
+ QualType getType() const { return Ty; }
- LValue getKnownLValue() const {
- assert(HasLV && !IsUsed);
- return LV;
- }
- RValue getKnownRValue() const {
- assert(!HasLV && !IsUsed);
- return RV;
- }
- void setRValue(RValue _RV) {
- assert(!HasLV);
- RV = _RV;
- }
+ /// \returns an independent RValue. If the CallArg contains an LValue,
+ /// a temporary copy is returned.
+ RValue getRValue(CodeGenFunction &CGF) const;
- bool isAggregate() const { return HasLV || RV.isAggregate(); }
+ LValue getKnownLValue() const {
+ assert(HasLV && !IsUsed);
+ return LV;
+ }
+ RValue getKnownRValue() const {
+ assert(!HasLV && !IsUsed);
+ return RV;
+ }
+ void setRValue(RValue _RV) {
+ assert(!HasLV);
+ RV = _RV;
+ }
- void copyInto(CodeGenFunction &CGF, Address A) const;
- };
+ bool isAggregate() const { return HasLV || RV.isAggregate(); }
- /// CallArgList - Type for representing both the value and type of
- /// arguments in a call.
- class CallArgList :
- public SmallVector<CallArg, 8> {
- public:
- CallArgList() : StackBase(nullptr) {}
+ void copyInto(CodeGenFunction &CGF, Address A) const;
+};
- struct Writeback {
- /// The original argument. Note that the argument l-value
- /// is potentially null.
- LValue Source;
+/// CallArgList - Type for representing both the value and type of
+/// arguments in a call.
+class CallArgList : public SmallVector<CallArg, 8> {
+public:
+ CallArgList() : StackBase(nullptr) {}
- /// The temporary alloca.
- Address Temporary;
+ struct Writeback {
+ /// The original argument. Note that the argument l-value
+ /// is potentially null.
+ LValue Source;
- /// A value to "use" after the writeback, or null.
- llvm::Value *ToUse;
- };
+ /// The temporary alloca.
+ Address Temporary;
- struct CallArgCleanup {
- EHScopeStack::stable_iterator Cleanup;
+ /// A value to "use" after the writeback, or null.
+ llvm::Value *ToUse;
+ };
- /// The "is active" insertion point. This instruction is temporary and
- /// will be removed after insertion.
- llvm::Instruction *IsActiveIP;
- };
+ struct CallArgCleanup {
+ EHScopeStack::stable_iterator Cleanup;
- void add(RValue rvalue, QualType type) { push_back(CallArg(rvalue, type)); }
+ /// The "is active" insertion point. This instruction is temporary and
+ /// will be removed after insertion.
+ llvm::Instruction *IsActiveIP;
+ };
- void addUncopiedAggregate(LValue LV, QualType type) {
- push_back(CallArg(LV, type));
- }
+ void add(RValue rvalue, QualType type) { push_back(CallArg(rvalue, type)); }
- /// Add all the arguments from another CallArgList to this one. After doing
- /// this, the old CallArgList retains its list of arguments, but must not
- /// be used to emit a call.
- void addFrom(const CallArgList &other) {
- insert(end(), other.begin(), other.end());
- Writebacks.insert(Writebacks.end(),
- other.Writebacks.begin(), other.Writebacks.end());
- CleanupsToDeactivate.insert(CleanupsToDeactivate.end(),
- other.CleanupsToDeactivate.begin(),
- other.CleanupsToDeactivate.end());
- assert(!(StackBase && other.StackBase) && "can't merge stackbases");
- if (!StackBase)
- StackBase = other.StackBase;
- }
+ void addUncopiedAggregate(LValue LV, QualType type) {
+ push_back(CallArg(LV, type));
+ }
+
+ /// Add all the arguments from another CallArgList to this one. After doing
+ /// this, the old CallArgList retains its list of arguments, but must not
+ /// be used to emit a call.
+ void addFrom(const CallArgList &other) {
+ insert(end(), other.begin(), other.end());
+ Writebacks.insert(Writebacks.end(), other.Writebacks.begin(),
+ other.Writebacks.end());
+ CleanupsToDeactivate.insert(CleanupsToDeactivate.end(),
+ other.CleanupsToDeactivate.begin(),
+ other.CleanupsToDeactivate.end());
+ assert(!(StackBase && other.StackBase) && "can't merge stackbases");
+ if (!StackBase)
+ StackBase = other.StackBase;
+ }
- void addWriteback(LValue srcLV, Address temporary,
- llvm::Value *toUse) {
- Writeback writeback = { srcLV, temporary, toUse };
- Writebacks.push_back(writeback);
- }
+ void addWriteback(LValue srcLV, Address temporary, llvm::Value *toUse) {
+ Writeback writeback = {srcLV, temporary, toUse};
+ Writebacks.push_back(writeback);
+ }
- bool hasWritebacks() const { return !Writebacks.empty(); }
+ bool hasWritebacks() const { return !Writebacks.empty(); }
- typedef llvm::iterator_range<SmallVectorImpl<Writeback>::const_iterator>
+ typedef llvm::iterator_range<SmallVectorImpl<Writeback>::const_iterator>
writeback_const_range;
- writeback_const_range writebacks() const {
- return writeback_const_range(Writebacks.begin(), Writebacks.end());
- }
+ writeback_const_range writebacks() const {
+ return writeback_const_range(Writebacks.begin(), Writebacks.end());
+ }
- void addArgCleanupDeactivation(EHScopeStack::stable_iterator Cleanup,
- llvm::Instruction *IsActiveIP) {
- CallArgCleanup ArgCleanup;
- ArgCleanup.Cleanup = Cleanup;
- ArgCleanup.IsActiveIP = IsActiveIP;
- CleanupsToDeactivate.push_back(ArgCleanup);
- }
+ void addArgCleanupDeactivation(EHScopeStack::stable_iterator Cleanup,
+ llvm::Instruction *IsActiveIP) {
+ CallArgCleanup ArgCleanup;
+ ArgCleanup.Cleanup = Cleanup;
+ ArgCleanup.IsActiveIP = IsActiveIP;
+ CleanupsToDeactivate.push_back(ArgCleanup);
+ }
- ArrayRef<CallArgCleanup> getCleanupsToDeactivate() const {
- return CleanupsToDeactivate;
- }
+ ArrayRef<CallArgCleanup> getCleanupsToDeactivate() const {
+ return CleanupsToDeactivate;
+ }
- void allocateArgumentMemory(CodeGenFunction &CGF);
- llvm::Instruction *getStackBase() const { return StackBase; }
- void freeArgumentMemory(CodeGenFunction &CGF) const;
+ void allocateArgumentMemory(CodeGenFunction &CGF);
+ llvm::Instruction *getStackBase() const { return StackBase; }
+ void freeArgumentMemory(CodeGenFunction &CGF) const;
- /// Returns if we're using an inalloca struct to pass arguments in
- /// memory.
- bool isUsingInAlloca() const { return StackBase; }
+ /// Returns if we're using an inalloca struct to pass arguments in
+ /// memory.
+ bool isUsingInAlloca() const { return StackBase; }
- private:
- SmallVector<Writeback, 1> Writebacks;
+private:
+ SmallVector<Writeback, 1> Writebacks;
- /// Deactivate these cleanups immediately before making the call. This
- /// is used to cleanup objects that are owned by the callee once the call
- /// occurs.
- SmallVector<CallArgCleanup, 1> CleanupsToDeactivate;
+ /// Deactivate these cleanups immediately before making the call. This
+ /// is used to cleanup objects that are owned by the callee once the call
+ /// occurs.
+ SmallVector<CallArgCleanup, 1> CleanupsToDeactivate;
- /// The stacksave call. It dominates all of the argument evaluation.
- llvm::CallInst *StackBase;
- };
+ /// The stacksave call. It dominates all of the argument evaluation.
+ llvm::CallInst *StackBase;
+};
- /// FunctionArgList - Type for representing both the decl and type
- /// of parameters to a function. The decl must be either a
- /// ParmVarDecl or ImplicitParamDecl.
- class FunctionArgList : public SmallVector<const VarDecl*, 16> {
- };
+/// FunctionArgList - Type for representing both the decl and type
+/// of parameters to a function. The decl must be either a
+/// ParmVarDecl or ImplicitParamDecl.
+class FunctionArgList : public SmallVector<const VarDecl *, 16> {};
- /// ReturnValueSlot - Contains the address where the return value of a
- /// function can be stored, and whether the address is volatile or not.
- class ReturnValueSlot {
- llvm::PointerIntPair<llvm::Value *, 2, unsigned int> Value;
- CharUnits Alignment;
+/// ReturnValueSlot - Contains the address where the return value of a
+/// function can be stored, and whether the address is volatile or not.
+class ReturnValueSlot {
+ llvm::PointerIntPair<llvm::Value *, 2, unsigned int> Value;
+ CharUnits Alignment;
- // Return value slot flags
- enum Flags {
- IS_VOLATILE = 0x1,
- IS_UNUSED = 0x2,
- };
+ // Return value slot flags
+ enum Flags {
+ IS_VOLATILE = 0x1,
+ IS_UNUSED = 0x2,
+ };
- public:
- ReturnValueSlot() {}
- ReturnValueSlot(Address Addr, bool IsVolatile, bool IsUnused = false)
+public:
+ ReturnValueSlot() {}
+ ReturnValueSlot(Address Addr, bool IsVolatile, bool IsUnused = false)
: Value(Addr.isValid() ? Addr.getPointer() : nullptr,
(IsVolatile ? IS_VOLATILE : 0) | (IsUnused ? IS_UNUSED : 0)),
Alignment(Addr.isValid() ? Addr.getAlignment() : CharUnits::Zero()) {}
- bool isNull() const { return !getValue().isValid(); }
+ bool isNull() const { return !getValue().isValid(); }
- bool isVolatile() const { return Value.getInt() & IS_VOLATILE; }
- Address getValue() const { return Address(Value.getPointer(), Alignment); }
- bool isUnused() const { return Value.getInt() & IS_UNUSED; }
- };
+ bool isVolatile() const { return Value.getInt() & IS_VOLATILE; }
+ Address getValue() const { return Address(Value.getPointer(), Alignment); }
+ bool isUnused() const { return Value.getInt() & IS_UNUSED; }
+};
-} // end namespace CodeGen
-} // end namespace clang
+} // end namespace CodeGen
+} // end namespace clang
#endif
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index 04ef912b18bd..3f3825b76275 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -16,6 +16,7 @@
#include "CGRecordLayout.h"
#include "CodeGenFunction.h"
#include "TargetInfo.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/EvaluatedExprVisitor.h"
@@ -657,7 +658,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
// the constructor.
QualType::DestructionKind dtorKind = FieldType.isDestructedType();
if (CGF.needsEHCleanup(dtorKind))
- CGF.pushEHDestroy(dtorKind, LHS.getAddress(), FieldType);
+ CGF.pushEHDestroy(dtorKind, LHS.getAddress(CGF), FieldType);
return;
}
}
@@ -681,16 +682,12 @@ void CodeGenFunction::EmitInitializerForField(FieldDecl *Field, LValue LHS,
EmitComplexExprIntoLValue(Init, LHS, /*isInit*/ true);
break;
case TEK_Aggregate: {
- AggValueSlot Slot =
- AggValueSlot::forLValue(
- LHS,
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- getOverlapForFieldInit(Field),
- AggValueSlot::IsNotZeroed,
- // Checks are made by the code that calls constructor.
- AggValueSlot::IsSanitizerChecked);
+ AggValueSlot Slot = AggValueSlot::forLValue(
+ LHS, *this, AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased,
+ getOverlapForFieldInit(Field), AggValueSlot::IsNotZeroed,
+ // Checks are made by the code that calls constructor.
+ AggValueSlot::IsSanitizerChecked);
EmitAggExpr(Init, Slot);
break;
}
@@ -700,7 +697,7 @@ void CodeGenFunction::EmitInitializerForField(FieldDecl *Field, LValue LHS,
// later in the constructor.
QualType::DestructionKind dtorKind = FieldType.isDestructedType();
if (needsEHCleanup(dtorKind))
- pushEHDestroy(dtorKind, LHS.getAddress(), FieldType);
+ pushEHDestroy(dtorKind, LHS.getAddress(*this), FieldType);
}
/// Checks whether the given constructor is a valid subject for the
@@ -914,6 +911,8 @@ namespace {
}
void addMemcpyableField(FieldDecl *F) {
+ if (F->isZeroSize(CGF.getContext()))
+ return;
if (!FirstField)
addInitialField(F);
else
@@ -961,9 +960,10 @@ namespace {
LValue SrcLV = CGF.MakeNaturalAlignAddrLValue(SrcPtr, RecordTy);
LValue Src = CGF.EmitLValueForFieldInitialization(SrcLV, FirstField);
- emitMemcpyIR(Dest.isBitField() ? Dest.getBitFieldAddress() : Dest.getAddress(),
- Src.isBitField() ? Src.getBitFieldAddress() : Src.getAddress(),
- MemcpySize);
+ emitMemcpyIR(
+ Dest.isBitField() ? Dest.getBitFieldAddress() : Dest.getAddress(CGF),
+ Src.isBitField() ? Src.getBitFieldAddress() : Src.getAddress(CGF),
+ MemcpySize);
reset();
}
@@ -1117,7 +1117,7 @@ namespace {
continue;
LValue FieldLHS = LHS;
EmitLValueForAnyFieldInitialization(CGF, MemberInit, FieldLHS);
- CGF.pushEHDestroy(dtorKind, FieldLHS.getAddress(), FieldType);
+ CGF.pushEHDestroy(dtorKind, FieldLHS.getAddress(CGF), FieldType);
}
}
@@ -1627,7 +1627,7 @@ namespace {
LValue LV = CGF.EmitLValueForField(ThisLV, field);
assert(LV.isSimple());
- CGF.emitDestroy(LV.getAddress(), field->getType(), destroyer,
+ CGF.emitDestroy(LV.getAddress(CGF), field->getType(), destroyer,
flags.isForNormalCleanup() && useEHCleanupForArray);
}
};
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 7c63743f3b43..cbd524eda9d0 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -18,8 +18,8 @@
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "ConstantEmitter.h"
-#include "clang/Analysis/Analyses/ExprMutationAnalyzer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -46,6 +46,7 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/TimeProfiler.h"
using namespace clang;
using namespace clang::CodeGen;
@@ -235,8 +236,7 @@ PrintingPolicy CGDebugInfo::getPrintingPolicy() const {
PP.MSVCFormatting = true;
// Apply -fdebug-prefix-map.
- PP.RemapFilePaths = true;
- PP.remapPath = [this](StringRef Path) { return remapDIPath(Path); };
+ PP.Callbacks = &PrintCB;
return PP;
}
@@ -293,13 +293,6 @@ StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) {
}
} else if (const auto *OCD = dyn_cast<ObjCCategoryImplDecl>(DC)) {
OS << OCD->getClassInterface()->getName() << '(' << OCD->getName() << ')';
- } else if (isa<ObjCProtocolDecl>(DC)) {
- // We can extract the type of the class from the self pointer.
- if (ImplicitParamDecl *SelfDecl = OMD->getSelfDecl()) {
- QualType ClassTy =
- cast<ObjCObjectPointerType>(SelfDecl->getType())->getPointeeType();
- ClassTy.print(OS, PrintingPolicy(LangOptions()));
- }
}
OS << ' ' << OMD->getSelector().getAsString() << ']';
@@ -598,6 +591,7 @@ void CGDebugInfo::CreateCompileUnit() {
case codegenoptions::DebugDirectivesOnly:
EmissionKind = llvm::DICompileUnit::DebugDirectivesOnly;
break;
+ case codegenoptions::DebugInfoConstructor:
case codegenoptions::LimitedDebugInfo:
case codegenoptions::FullDebugInfo:
EmissionKind = llvm::DICompileUnit::FullDebug;
@@ -1142,10 +1136,11 @@ llvm::DIType *CGDebugInfo::CreateType(const TypedefType *Ty,
// declared.
SourceLocation Loc = Ty->getDecl()->getLocation();
+ uint32_t Align = getDeclAlignIfRequired(Ty->getDecl(), CGM.getContext());
// Typedefs are derived from some other type.
return DBuilder.createTypedef(Underlying, Ty->getDecl()->getName(),
getOrCreateFile(Loc), getLineNumber(Loc),
- getDeclContextDescriptor(Ty->getDecl()));
+ getDeclContextDescriptor(Ty->getDecl()), Align);
}
static unsigned getDwarfCC(CallingConv CC) {
@@ -1607,8 +1602,31 @@ llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction(
ContainingType = RecordTy;
}
+ // We're checking for deleted C++ special member functions
+ // [Ctors,Dtors, Copy/Move]
+ auto checkAttrDeleted = [&](const auto *Method) {
+ if (Method->getCanonicalDecl()->isDeleted())
+ SPFlags |= llvm::DISubprogram::SPFlagDeleted;
+ };
+
+ switch (Method->getKind()) {
+
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ checkAttrDeleted(Method);
+ break;
+ case Decl::CXXMethod:
+ if (Method->isCopyAssignmentOperator() ||
+ Method->isMoveAssignmentOperator())
+ checkAttrDeleted(Method);
+ break;
+ default:
+ break;
+ }
+
if (Method->isNoReturn())
Flags |= llvm::DINode::FlagNoReturn;
+
if (Method->isStatic())
Flags |= llvm::DINode::FlagStaticMember;
if (Method->isImplicit())
@@ -1630,6 +1648,12 @@ llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction(
if (CGM.getLangOpts().Optimize)
SPFlags |= llvm::DISubprogram::SPFlagOptimized;
+ // In this debug mode, emit type info for a class when its constructor type
+ // info is emitted.
+ if (DebugKind == codegenoptions::DebugInfoConstructor)
+ if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(Method))
+ completeClass(CD->getParent());
+
llvm::DINodeArray TParamsArray = CollectFunctionTemplateParams(Method, Unit);
llvm::DISubprogram *SP = DBuilder.createMethod(
RecordTy, MethodName, MethodLinkageName, MethodDefUnit, MethodLine,
@@ -2026,7 +2050,7 @@ void CGDebugInfo::CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile *Unit,
llvm::DIType *CGDebugInfo::getOrCreateRecordType(QualType RTy,
SourceLocation Loc) {
- assert(DebugKind >= codegenoptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().hasReducedDebugInfo());
llvm::DIType *T = getOrCreateType(RTy, getOrCreateFile(Loc));
return T;
}
@@ -2038,7 +2062,7 @@ llvm::DIType *CGDebugInfo::getOrCreateInterfaceType(QualType D,
llvm::DIType *CGDebugInfo::getOrCreateStandaloneType(QualType D,
SourceLocation Loc) {
- assert(DebugKind >= codegenoptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().hasReducedDebugInfo());
assert(!D.isNull() && "null type");
llvm::DIType *T = getOrCreateType(D, getOrCreateFile(Loc));
assert(T && "could not create debug info for type");
@@ -2193,6 +2217,17 @@ static bool shouldOmitDefinition(codegenoptions::DebugInfoKind DebugKind,
!isClassOrMethodDLLImport(CXXDecl))
return true;
+ // In constructor debug mode, only emit debug info for a class when its
+ // constructor is emitted. Skip this optimization if the class or any of
+ // its methods are marked dllimport.
+ if (DebugKind == codegenoptions::DebugInfoConstructor &&
+ !CXXDecl->isLambda() && !isClassOrMethodDLLImport(CXXDecl)) {
+ for (const auto *Ctor : CXXDecl->ctors()) {
+ if (Ctor->isUserProvided())
+ return true;
+ }
+ }
+
TemplateSpecializationKind Spec = TSK_Undeclared;
if (const auto *SD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
Spec = SD->getSpecializationKind();
@@ -2577,8 +2612,8 @@ llvm::DIType *CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty,
SourceLocation Loc = PD->getLocation();
llvm::DIFile *PUnit = getOrCreateFile(Loc);
unsigned PLine = getLineNumber(Loc);
- ObjCMethodDecl *Getter = PD->getGetterMethodDecl();
- ObjCMethodDecl *Setter = PD->getSetterMethodDecl();
+ ObjCMethodDecl *Getter = PImpD->getGetterMethodDecl();
+ ObjCMethodDecl *Setter = PImpD->getSetterMethodDecl();
PropertyNode = DBuilder.createObjCProperty(
PD->getName(), PUnit, PLine,
hasDefaultGetterName(PD, Getter)
@@ -2711,19 +2746,17 @@ llvm::DIType *CGDebugInfo::CreateType(const MemberPointerType *Ty,
// Set the MS inheritance model. There is no flag for the unspecified model.
if (CGM.getTarget().getCXXABI().isMicrosoft()) {
switch (Ty->getMostRecentCXXRecordDecl()->getMSInheritanceModel()) {
- case MSInheritanceAttr::Keyword_single_inheritance:
+ case MSInheritanceModel::Single:
Flags |= llvm::DINode::FlagSingleInheritance;
break;
- case MSInheritanceAttr::Keyword_multiple_inheritance:
+ case MSInheritanceModel::Multiple:
Flags |= llvm::DINode::FlagMultipleInheritance;
break;
- case MSInheritanceAttr::Keyword_virtual_inheritance:
+ case MSInheritanceModel::Virtual:
Flags |= llvm::DINode::FlagVirtualInheritance;
break;
- case MSInheritanceAttr::Keyword_unspecified_inheritance:
+ case MSInheritanceModel::Unspecified:
break;
- case MSInheritanceAttr::SpellingNotCalculated:
- llvm_unreachable("Spelling not yet calculated");
}
}
}
@@ -2946,6 +2979,13 @@ llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) {
if (Ty.isNull())
return nullptr;
+ llvm::TimeTraceScope TimeScope("DebugType", [&]() {
+ std::string Name;
+ llvm::raw_string_ostream OS(Name);
+ Ty.print(OS, getPrintingPolicy());
+ return Name;
+ });
+
// Unwrap the type as needed for debug information.
Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext());
@@ -3248,7 +3288,7 @@ void CGDebugInfo::collectFunctionDeclProps(GlobalDecl GD, llvm::DIFile *Unit,
DebugKind <= codegenoptions::DebugLineTablesOnly))
LinkageName = StringRef();
- if (DebugKind >= codegenoptions::LimitedDebugInfo) {
+ if (CGM.getCodeGenOpts().hasReducedDebugInfo()) {
if (const NamespaceDecl *NSDecl =
dyn_cast_or_null<NamespaceDecl>(FD->getDeclContext()))
FDContext = getOrCreateNamespace(NSDecl);
@@ -3460,6 +3500,42 @@ llvm::DISubprogram *CGDebugInfo::getFunctionDeclaration(const Decl *D) {
return nullptr;
}
+llvm::DISubprogram *CGDebugInfo::getObjCMethodDeclaration(
+ const Decl *D, llvm::DISubroutineType *FnType, unsigned LineNo,
+ llvm::DINode::DIFlags Flags, llvm::DISubprogram::DISPFlags SPFlags) {
+ if (!D || DebugKind <= codegenoptions::DebugLineTablesOnly)
+ return nullptr;
+
+ const auto *OMD = dyn_cast<ObjCMethodDecl>(D);
+ if (!OMD)
+ return nullptr;
+
+ if (CGM.getCodeGenOpts().DwarfVersion < 5 && !OMD->isDirectMethod())
+ return nullptr;
+
+ if (OMD->isDirectMethod())
+ SPFlags |= llvm::DISubprogram::SPFlagObjCDirect;
+
+ // Starting with DWARF V5 method declarations are emitted as children of
+ // the interface type.
+ auto *ID = dyn_cast_or_null<ObjCInterfaceDecl>(D->getDeclContext());
+ if (!ID)
+ ID = OMD->getClassInterface();
+ if (!ID)
+ return nullptr;
+ QualType QTy(ID->getTypeForDecl(), 0);
+ auto It = TypeCache.find(QTy.getAsOpaquePtr());
+ if (It == TypeCache.end())
+ return nullptr;
+ auto *InterfaceType = cast<llvm::DICompositeType>(It->second);
+ llvm::DISubprogram *FD = DBuilder.createFunction(
+ InterfaceType, getObjCMethodName(OMD), StringRef(),
+ InterfaceType->getFile(), LineNo, FnType, LineNo, Flags, SPFlags);
+ DBuilder.finalizeSubprogram(FD);
+ ObjCMethodCache[ID].push_back({FD, OMD->isDirectMethod()});
+ return FD;
+}
+
// getOrCreateFunctionType - Construct type. If it is a c++ method, include
// implicit parameter "this".
llvm::DISubroutineType *CGDebugInfo::getOrCreateFunctionType(const Decl *D,
@@ -3602,6 +3678,12 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc,
unsigned LineNo = getLineNumber(Loc);
unsigned ScopeLine = getLineNumber(ScopeLoc);
+ llvm::DISubroutineType *DIFnType = getOrCreateFunctionType(D, FnType, Unit);
+ llvm::DISubprogram *Decl = nullptr;
+ if (D)
+ Decl = isa<ObjCMethodDecl>(D)
+ ? getObjCMethodDeclaration(D, DIFnType, LineNo, Flags, SPFlags)
+ : getFunctionDeclaration(D);
// FIXME: The function declaration we're constructing here is mostly reusing
// declarations from CXXMethodDecl and not constructing new ones for arbitrary
@@ -3609,9 +3691,8 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc,
// all subprograms instead of the actual context since subprogram definitions
// are emitted as CU level entities by the backend.
llvm::DISubprogram *SP = DBuilder.createFunction(
- FDContext, Name, LinkageName, Unit, LineNo,
- getOrCreateFunctionType(D, FnType, Unit), ScopeLine, FlagsForDef,
- SPFlagsForDef, TParamsArray.get(), getFunctionDeclaration(D));
+ FDContext, Name, LinkageName, Unit, LineNo, DIFnType, ScopeLine,
+ FlagsForDef, SPFlagsForDef, TParamsArray.get(), Decl);
Fn->setSubprogram(SP);
// We might get here with a VarDecl in the case we're generating
// code for the initialization of globals. Do not record these decls
@@ -3619,35 +3700,6 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc,
if (HasDecl && isa<FunctionDecl>(D))
DeclCache[D->getCanonicalDecl()].reset(SP);
- // We use the SPDefCache only in the case when the debug entry values option
- // is set, in order to speed up parameters modification analysis.
- //
- // FIXME: Use AbstractCallee here to support ObjCMethodDecl.
- if (CGM.getCodeGenOpts().EnableDebugEntryValues && HasDecl)
- if (auto *FD = dyn_cast<FunctionDecl>(D))
- if (FD->hasBody() && !FD->param_empty())
- SPDefCache[FD].reset(SP);
-
- if (CGM.getCodeGenOpts().DwarfVersion >= 5) {
- // Starting with DWARF V5 method declarations are emitted as children of
- // the interface type.
- if (const auto *OMD = dyn_cast_or_null<ObjCMethodDecl>(D)) {
- const ObjCInterfaceDecl *ID = OMD->getClassInterface();
- QualType QTy(ID->getTypeForDecl(), 0);
- auto It = TypeCache.find(QTy.getAsOpaquePtr());
- if (It != TypeCache.end()) {
- llvm::DICompositeType *InterfaceDecl =
- cast<llvm::DICompositeType>(It->second);
- llvm::DISubprogram *FD = DBuilder.createFunction(
- InterfaceDecl, Name, LinkageName, Unit, LineNo,
- getOrCreateFunctionType(D, FnType, Unit), ScopeLine, Flags, SPFlags,
- TParamsArray.get());
- DBuilder.finalizeSubprogram(FD);
- ObjCMethodCache[ID].push_back(FD);
- }
- }
- }
-
// Push the function onto the lexical block stack.
LexicalBlockStack.emplace_back(SP);
@@ -3664,6 +3716,15 @@ void CGDebugInfo::EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc,
if (!D)
return;
+ llvm::TimeTraceScope TimeScope("DebugFunction", [&]() {
+ std::string Name;
+ llvm::raw_string_ostream OS(Name);
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
+ ND->getNameForDiagnostic(OS, getPrintingPolicy(),
+ /*Qualified=*/true);
+ return Name;
+ });
+
llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
llvm::DIFile *Unit = getOrCreateFile(Loc);
bool IsDeclForCallSite = Fn ? true : false;
@@ -3709,21 +3770,29 @@ void CGDebugInfo::EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc,
void CGDebugInfo::EmitFuncDeclForCallSite(llvm::CallBase *CallOrInvoke,
QualType CalleeType,
const FunctionDecl *CalleeDecl) {
- auto &CGOpts = CGM.getCodeGenOpts();
- if (!CGOpts.EnableDebugEntryValues || !CGM.getLangOpts().Optimize ||
- !CallOrInvoke)
+ if (!CallOrInvoke)
return;
-
auto *Func = CallOrInvoke->getCalledFunction();
if (!Func)
return;
+ if (Func->getSubprogram())
+ return;
+
+ // Do not emit a declaration subprogram for a builtin 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 ||
+ getCallSiteRelatedAttrs() == llvm::DINode::FlagZero)
+ return;
+ if (const auto *Id = CalleeDecl->getIdentifier())
+ if (Id->isReservedName())
+ return;
// If there is no DISubprogram attached to the function being called,
// create the one describing the function in order to have complete
// call site debug info.
- if (Func->getSubprogram())
- return;
-
if (!CalleeDecl->isStatic() && !CalleeDecl->isInlined())
EmitFunctionDecl(CalleeDecl, CalleeDecl->getLocation(), CalleeType, Func);
}
@@ -3906,7 +3975,7 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD,
llvm::Optional<unsigned> ArgNo,
CGBuilderTy &Builder,
const bool UsePointerValue) {
- assert(DebugKind >= codegenoptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().hasReducedDebugInfo());
assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
if (VD->hasAttr<NoDebugAttr>())
return nullptr;
@@ -4033,11 +4102,6 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD,
llvm::DebugLoc::get(Line, Column, Scope, CurInlinedAt),
Builder.GetInsertBlock());
- if (CGM.getCodeGenOpts().EnableDebugEntryValues && ArgNo) {
- if (auto *PD = dyn_cast<ParmVarDecl>(VD))
- ParamCache[PD].reset(D);
- }
-
return D;
}
@@ -4045,12 +4109,12 @@ llvm::DILocalVariable *
CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD, llvm::Value *Storage,
CGBuilderTy &Builder,
const bool UsePointerValue) {
- assert(DebugKind >= codegenoptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().hasReducedDebugInfo());
return EmitDeclare(VD, Storage, llvm::None, Builder, UsePointerValue);
}
void CGDebugInfo::EmitLabel(const LabelDecl *D, CGBuilderTy &Builder) {
- assert(DebugKind >= codegenoptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().hasReducedDebugInfo());
assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
if (D->hasAttr<NoDebugAttr>())
@@ -4086,7 +4150,7 @@ llvm::DIType *CGDebugInfo::CreateSelfType(const QualType &QualTy,
void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
const VarDecl *VD, llvm::Value *Storage, CGBuilderTy &Builder,
const CGBlockInfo &blockInfo, llvm::Instruction *InsertPoint) {
- assert(DebugKind >= codegenoptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().hasReducedDebugInfo());
assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
if (Builder.GetInsertBlock() == nullptr)
@@ -4157,7 +4221,7 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI,
unsigned ArgNo,
CGBuilderTy &Builder) {
- assert(DebugKind >= codegenoptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().hasReducedDebugInfo());
EmitDeclare(VD, AI, ArgNo, Builder);
}
@@ -4214,7 +4278,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
unsigned ArgNo,
llvm::AllocaInst *Alloca,
CGBuilderTy &Builder) {
- assert(DebugKind >= codegenoptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().hasReducedDebugInfo());
ASTContext &C = CGM.getContext();
const BlockDecl *blockDecl = block.getBlockDecl();
@@ -4380,10 +4444,18 @@ llvm::DIGlobalVariableExpression *CGDebugInfo::CollectAnonRecordDecls(
void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
const VarDecl *D) {
- assert(DebugKind >= codegenoptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().hasReducedDebugInfo());
if (D->hasAttr<NoDebugAttr>())
return;
+ llvm::TimeTraceScope TimeScope("DebugGlobalVariable", [&]() {
+ std::string Name;
+ llvm::raw_string_ostream OS(Name);
+ D->getNameForDiagnostic(OS, getPrintingPolicy(),
+ /*Qualified=*/true);
+ return Name;
+ });
+
// If we already created a DIGlobalVariable for this declaration, just attach
// it to the llvm::GlobalVariable.
auto Cached = DeclCache.find(D->getCanonicalDecl());
@@ -4431,7 +4503,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
GVE = DBuilder.createGlobalVariableExpression(
DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit),
- Var->hasLocalLinkage(),
+ Var->hasLocalLinkage(), true,
Expr.empty() ? nullptr : DBuilder.createExpression(Expr),
getOrCreateStaticDataMemberDeclarationOrNull(D), TemplateParameters,
Align);
@@ -4441,9 +4513,17 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
}
void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, const APValue &Init) {
- assert(DebugKind >= codegenoptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().hasReducedDebugInfo());
if (VD->hasAttr<NoDebugAttr>())
return;
+ llvm::TimeTraceScope TimeScope("DebugConstGlobalVariable", [&]() {
+ std::string Name;
+ llvm::raw_string_ostream OS(Name);
+ VD->getNameForDiagnostic(OS, getPrintingPolicy(),
+ /*Qualified=*/true);
+ return Name;
+ });
+
auto Align = getDeclAlignIfRequired(VD, CGM.getContext());
// Create the descriptor for the variable.
llvm::DIFile *Unit = getOrCreateFile(VD->getLocation());
@@ -4526,10 +4606,29 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, const APValue &Init) {
GV.reset(DBuilder.createGlobalVariableExpression(
DContext, Name, StringRef(), Unit, getLineNumber(VD->getLocation()), Ty,
- true, InitExpr, getOrCreateStaticDataMemberDeclarationOrNull(VarD),
+ true, true, InitExpr, getOrCreateStaticDataMemberDeclarationOrNull(VarD),
TemplateParameters, Align));
}
+void CGDebugInfo::EmitExternalVariable(llvm::GlobalVariable *Var,
+ const VarDecl *D) {
+ assert(CGM.getCodeGenOpts().hasReducedDebugInfo());
+ if (D->hasAttr<NoDebugAttr>())
+ return;
+
+ auto Align = getDeclAlignIfRequired(D, CGM.getContext());
+ llvm::DIFile *Unit = getOrCreateFile(D->getLocation());
+ StringRef Name = D->getName();
+ llvm::DIType *Ty = getOrCreateType(D->getType(), Unit);
+
+ llvm::DIScope *DContext = getDeclContextDescriptor(D);
+ llvm::DIGlobalVariableExpression *GVE =
+ DBuilder.createGlobalVariableExpression(
+ DContext, Name, StringRef(), Unit, getLineNumber(D->getLocation()),
+ Ty, false, false, nullptr, nullptr, nullptr, Align);
+ Var->addDebugInfo(GVE);
+}
+
llvm::DIScope *CGDebugInfo::getCurrentContextDescriptor(const Decl *D) {
if (!LexicalBlockStack.empty())
return LexicalBlockStack.back();
@@ -4538,7 +4637,7 @@ llvm::DIScope *CGDebugInfo::getCurrentContextDescriptor(const Decl *D) {
}
void CGDebugInfo::EmitUsingDirective(const UsingDirectiveDecl &UD) {
- if (CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo)
+ if (!CGM.getCodeGenOpts().hasReducedDebugInfo())
return;
const NamespaceDecl *NSDecl = UD.getNominatedNamespace();
if (!NSDecl->isAnonymousNamespace() ||
@@ -4551,7 +4650,7 @@ void CGDebugInfo::EmitUsingDirective(const UsingDirectiveDecl &UD) {
}
void CGDebugInfo::EmitUsingDecl(const UsingDecl &UD) {
- if (CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo)
+ if (!CGM.getCodeGenOpts().hasReducedDebugInfo())
return;
assert(UD.shadow_size() &&
"We shouldn't be codegening an invalid UsingDecl containing no decls");
@@ -4592,7 +4691,7 @@ void CGDebugInfo::EmitImportDecl(const ImportDecl &ID) {
llvm::DIImportedEntity *
CGDebugInfo::EmitNamespaceAlias(const NamespaceAliasDecl &NA) {
- if (CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo)
+ if (!CGM.getCodeGenOpts().hasReducedDebugInfo())
return nullptr;
auto &VH = NamespaceAliasCache[&NA];
if (VH)
@@ -4637,29 +4736,6 @@ void CGDebugInfo::setDwoId(uint64_t Signature) {
TheCU->setDWOId(Signature);
}
-/// Analyzes each function parameter to determine whether it is constant
-/// throughout the function body.
-static void analyzeParametersModification(
- ASTContext &Ctx,
- llvm::DenseMap<const FunctionDecl *, llvm::TrackingMDRef> &SPDefCache,
- llvm::DenseMap<const ParmVarDecl *, llvm::TrackingMDRef> &ParamCache) {
- for (auto &SP : SPDefCache) {
- auto *FD = SP.first;
- assert(FD->hasBody() && "Functions must have body here");
- const Stmt *FuncBody = (*FD).getBody();
- for (auto Parm : FD->parameters()) {
- ExprMutationAnalyzer FuncAnalyzer(*FuncBody, Ctx);
- if (FuncAnalyzer.isMutated(Parm))
- continue;
-
- auto I = ParamCache.find(Parm);
- assert(I != ParamCache.end() && "Parameters should be already cached");
- auto *DIParm = cast<llvm::DILocalVariable>(I->second);
- DIParm->setIsNotModified();
- }
- }
-}
-
void CGDebugInfo::finalize() {
// Creating types might create further types - invalidating the current
// element and the size(), so don't cache/reference them.
@@ -4671,27 +4747,28 @@ void CGDebugInfo::finalize() {
DBuilder.replaceTemporary(llvm::TempDIType(E.Decl), Ty);
}
- if (CGM.getCodeGenOpts().DwarfVersion >= 5) {
- // Add methods to interface.
- for (const auto &P : ObjCMethodCache) {
- if (P.second.empty())
- continue;
+ // Add methods to interface.
+ for (const auto &P : ObjCMethodCache) {
+ if (P.second.empty())
+ continue;
- QualType QTy(P.first->getTypeForDecl(), 0);
- auto It = TypeCache.find(QTy.getAsOpaquePtr());
- assert(It != TypeCache.end());
+ QualType QTy(P.first->getTypeForDecl(), 0);
+ auto It = TypeCache.find(QTy.getAsOpaquePtr());
+ assert(It != TypeCache.end());
- llvm::DICompositeType *InterfaceDecl =
- cast<llvm::DICompositeType>(It->second);
+ llvm::DICompositeType *InterfaceDecl =
+ cast<llvm::DICompositeType>(It->second);
- SmallVector<llvm::Metadata *, 16> EltTys;
- auto CurrenetElts = InterfaceDecl->getElements();
- EltTys.append(CurrenetElts.begin(), CurrenetElts.end());
- for (auto &MD : P.second)
- EltTys.push_back(MD);
- llvm::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys);
- DBuilder.replaceArrays(InterfaceDecl, Elements);
- }
+ auto CurElts = InterfaceDecl->getElements();
+ SmallVector<llvm::Metadata *, 16> EltTys(CurElts.begin(), CurElts.end());
+
+ // For DWARF v4 or earlier, only add objc_direct methods.
+ for (auto &SubprogramDirect : P.second)
+ if (CGM.getCodeGenOpts().DwarfVersion >= 5 || SubprogramDirect.getInt())
+ EltTys.push_back(SubprogramDirect.getPointer());
+
+ llvm::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys);
+ DBuilder.replaceArrays(InterfaceDecl, Elements);
}
for (const auto &P : ReplaceMap) {
@@ -4732,15 +4809,11 @@ void CGDebugInfo::finalize() {
if (auto MD = TypeCache[RT])
DBuilder.retainType(cast<llvm::DIType>(MD));
- if (CGM.getCodeGenOpts().EnableDebugEntryValues)
- // This will be used to emit debug entry values.
- analyzeParametersModification(CGM.getContext(), SPDefCache, ParamCache);
-
DBuilder.finalize();
}
void CGDebugInfo::EmitExplicitCastType(QualType Ty) {
- if (CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo)
+ if (!CGM.getCodeGenOpts().hasReducedDebugInfo())
return;
if (auto *DieTy = getOrCreateType(Ty, TheCU->getFile()))
@@ -4769,10 +4842,10 @@ llvm::DINode::DIFlags CGDebugInfo::getCallSiteRelatedAttrs() const {
bool SupportsDWARFv4Ext =
CGM.getCodeGenOpts().DwarfVersion == 4 &&
(CGM.getCodeGenOpts().getDebuggerTuning() == llvm::DebuggerKind::LLDB ||
- (CGM.getCodeGenOpts().EnableDebugEntryValues &&
- CGM.getCodeGenOpts().getDebuggerTuning() == llvm::DebuggerKind::GDB));
+ CGM.getCodeGenOpts().getDebuggerTuning() == llvm::DebuggerKind::GDB);
- if (!SupportsDWARFv4Ext && CGM.getCodeGenOpts().DwarfVersion < 5)
+ if (!SupportsDWARFv4Ext && CGM.getCodeGenOpts().DwarfVersion < 5 &&
+ !CGM.getCodeGenOpts().EnableDebugEntryValues)
return llvm::DINode::FlagZero;
return llvm::DINode::FlagAllCallsDescribed;
diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h
index 7edbea86633a..90e9a61ebe96 100644
--- a/clang/lib/CodeGen/CGDebugInfo.h
+++ b/clang/lib/CodeGen/CGDebugInfo.h
@@ -83,12 +83,25 @@ class CGDebugInfo {
/// Cache of previously constructed Types.
llvm::DenseMap<const void *, llvm::TrackingMDRef> TypeCache;
- llvm::SmallDenseMap<llvm::StringRef, llvm::StringRef> DebugPrefixMap;
+ std::map<llvm::StringRef, llvm::StringRef, std::greater<llvm::StringRef>>
+ DebugPrefixMap;
/// Cache that maps VLA types to size expressions for that type,
/// represented by instantiated Metadata nodes.
llvm::SmallDenseMap<QualType, llvm::Metadata *> SizeExprCache;
+ /// Callbacks to use when printing names and types.
+ class PrintingCallbacks final : public clang::PrintingCallbacks {
+ const CGDebugInfo &Self;
+
+ public:
+ PrintingCallbacks(const CGDebugInfo &Self) : Self(Self) {}
+ std::string remapPath(StringRef Path) const override {
+ return Self.remapDIPath(Path);
+ }
+ };
+ PrintingCallbacks PrintCB = {*this};
+
struct ObjCInterfaceCacheEntry {
const ObjCInterfaceType *Type;
llvm::DIType *Decl;
@@ -102,7 +115,10 @@ class CGDebugInfo {
llvm::SmallVector<ObjCInterfaceCacheEntry, 32> ObjCInterfaceCache;
/// Cache of forward declarations for methods belonging to the interface.
- llvm::DenseMap<const ObjCInterfaceDecl *, std::vector<llvm::DISubprogram *>>
+ /// The extra bit on the DISubprogram specifies whether a method is
+ /// "objc_direct".
+ llvm::DenseMap<const ObjCInterfaceDecl *,
+ std::vector<llvm::PointerIntPair<llvm::DISubprogram *, 1>>>
ObjCMethodCache;
/// Cache of references to clang modules and precompiled headers.
@@ -134,10 +150,6 @@ class CGDebugInfo {
llvm::DenseMap<const char *, llvm::TrackingMDRef> DIFileCache;
llvm::DenseMap<const FunctionDecl *, llvm::TrackingMDRef> SPCache;
- /// Cache function definitions relevant to use for parameters mutation
- /// analysis.
- llvm::DenseMap<const FunctionDecl *, llvm::TrackingMDRef> SPDefCache;
- llvm::DenseMap<const ParmVarDecl *, llvm::TrackingMDRef> ParamCache;
/// Cache declarations relevant to DW_TAG_imported_declarations (C++
/// using declarations) that aren't covered by other more specific caches.
llvm::DenseMap<const Decl *, llvm::TrackingMDRef> DeclCache;
@@ -466,6 +478,9 @@ public:
/// Emit a constant global variable's debug info.
void EmitGlobalVariable(const ValueDecl *VD, const APValue &Init);
+ /// Emit information about an external variable.
+ void EmitExternalVariable(llvm::GlobalVariable *GV, const VarDecl *Decl);
+
/// Emit C++ using directive.
void EmitUsingDirective(const UsingDirectiveDecl &UD);
@@ -601,6 +616,17 @@ private:
/// declaration for the given method definition.
llvm::DISubprogram *getFunctionDeclaration(const Decl *D);
+ /// \return debug info descriptor to the describe method declaration
+ /// for the given method definition.
+ /// \param FnType For Objective-C methods, their type.
+ /// \param LineNo The declaration's line number.
+ /// \param Flags The DIFlags for the method declaration.
+ /// \param SPFlags The subprogram-spcific flags for the method declaration.
+ llvm::DISubprogram *
+ getObjCMethodDeclaration(const Decl *D, llvm::DISubroutineType *FnType,
+ unsigned LineNo, llvm::DINode::DIFlags Flags,
+ llvm::DISubprogram::DISPFlags SPFlags);
+
/// \return debug info descriptor to describe in-class static data
/// member declaration for the given out-of-class definition. If D
/// is an out-of-class definition of a static data member of a
@@ -725,6 +751,7 @@ public:
ApplyDebugLocation(ApplyDebugLocation &&Other) : CGF(Other.CGF) {
Other.CGF = nullptr;
}
+ ApplyDebugLocation &operator=(ApplyDebugLocation &&) = default;
~ApplyDebugLocation();
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 563841c068f6..5aac7a8d54c7 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -22,6 +22,7 @@
#include "PatternInit.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
@@ -109,6 +110,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::OMPRequires:
case Decl::Empty:
case Decl::Concept:
+ case Decl::LifetimeExtendedTemporary:
// None of these decls require codegen support.
return;
@@ -364,7 +366,8 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D,
emitter.finalize(GV);
- if (D.needsDestruction(getContext()) && HaveInsertPoint()) {
+ if (D.needsDestruction(getContext()) == QualType::DK_cxx_destructor &&
+ HaveInsertPoint()) {
// We have a constant initializer, but a nontrivial destructor. We still
// need to perform a guarded "initialization" in order to register the
// destructor.
@@ -443,8 +446,7 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
// Emit global variable debug descriptor for static vars.
CGDebugInfo *DI = getDebugInfo();
- if (DI &&
- CGM.getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo) {
+ if (DI && CGM.getCodeGenOpts().hasReducedDebugInfo()) {
DI->setLocation(D.getLocation());
DI->EmitGlobalVariable(var, &D);
}
@@ -569,7 +571,7 @@ namespace {
Var.getType(), VK_LValue, SourceLocation());
// Compute the address of the local variable, in case it's a byref
// or something.
- llvm::Value *Addr = CGF.EmitDeclRefLValue(&DRE).getPointer();
+ llvm::Value *Addr = CGF.EmitDeclRefLValue(&DRE).getPointer(CGF);
// In some cases, the type of the function argument will be different from
// the type of the pointer. An example of this is
@@ -684,18 +686,18 @@ static bool tryEmitARCCopyWeakInit(CodeGenFunction &CGF,
LValue srcLV = CGF.EmitLValue(srcExpr);
// Handle a formal type change to avoid asserting.
- auto srcAddr = srcLV.getAddress();
+ auto srcAddr = srcLV.getAddress(CGF);
if (needsCast) {
- srcAddr = CGF.Builder.CreateElementBitCast(srcAddr,
- destLV.getAddress().getElementType());
+ srcAddr = CGF.Builder.CreateElementBitCast(
+ srcAddr, destLV.getAddress(CGF).getElementType());
}
// If it was an l-value, use objc_copyWeak.
if (srcExpr->getValueKind() == VK_LValue) {
- CGF.EmitARCCopyWeak(destLV.getAddress(), srcAddr);
+ CGF.EmitARCCopyWeak(destLV.getAddress(CGF), srcAddr);
} else {
assert(srcExpr->getValueKind() == VK_XValue);
- CGF.EmitARCMoveWeak(destLV.getAddress(), srcAddr);
+ CGF.EmitARCMoveWeak(destLV.getAddress(CGF), srcAddr);
}
return true;
}
@@ -713,7 +715,7 @@ static bool tryEmitARCCopyWeakInit(CodeGenFunction &CGF,
static void drillIntoBlockVariable(CodeGenFunction &CGF,
LValue &lvalue,
const VarDecl *var) {
- lvalue.setAddress(CGF.emitBlockByrefAddress(lvalue.getAddress(), var));
+ lvalue.setAddress(CGF.emitBlockByrefAddress(lvalue.getAddress(CGF), var));
}
void CodeGenFunction::EmitNullabilityCheck(LValue LHS, llvm::Value *RHS,
@@ -773,17 +775,18 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D,
if (capturedByInit) {
// We can use a simple GEP for this because it can't have been
// moved yet.
- tempLV.setAddress(emitBlockByrefAddress(tempLV.getAddress(),
+ tempLV.setAddress(emitBlockByrefAddress(tempLV.getAddress(*this),
cast<VarDecl>(D),
/*follow*/ false));
}
- auto ty = cast<llvm::PointerType>(tempLV.getAddress().getElementType());
+ auto ty =
+ cast<llvm::PointerType>(tempLV.getAddress(*this).getElementType());
llvm::Value *zero = CGM.getNullPointer(ty, tempLV.getType());
// If __weak, we want to use a barrier under certain conditions.
if (lifetime == Qualifiers::OCL_Weak)
- EmitARCInitWeak(tempLV.getAddress(), zero);
+ EmitARCInitWeak(tempLV.getAddress(*this), zero);
// Otherwise just do a simple store.
else
@@ -826,9 +829,9 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D,
if (capturedByInit) drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
if (accessedByInit)
- EmitARCStoreWeak(lvalue.getAddress(), value, /*ignored*/ true);
+ EmitARCStoreWeak(lvalue.getAddress(*this), value, /*ignored*/ true);
else
- EmitARCInitWeak(lvalue.getAddress(), value);
+ EmitARCInitWeak(lvalue.getAddress(*this), value);
return;
}
@@ -1390,8 +1393,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
EmitVariablyModifiedType(Ty);
auto *DI = getDebugInfo();
- bool EmitDebugInfo = DI && CGM.getCodeGenOpts().getDebugInfo() >=
- codegenoptions::LimitedDebugInfo;
+ bool EmitDebugInfo = DI && CGM.getCodeGenOpts().hasReducedDebugInfo();
Address address = Address::invalid();
Address AllocaAddr = Address::invalid();
@@ -1896,11 +1898,10 @@ void CodeGenFunction::EmitExprAsInit(const Expr *init, const ValueDecl *D,
else if (auto *FD = dyn_cast<FieldDecl>(D))
Overlap = getOverlapForFieldInit(FD);
// TODO: how can we delay here if D is captured by its initializer?
- EmitAggExpr(init, AggValueSlot::forLValue(lvalue,
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- Overlap));
+ EmitAggExpr(init, AggValueSlot::forLValue(
+ lvalue, *this, AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased, Overlap));
}
return;
}
@@ -2456,7 +2457,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg,
// objc_storeStrong attempts to release its old value.
llvm::Value *Null = CGM.EmitNullConstant(D.getType());
EmitStoreOfScalar(Null, lv, /* isInitialization */ true);
- EmitARCStoreStrongCall(lv.getAddress(), ArgVal, true);
+ EmitARCStoreStrongCall(lv.getAddress(*this), ArgVal, true);
DoStore = false;
}
else
@@ -2493,9 +2494,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg,
// Emit debug info for param declarations in non-thunk functions.
if (CGDebugInfo *DI = getDebugInfo()) {
- if (CGM.getCodeGenOpts().getDebugInfo() >=
- codegenoptions::LimitedDebugInfo &&
- !CurFuncIsThunk) {
+ if (CGM.getCodeGenOpts().hasReducedDebugInfo() && !CurFuncIsThunk) {
DI->EmitDeclareOfArgVariable(&D, DeclPtr.getPointer(), ArgNo, Builder);
}
}
diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp
index bf16b7bec4b1..3baa0a080f5d 100644
--- a/clang/lib/CodeGen/CGDeclCXX.cpp
+++ b/clang/lib/CodeGen/CGDeclCXX.cpp
@@ -10,11 +10,12 @@
//
//===----------------------------------------------------------------------===//
-#include "CodeGenFunction.h"
#include "CGCXXABI.h"
#include "CGObjCRuntime.h"
#include "CGOpenMPRuntime.h"
+#include "CodeGenFunction.h"
#include "TargetInfo.h"
+#include "clang/AST/Attr.h"
#include "clang/Basic/CodeGenOptions.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/Intrinsics.h"
@@ -54,10 +55,11 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
CGF.EmitComplexExprIntoLValue(Init, lv, /*isInit*/ true);
return;
case TEK_Aggregate:
- CGF.EmitAggExpr(Init, AggValueSlot::forLValue(lv,AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- AggValueSlot::DoesNotOverlap));
+ CGF.EmitAggExpr(Init,
+ AggValueSlot::forLValue(lv, CGF, AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased,
+ AggValueSlot::DoesNotOverlap));
return;
}
llvm_unreachable("bad evaluation kind");
@@ -437,7 +439,7 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
// that are of class type, cannot have a non-empty constructor. All
// the checks have been done in Sema by now. Whatever initializers
// are allowed are empty and we just need to ignore them here.
- if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice &&
+ if (getLangOpts().CUDAIsDevice && !getLangOpts().GPUAllowDeviceInit &&
(D->hasAttr<CUDADeviceAttr>() || D->hasAttr<CUDAConstantAttr>() ||
D->hasAttr<CUDASharedAttr>()))
return;
@@ -608,6 +610,11 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
Fn->setCallingConv(llvm::CallingConv::SPIR_KERNEL);
}
+ if (getLangOpts().HIP) {
+ Fn->setCallingConv(llvm::CallingConv::AMDGPU_KERNEL);
+ Fn->addFnAttr("device-init");
+ }
+
CXXGlobalInits.clear();
}
diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp
index 645d7a878e3b..53fafab3e0e6 100644
--- a/clang/lib/CodeGen/CGException.cpp
+++ b/clang/lib/CodeGen/CGException.cpp
@@ -10,10 +10,10 @@
//
//===----------------------------------------------------------------------===//
-#include "CodeGenFunction.h"
#include "CGCXXABI.h"
#include "CGCleanup.h"
#include "CGObjCRuntime.h"
+#include "CodeGenFunction.h"
#include "ConstantEmitter.h"
#include "TargetInfo.h"
#include "clang/AST/Mangle.h"
@@ -21,8 +21,9 @@
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/TargetBuiltins.h"
-#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/IntrinsicsWebAssembly.h"
#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index dcd365c8eaf0..8e0604181fb1 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -417,7 +417,7 @@ static Address createReferenceTemporary(CodeGenFunction &CGF,
LValue CodeGenFunction::
EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) {
- const Expr *E = M->GetTemporaryExpr();
+ const Expr *E = M->getSubExpr();
assert((!M->getExtendingDecl() || !isa<VarDecl>(M->getExtendingDecl()) ||
!cast<VarDecl>(M->getExtendingDecl())->isARCPseudoStrong()) &&
@@ -573,7 +573,7 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) {
LV = EmitLValueForField(LV, Adjustment.Field);
assert(LV.isSimple() &&
"materialized temporary field is not a simple lvalue");
- Object = LV.getAddress();
+ Object = LV.getAddress(*this);
break;
}
@@ -594,7 +594,7 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E) {
// Emit the expression as an lvalue.
LValue LV = EmitLValue(E);
assert(LV.isSimple());
- llvm::Value *Value = LV.getPointer();
+ llvm::Value *Value = LV.getPointer(*this);
if (sanitizePerformTypeCheck() && !E->getType()->isFunctionType()) {
// C++11 [dcl.ref]p5 (as amended by core issue 453):
@@ -1011,6 +1011,9 @@ EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
// Store the updated result through the lvalue.
EmitStoreOfComplex(IncVal, LV, /*init*/ false);
+ if (getLangOpts().OpenMP)
+ CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(*this,
+ E->getSubExpr());
// If this is a postinc, return the value read from memory, otherwise use the
// updated value.
@@ -1129,7 +1132,7 @@ Address CodeGenFunction::EmitPointerWithAlignment(const Expr *E,
LValue LV = EmitLValue(UO->getSubExpr());
if (BaseInfo) *BaseInfo = LV.getBaseInfo();
if (TBAAInfo) *TBAAInfo = LV.getTBAAInfo();
- return LV.getAddress();
+ return LV.getAddress(*this);
}
}
@@ -1219,8 +1222,8 @@ LValue CodeGenFunction::EmitCheckedLValue(const Expr *E, TypeCheckKind TCK) {
if (IsBaseCXXThis || isa<DeclRefExpr>(ME->getBase()))
SkippedChecks.set(SanitizerKind::Null, true);
}
- EmitTypeCheck(TCK, E->getExprLoc(), LV.getPointer(),
- E->getType(), LV.getAlignment(), SkippedChecks);
+ EmitTypeCheck(TCK, E->getExprLoc(), LV.getPointer(*this), E->getType(),
+ LV.getAlignment(), SkippedChecks);
}
return LV;
}
@@ -1307,7 +1310,7 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
if (LV.isSimple()) {
// Defend against branches out of gnu statement expressions surrounded by
// cleanups.
- llvm::Value *V = LV.getPointer();
+ llvm::Value *V = LV.getPointer(*this);
Scope.ForceCleanup({&V});
return LValue::MakeAddr(Address(V, LV.getAlignment()), LV.getType(),
getContext(), LV.getBaseInfo(), LV.getTBAAInfo());
@@ -1523,7 +1526,7 @@ llvm::Value *CodeGenFunction::emitScalarConstant(
llvm::Value *CodeGenFunction::EmitLoadOfScalar(LValue lvalue,
SourceLocation Loc) {
- return EmitLoadOfScalar(lvalue.getAddress(), lvalue.isVolatile(),
+ return EmitLoadOfScalar(lvalue.getAddress(*this), lvalue.isVolatile(),
lvalue.getType(), Loc, lvalue.getBaseInfo(),
lvalue.getTBAAInfo(), lvalue.isNontemporal());
}
@@ -1763,7 +1766,7 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, Address Addr,
void CodeGenFunction::EmitStoreOfScalar(llvm::Value *value, LValue lvalue,
bool isInit) {
- EmitStoreOfScalar(value, lvalue.getAddress(), lvalue.isVolatile(),
+ EmitStoreOfScalar(value, lvalue.getAddress(*this), lvalue.isVolatile(),
lvalue.getType(), lvalue.getBaseInfo(),
lvalue.getTBAAInfo(), isInit, lvalue.isNontemporal());
}
@@ -1774,18 +1777,18 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *value, LValue lvalue,
RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) {
if (LV.isObjCWeak()) {
// load of a __weak object.
- Address AddrWeakObj = LV.getAddress();
+ Address AddrWeakObj = LV.getAddress(*this);
return RValue::get(CGM.getObjCRuntime().EmitObjCWeakRead(*this,
AddrWeakObj));
}
if (LV.getQuals().getObjCLifetime() == Qualifiers::OCL_Weak) {
// In MRC mode, we do a load+autorelease.
if (!getLangOpts().ObjCAutoRefCount) {
- return RValue::get(EmitARCLoadWeak(LV.getAddress()));
+ return RValue::get(EmitARCLoadWeak(LV.getAddress(*this)));
}
// In ARC mode, we load retained and then consume the value.
- llvm::Value *Object = EmitARCLoadWeakRetained(LV.getAddress());
+ llvm::Value *Object = EmitARCLoadWeakRetained(LV.getAddress(*this));
Object = EmitObjCConsumeObject(LV.getType(), Object);
return RValue::get(Object);
}
@@ -1880,8 +1883,7 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV) {
/// Generates lvalue for partial ext_vector access.
Address CodeGenFunction::EmitExtVectorElementLValue(LValue LV) {
Address VectorAddress = LV.getExtVectorAddress();
- const VectorType *ExprVT = LV.getType()->getAs<VectorType>();
- QualType EQT = ExprVT->getElementType();
+ QualType EQT = LV.getType()->castAs<VectorType>()->getElementType();
llvm::Type *VectorElementTy = CGM.getTypes().ConvertType(EQT);
Address CastToPointerElement =
@@ -1971,9 +1973,10 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
case Qualifiers::OCL_Weak:
if (isInit)
// Initialize and then skip the primitive store.
- EmitARCInitWeak(Dst.getAddress(), Src.getScalarVal());
+ EmitARCInitWeak(Dst.getAddress(*this), Src.getScalarVal());
else
- EmitARCStoreWeak(Dst.getAddress(), Src.getScalarVal(), /*ignore*/ true);
+ EmitARCStoreWeak(Dst.getAddress(*this), Src.getScalarVal(),
+ /*ignore*/ true);
return;
case Qualifiers::OCL_Autoreleasing:
@@ -1986,7 +1989,7 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
if (Dst.isObjCWeak() && !Dst.isNonGC()) {
// load of a __weak object.
- Address LvalueDst = Dst.getAddress();
+ Address LvalueDst = Dst.getAddress(*this);
llvm::Value *src = Src.getScalarVal();
CGM.getObjCRuntime().EmitObjCWeakAssign(*this, src, LvalueDst);
return;
@@ -1994,7 +1997,7 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
if (Dst.isObjCStrong() && !Dst.isNonGC()) {
// load of a __strong object.
- Address LvalueDst = Dst.getAddress();
+ Address LvalueDst = Dst.getAddress(*this);
llvm::Value *src = Src.getScalarVal();
if (Dst.isObjCIvar()) {
assert(Dst.getBaseIvarExp() && "BaseIvarExp is NULL");
@@ -2320,8 +2323,8 @@ Address
CodeGenFunction::EmitLoadOfReference(LValue RefLVal,
LValueBaseInfo *PointeeBaseInfo,
TBAAAccessInfo *PointeeTBAAInfo) {
- llvm::LoadInst *Load = Builder.CreateLoad(RefLVal.getAddress(),
- RefLVal.isVolatile());
+ llvm::LoadInst *Load =
+ Builder.CreateLoad(RefLVal.getAddress(*this), RefLVal.isVolatile());
CGM.DecorateInstructionWithTBAA(Load, RefLVal.getTBAAInfo());
CharUnits Align = getNaturalTypeAlignment(RefLVal.getType()->getPointeeType(),
@@ -2565,21 +2568,35 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
VD = VD->getCanonicalDecl();
if (auto *FD = LambdaCaptureFields.lookup(VD))
return EmitCapturedFieldLValue(*this, FD, CXXABIThisValue);
- else if (CapturedStmtInfo) {
+ if (CapturedStmtInfo) {
auto I = LocalDeclMap.find(VD);
if (I != LocalDeclMap.end()) {
+ LValue CapLVal;
if (VD->getType()->isReferenceType())
- return EmitLoadOfReferenceLValue(I->second, VD->getType(),
- AlignmentSource::Decl);
- return MakeAddrLValue(I->second, T);
+ CapLVal = EmitLoadOfReferenceLValue(I->second, VD->getType(),
+ AlignmentSource::Decl);
+ else
+ CapLVal = MakeAddrLValue(I->second, T);
+ // Mark lvalue as nontemporal if the variable is marked as nontemporal
+ // in simd context.
+ if (getLangOpts().OpenMP &&
+ CGM.getOpenMPRuntime().isNontemporalDecl(VD))
+ CapLVal.setNontemporal(/*Value=*/true);
+ return CapLVal;
}
LValue CapLVal =
EmitCapturedFieldLValue(*this, CapturedStmtInfo->lookup(VD),
CapturedStmtInfo->getContextValue());
- return MakeAddrLValue(
- Address(CapLVal.getPointer(), getContext().getDeclAlign(VD)),
+ CapLVal = MakeAddrLValue(
+ Address(CapLVal.getPointer(*this), getContext().getDeclAlign(VD)),
CapLVal.getType(), LValueBaseInfo(AlignmentSource::Decl),
CapLVal.getTBAAInfo());
+ // Mark lvalue as nontemporal if the variable is marked as nontemporal
+ // in simd context.
+ if (getLangOpts().OpenMP &&
+ CGM.getOpenMPRuntime().isNontemporalDecl(VD))
+ CapLVal.setNontemporal(/*Value=*/true);
+ return CapLVal;
}
assert(isa<BlockDecl>(CurCodeDecl));
@@ -2712,7 +2729,7 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
// __real is valid on scalars. This is a faster way of testing that.
// __imag can only produce an rvalue on scalars.
if (E->getOpcode() == UO_Real &&
- !LV.getAddress().getElementType()->isStructTy()) {
+ !LV.getAddress(*this).getElementType()->isStructTy()) {
assert(E->getSubExpr()->getType()->isArithmeticType());
return LV;
}
@@ -2720,9 +2737,9 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
QualType T = ExprTy->castAs<ComplexType>()->getElementType();
Address Component =
- (E->getOpcode() == UO_Real
- ? emitAddrOfRealComponent(LV.getAddress(), LV.getType())
- : emitAddrOfImagComponent(LV.getAddress(), LV.getType()));
+ (E->getOpcode() == UO_Real
+ ? emitAddrOfRealComponent(LV.getAddress(*this), LV.getType())
+ : emitAddrOfImagComponent(LV.getAddress(*this), LV.getType()));
LValue ElemLV = MakeAddrLValue(Component, T, LV.getBaseInfo(),
CGM.getTBAAInfoForSubobject(LV, T));
ElemLV.getQuals().addQualifiers(LV.getQuals());
@@ -3200,6 +3217,9 @@ void CodeGenFunction::EmitCfiCheckFail() {
llvm::Function *F = llvm::Function::Create(
llvm::FunctionType::get(VoidTy, {VoidPtrTy, VoidPtrTy}, false),
llvm::GlobalValue::WeakODRLinkage, "__cfi_check_fail", &CGM.getModule());
+
+ CGM.SetLLVMFunctionAttributes(GlobalDecl(), FI, F);
+ CGM.SetLLVMFunctionAttributesForDefinition(nullptr, F);
F->setVisibility(llvm::GlobalValue::HiddenVisibility);
StartFunction(GlobalDecl(), CGM.getContext().VoidTy, F, FI, Args,
@@ -3319,7 +3339,7 @@ Address CodeGenFunction::EmitArrayToPointerDecay(const Expr *E,
// Expressions of array type can't be bitfields or vector elements.
LValue LV = EmitLValue(E);
- Address Addr = LV.getAddress();
+ Address Addr = LV.getAddress(*this);
// If the array type was an incomplete type, we need to make sure
// the decay ends up being the right type.
@@ -3402,11 +3422,48 @@ static QualType getFixedSizeElementType(const ASTContext &ctx,
return eltType;
}
+/// Given an array base, check whether its member access belongs to a record
+/// with preserve_access_index attribute or not.
+static bool IsPreserveAIArrayBase(CodeGenFunction &CGF, const Expr *ArrayBase) {
+ if (!ArrayBase || !CGF.getDebugInfo())
+ return false;
+
+ // Only support base as either a MemberExpr or DeclRefExpr.
+ // DeclRefExpr to cover cases like:
+ // struct s { int a; int b[10]; };
+ // struct s *p;
+ // p[1].a
+ // p[1] will generate a DeclRefExpr and p[1].a is a MemberExpr.
+ // p->b[5] is a MemberExpr example.
+ const Expr *E = ArrayBase->IgnoreImpCasts();
+ if (const auto *ME = dyn_cast<MemberExpr>(E))
+ return ME->getMemberDecl()->hasAttr<BPFPreserveAccessIndexAttr>();
+
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
+ const auto *VarDef = dyn_cast<VarDecl>(DRE->getDecl());
+ if (!VarDef)
+ return false;
+
+ const auto *PtrT = VarDef->getType()->getAs<PointerType>();
+ if (!PtrT)
+ return false;
+
+ const auto *PointeeT = PtrT->getPointeeType()
+ ->getUnqualifiedDesugaredType();
+ if (const auto *RecT = dyn_cast<RecordType>(PointeeT))
+ return RecT->getDecl()->hasAttr<BPFPreserveAccessIndexAttr>();
+ return false;
+ }
+
+ return false;
+}
+
static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
ArrayRef<llvm::Value *> indices,
QualType eltType, bool inbounds,
bool signedIndices, SourceLocation loc,
QualType *arrayType = nullptr,
+ const Expr *Base = nullptr,
const llvm::Twine &name = "arrayidx") {
// All the indices except that last must be zero.
#ifndef NDEBUG
@@ -3428,7 +3485,8 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
llvm::Value *eltPtr;
auto LastIndex = dyn_cast<llvm::ConstantInt>(indices.back());
- if (!CGF.IsInPreservedAIRegion || !LastIndex) {
+ if (!LastIndex ||
+ (!CGF.IsInPreservedAIRegion && !IsPreserveAIArrayBase(CGF, Base))) {
eltPtr = emitArraySubscriptGEP(
CGF, addr.getPointer(), indices, inbounds, signedIndices,
loc, name);
@@ -3438,7 +3496,8 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
llvm::DIType *DbgInfo = nullptr;
if (arrayType)
DbgInfo = CGF.getDebugInfo()->getOrCreateStandaloneType(*arrayType, loc);
- eltPtr = CGF.Builder.CreatePreserveArrayAccessIndex(addr.getPointer(),
+ eltPtr = CGF.Builder.CreatePreserveArrayAccessIndex(addr.getElementType(),
+ addr.getPointer(),
indices.size() - 1,
idx, DbgInfo);
}
@@ -3483,8 +3542,9 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
LValue LHS = EmitLValue(E->getBase());
auto *Idx = EmitIdxAfterBase(/*Promote*/false);
assert(LHS.isSimple() && "Can only subscript lvalue vectors here!");
- return LValue::MakeVectorElt(LHS.getAddress(), Idx, E->getBase()->getType(),
- LHS.getBaseInfo(), TBAAAccessInfo());
+ return LValue::MakeVectorElt(LHS.getAddress(*this), Idx,
+ E->getBase()->getType(), LHS.getBaseInfo(),
+ TBAAAccessInfo());
}
// All the other cases basically behave like simple offsetting.
@@ -3579,9 +3639,9 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
// Propagate the alignment from the array itself to the result.
QualType arrayType = Array->getType();
Addr = emitArraySubscriptGEP(
- *this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx},
+ *this, ArrayLV.getAddress(*this), {CGM.getSize(CharUnits::Zero()), Idx},
E->getType(), !getLangOpts().isSignedOverflowDefined(), SignedIndices,
- E->getExprLoc(), &arrayType);
+ E->getExprLoc(), &arrayType, E->getBase());
EltBaseInfo = ArrayLV.getBaseInfo();
EltTBAAInfo = CGM.getTBAAInfoForSubobject(ArrayLV, E->getType());
} else {
@@ -3591,7 +3651,8 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
QualType ptrType = E->getBase()->getType();
Addr = emitArraySubscriptGEP(*this, Addr, Idx, E->getType(),
!getLangOpts().isSignedOverflowDefined(),
- SignedIndices, E->getExprLoc(), &ptrType);
+ SignedIndices, E->getExprLoc(), &ptrType,
+ E->getBase());
}
LValue LV = MakeAddrLValue(Addr, E->getType(), EltBaseInfo, EltTBAAInfo);
@@ -3613,7 +3674,7 @@ static Address emitOMPArraySectionBase(CodeGenFunction &CGF, const Expr *Base,
if (auto *ASE = dyn_cast<OMPArraySectionExpr>(Base->IgnoreParenImpCasts())) {
BaseLVal = CGF.EmitOMPArraySectionExpr(ASE, IsLowerBound);
if (BaseTy->isArrayType()) {
- Address Addr = BaseLVal.getAddress();
+ Address Addr = BaseLVal.getAddress(CGF);
BaseInfo = BaseLVal.getBaseInfo();
// If the array type was an incomplete type, we need to make sure
@@ -3638,7 +3699,7 @@ static Address emitOMPArraySectionBase(CodeGenFunction &CGF, const Expr *Base,
&TypeTBAAInfo);
BaseInfo.mergeForCast(TypeBaseInfo);
TBAAInfo = CGF.CGM.mergeTBAAInfoForCast(TBAAInfo, TypeTBAAInfo);
- return Address(CGF.Builder.CreateLoad(BaseLVal.getAddress()), Align);
+ return Address(CGF.Builder.CreateLoad(BaseLVal.getAddress(CGF)), Align);
}
return CGF.EmitPointerWithAlignment(Base, &BaseInfo, &TBAAInfo);
}
@@ -3779,7 +3840,7 @@ LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E,
// Propagate the alignment from the array itself to the result.
EltPtr = emitArraySubscriptGEP(
- *this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx},
+ *this, ArrayLV.getAddress(*this), {CGM.getSize(CharUnits::Zero()), Idx},
ResultExprTy, !getLangOpts().isSignedOverflowDefined(),
/*signedIndices=*/false, E->getExprLoc());
BaseInfo = ArrayLV.getBaseInfo();
@@ -3808,7 +3869,7 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
LValueBaseInfo BaseInfo;
TBAAAccessInfo TBAAInfo;
Address Ptr = EmitPointerWithAlignment(E->getBase(), &BaseInfo, &TBAAInfo);
- const PointerType *PT = E->getBase()->getType()->getAs<PointerType>();
+ const auto *PT = E->getBase()->getType()->castAs<PointerType>();
Base = MakeAddrLValue(Ptr, PT->getPointeeType(), BaseInfo, TBAAInfo);
Base.getQuals().removeObjCGCAttr();
} else if (E->getBase()->isGLValue()) {
@@ -3839,7 +3900,7 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
if (Base.isSimple()) {
llvm::Constant *CV =
llvm::ConstantDataVector::get(getLLVMContext(), Indices);
- return LValue::MakeExtVectorElt(Base.getAddress(), CV, type,
+ return LValue::MakeExtVectorElt(Base.getAddress(*this), CV, type,
Base.getBaseInfo(), TBAAAccessInfo());
}
assert(Base.isExtVectorElt() && "Can only subscript lvalue vec elts here!");
@@ -3884,6 +3945,15 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
if (auto *Field = dyn_cast<FieldDecl>(ND)) {
LValue LV = EmitLValueForField(BaseLV, Field);
setObjCGCLValueClass(getContext(), E, LV);
+ if (getLangOpts().OpenMP) {
+ // If the member was explicitly marked as nontemporal, mark it as
+ // nontemporal. If the base lvalue is marked as nontemporal, mark access
+ // to children as nontemporal too.
+ if ((IsWrappedCXXThis(BaseExpr) &&
+ CGM.getOpenMPRuntime().isNontemporalDecl(Field)) ||
+ BaseLV.isNontemporal())
+ LV.setNontemporal(/*Value=*/true);
+ }
return LV;
}
@@ -3990,14 +4060,15 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
const CGRecordLayout &RL =
CGM.getTypes().getCGRecordLayout(field->getParent());
const CGBitFieldInfo &Info = RL.getBitFieldInfo(field);
- Address Addr = base.getAddress();
+ Address Addr = base.getAddress(*this);
unsigned Idx = RL.getLLVMFieldNo(field);
- if (!IsInPreservedAIRegion) {
+ const RecordDecl *rec = field->getParent();
+ if (!IsInPreservedAIRegion &&
+ (!getDebugInfo() || !rec->hasAttr<BPFPreserveAccessIndexAttr>())) {
if (Idx != 0)
// For structs, we GEP to the field that the record layout suggests.
Addr = Builder.CreateStructGEP(Addr, Idx, field->getName());
} else {
- const RecordDecl *rec = field->getParent();
llvm::DIType *DbgInfo = getDebugInfo()->getOrCreateRecordType(
getContext().getRecordType(rec), rec->getLocation());
Addr = Builder.CreatePreserveStructAccessIndex(Addr, Idx,
@@ -4057,7 +4128,7 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
getContext().getTypeSizeInChars(FieldType).getQuantity();
}
- Address addr = base.getAddress();
+ Address addr = base.getAddress(*this);
if (auto *ClassDef = dyn_cast<CXXRecordDecl>(rec)) {
if (CGM.getCodeGenOpts().StrictVTablePointers &&
ClassDef->isDynamicClass()) {
@@ -4080,7 +4151,8 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
addr = Address(Builder.CreateLaunderInvariantGroup(addr.getPointer()),
addr.getAlignment());
- if (IsInPreservedAIRegion) {
+ if (IsInPreservedAIRegion ||
+ (getDebugInfo() && rec->hasAttr<BPFPreserveAccessIndexAttr>())) {
// Remember the original union field index
llvm::DIType *DbgInfo = getDebugInfo()->getOrCreateRecordType(
getContext().getRecordType(rec), rec->getLocation());
@@ -4094,7 +4166,8 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
addr = Builder.CreateElementBitCast(
addr, CGM.getTypes().ConvertTypeForMem(FieldType), field->getName());
} else {
- if (!IsInPreservedAIRegion)
+ if (!IsInPreservedAIRegion &&
+ (!getDebugInfo() || !rec->hasAttr<BPFPreserveAccessIndexAttr>()))
// For structs, we GEP to the field that the record layout suggests.
addr = emitAddrOfFieldStorage(*this, addr, field);
else
@@ -4143,7 +4216,7 @@ CodeGenFunction::EmitLValueForFieldInitialization(LValue Base,
if (!FieldType->isReferenceType())
return EmitLValueForField(Base, Field);
- Address V = emitAddrOfFieldStorage(*this, Base.getAddress(), Field);
+ Address V = emitAddrOfFieldStorage(*this, Base.getAddress(*this), Field);
// Make sure that the address is pointing to the right type.
llvm::Type *llvmType = ConvertTypeForMem(FieldType);
@@ -4261,10 +4334,10 @@ EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) {
EmitBlock(contBlock);
if (lhs && rhs) {
- llvm::PHINode *phi = Builder.CreatePHI(lhs->getPointer()->getType(),
- 2, "cond-lvalue");
- phi->addIncoming(lhs->getPointer(), lhsBlock);
- phi->addIncoming(rhs->getPointer(), rhsBlock);
+ llvm::PHINode *phi =
+ Builder.CreatePHI(lhs->getPointer(*this)->getType(), 2, "cond-lvalue");
+ phi->addIncoming(lhs->getPointer(*this), lhsBlock);
+ phi->addIncoming(rhs->getPointer(*this), rhsBlock);
Address result(phi, std::min(lhs->getAlignment(), rhs->getAlignment()));
AlignmentSource alignSource =
std::max(lhs->getBaseInfo().getAlignmentSource(),
@@ -4347,7 +4420,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_Dynamic: {
LValue LV = EmitLValue(E->getSubExpr());
- Address V = LV.getAddress();
+ Address V = LV.getAddress(*this);
const auto *DCE = cast<CXXDynamicCastExpr>(E);
return MakeNaturalAlignAddrLValue(EmitDynamicCast(V, DCE), E->getType());
}
@@ -4362,12 +4435,12 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_UncheckedDerivedToBase:
case CK_DerivedToBase: {
- const RecordType *DerivedClassTy =
- E->getSubExpr()->getType()->getAs<RecordType>();
+ const auto *DerivedClassTy =
+ E->getSubExpr()->getType()->castAs<RecordType>();
auto *DerivedClassDecl = cast<CXXRecordDecl>(DerivedClassTy->getDecl());
LValue LV = EmitLValue(E->getSubExpr());
- Address This = LV.getAddress();
+ Address This = LV.getAddress(*this);
// Perform the derived-to-base conversion
Address Base = GetAddressOfBaseClass(
@@ -4383,16 +4456,15 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_ToUnion:
return EmitAggExprToLValue(E);
case CK_BaseToDerived: {
- const RecordType *DerivedClassTy = E->getType()->getAs<RecordType>();
+ const auto *DerivedClassTy = E->getType()->castAs<RecordType>();
auto *DerivedClassDecl = cast<CXXRecordDecl>(DerivedClassTy->getDecl());
LValue LV = EmitLValue(E->getSubExpr());
// Perform the base-to-derived conversion
- Address Derived =
- GetAddressOfDerivedClass(LV.getAddress(), DerivedClassDecl,
- E->path_begin(), E->path_end(),
- /*NullCheckValue=*/false);
+ Address Derived = GetAddressOfDerivedClass(
+ LV.getAddress(*this), DerivedClassDecl, E->path_begin(), E->path_end(),
+ /*NullCheckValue=*/false);
// C++11 [expr.static.cast]p2: Behavior is undefined if a downcast is
// performed and the object is not of the derived type.
@@ -4414,7 +4486,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
CGM.EmitExplicitCastExprType(CE, this);
LValue LV = EmitLValue(E->getSubExpr());
- Address V = Builder.CreateBitCast(LV.getAddress(),
+ Address V = Builder.CreateBitCast(LV.getAddress(*this),
ConvertType(CE->getTypeAsWritten()));
if (SanOpts.has(SanitizerKind::CFIUnrelatedCast))
@@ -4429,14 +4501,15 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
LValue LV = EmitLValue(E->getSubExpr());
QualType DestTy = getContext().getPointerType(E->getType());
llvm::Value *V = getTargetHooks().performAddrSpaceCast(
- *this, LV.getPointer(), E->getSubExpr()->getType().getAddressSpace(),
+ *this, LV.getPointer(*this),
+ E->getSubExpr()->getType().getAddressSpace(),
E->getType().getAddressSpace(), ConvertType(DestTy));
- return MakeAddrLValue(Address(V, LV.getAddress().getAlignment()),
+ return MakeAddrLValue(Address(V, LV.getAddress(*this).getAlignment()),
E->getType(), LV.getBaseInfo(), LV.getTBAAInfo());
}
case CK_ObjCObjectLValueCast: {
LValue LV = EmitLValue(E->getSubExpr());
- Address V = Builder.CreateElementBitCast(LV.getAddress(),
+ Address V = Builder.CreateElementBitCast(LV.getAddress(*this),
ConvertType(E->getType()));
return MakeAddrLValue(V, E->getType(), LV.getBaseInfo(),
CGM.getTBAAInfoForSubobject(LV, E->getType()));
@@ -4490,13 +4563,17 @@ RValue CodeGenFunction::EmitRValueForField(LValue LV,
case TEK_Complex:
return RValue::getComplex(EmitLoadOfComplex(FieldLV, Loc));
case TEK_Aggregate:
- return FieldLV.asAggregateRValue();
+ return FieldLV.asAggregateRValue(*this);
case TEK_Scalar:
// This routine is used to load fields one-by-one to perform a copy, so
// don't load reference fields.
if (FD->getType()->isReferenceType())
- return RValue::get(FieldLV.getPointer());
- return EmitLoadOfLValue(FieldLV, Loc);
+ return RValue::get(FieldLV.getPointer(*this));
+ // Call EmitLoadOfScalar except when the lvalue is a bitfield to emit a
+ // primitive load.
+ if (FieldLV.isBitField())
+ return EmitLoadOfLValue(FieldLV, Loc);
+ return RValue::get(EmitLoadOfScalar(FieldLV, Loc));
}
llvm_unreachable("bad evaluation kind");
}
@@ -4544,8 +4621,15 @@ RValue CodeGenFunction::EmitSimpleCallExpr(const CallExpr *E,
}
static CGCallee EmitDirectCallee(CodeGenFunction &CGF, const FunctionDecl *FD) {
+
if (auto builtinID = FD->getBuiltinID()) {
- return CGCallee::forBuiltin(builtinID, FD);
+ // Replaceable builtin provide their own implementation of a builtin. Unless
+ // we are in the builtin implementation itself, don't call the actual
+ // builtin. If we are in the builtin implementation, avoid trivial infinite
+ // recursion.
+ if (!FD->isInlineBuiltinDeclaration() ||
+ CGF.CurFn->getName() == FD->getName())
+ return CGCallee::forBuiltin(builtinID, FD);
}
llvm::Constant *calleePtr = EmitFunctionDeclPointer(CGF.CGM, FD);
@@ -4590,7 +4674,7 @@ CGCallee CodeGenFunction::EmitCallee(const Expr *E) {
functionType = ptrType->getPointeeType();
} else {
functionType = E->getType();
- calleePtr = EmitLValue(E).getPointer();
+ calleePtr = EmitLValue(E).getPointer(*this);
}
assert(functionType->isFunctionType());
@@ -4642,6 +4726,9 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
if (RV.isScalar())
EmitNullabilityCheck(LV, RV.getScalarVal(), E->getExprLoc());
EmitStoreThroughLValue(RV, LV);
+ if (getLangOpts().OpenMP)
+ CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(*this,
+ E->getLHS());
return LV;
}
@@ -4750,7 +4837,7 @@ LValue CodeGenFunction::EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E) {
BaseQuals = ObjectTy.getQualifiers();
} else {
LValue BaseLV = EmitLValue(BaseExpr);
- BaseValue = BaseLV.getPointer();
+ BaseValue = BaseLV.getPointer(*this);
ObjectTy = BaseExpr->getType();
BaseQuals = ObjectTy.getQualifiers();
}
@@ -4960,13 +5047,11 @@ EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E) {
if (E->getOpcode() == BO_PtrMemI) {
BaseAddr = EmitPointerWithAlignment(E->getLHS());
} else {
- BaseAddr = EmitLValue(E->getLHS()).getAddress();
+ BaseAddr = EmitLValue(E->getLHS()).getAddress(*this);
}
llvm::Value *OffsetV = EmitScalarExpr(E->getRHS());
-
- const MemberPointerType *MPT
- = E->getRHS()->getType()->getAs<MemberPointerType>();
+ const auto *MPT = E->getRHS()->getType()->castAs<MemberPointerType>();
LValueBaseInfo BaseInfo;
TBAAAccessInfo TBAAInfo;
@@ -4987,7 +5072,7 @@ RValue CodeGenFunction::convertTempToRValue(Address addr,
case TEK_Complex:
return RValue::getComplex(EmitLoadOfComplex(lvalue, loc));
case TEK_Aggregate:
- return lvalue.asAggregateRValue();
+ return lvalue.asAggregateRValue(*this);
case TEK_Scalar:
return RValue::get(EmitLoadOfScalar(lvalue, loc));
}
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 2f0e4937613f..8de609a2ccd9 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -10,20 +10,21 @@
//
//===----------------------------------------------------------------------===//
-#include "CodeGenFunction.h"
#include "CGCXXABI.h"
#include "CGObjCRuntime.h"
+#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "ConstantEmitter.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/StmtVisitor.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
-#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Intrinsics.h"
using namespace clang;
using namespace CodeGen;
@@ -345,10 +346,9 @@ void AggExprEmitter::EmitFinalDestCopy(QualType type, const LValue &src,
}
}
- AggValueSlot srcAgg =
- AggValueSlot::forLValue(src, AggValueSlot::IsDestructed,
- needsGC(type), AggValueSlot::IsAliased,
- AggValueSlot::MayOverlap);
+ AggValueSlot srcAgg = AggValueSlot::forLValue(
+ src, CGF, AggValueSlot::IsDestructed, needsGC(type),
+ AggValueSlot::IsAliased, AggValueSlot::MayOverlap);
EmitCopy(type, Dest, srcAgg);
}
@@ -386,7 +386,7 @@ AggExprEmitter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
ASTContext &Ctx = CGF.getContext();
LValue Array = CGF.EmitLValue(E->getSubExpr());
assert(Array.isSimple() && "initializer_list array not a simple lvalue");
- Address ArrayPtr = Array.getAddress();
+ Address ArrayPtr = Array.getAddress(CGF);
const ConstantArrayType *ArrayType =
Ctx.getAsConstantArrayType(E->getSubExpr()->getType());
@@ -493,7 +493,7 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
if (NumInitElements * elementSize.getQuantity() > 16 &&
elementType.isTriviallyCopyableType(CGF.getContext())) {
CodeGen::CodeGenModule &CGM = CGF.CGM;
- ConstantEmitter Emitter(CGM);
+ ConstantEmitter Emitter(CGF);
LangAS AS = ArrayQTy.getAddressSpace();
if (llvm::Constant *C = Emitter.tryEmitForInitializer(E, AS, ArrayQTy)) {
auto GV = new llvm::GlobalVariable(
@@ -637,7 +637,7 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
//===----------------------------------------------------------------------===//
void AggExprEmitter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E){
- Visit(E->GetTemporaryExpr());
+ Visit(E->getSubExpr());
}
void AggExprEmitter::VisitOpaqueValueExpr(OpaqueValueExpr *e) {
@@ -688,7 +688,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
CodeGenFunction::TCK_Load);
// FIXME: Do we also need to handle property references here?
if (LV.isSimple())
- CGF.EmitDynamicCast(LV.getAddress(), cast<CXXDynamicCastExpr>(E));
+ CGF.EmitDynamicCast(LV.getAddress(CGF), cast<CXXDynamicCastExpr>(E));
else
CGF.CGM.ErrorUnsupported(E, "non-simple lvalue dynamic_cast");
@@ -723,7 +723,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
LValue SourceLV = CGF.EmitLValue(E->getSubExpr());
Address SourceAddress =
- Builder.CreateElementBitCast(SourceLV.getAddress(), CGF.Int8Ty);
+ Builder.CreateElementBitCast(SourceLV.getAddress(CGF), CGF.Int8Ty);
Address DestAddress =
Builder.CreateElementBitCast(Dest.getAddress(), CGF.Int8Ty);
llvm::Value *SizeVal = llvm::ConstantInt::get(
@@ -981,10 +981,6 @@ void AggExprEmitter::VisitBinCmp(const BinaryOperator *E) {
QualType ArgTy = E->getLHS()->getType();
- // TODO: Handle comparing these types.
- if (ArgTy->isVectorType())
- return CGF.ErrorUnsupported(
- E, "aggregate three-way comparison with vector arguments");
if (!ArgTy->isIntegralOrEnumerationType() && !ArgTy->isRealFloatingType() &&
!ArgTy->isNullPtrType() && !ArgTy->isPointerType() &&
!ArgTy->isMemberPointerType() && !ArgTy->isAnyComplexType()) {
@@ -1022,10 +1018,6 @@ void AggExprEmitter::VisitBinCmp(const BinaryOperator *E) {
Value *Select;
if (ArgTy->isNullPtrType()) {
Select = EmitCmpRes(CmpInfo.getEqualOrEquiv());
- } else if (CmpInfo.isEquality()) {
- Select = Builder.CreateSelect(
- EmitCmp(CK_Equal), EmitCmpRes(CmpInfo.getEqualOrEquiv()),
- EmitCmpRes(CmpInfo.getNonequalOrNonequiv()), "sel.eq");
} else if (!CmpInfo.isPartial()) {
Value *SelectOne =
Builder.CreateSelect(EmitCmp(CK_Less), EmitCmpRes(CmpInfo.getLess()),
@@ -1163,7 +1155,7 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
}
EmitCopy(E->getLHS()->getType(),
- AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed,
+ AggValueSlot::forLValue(LHS, CGF, AggValueSlot::IsDestructed,
needsGC(E->getLHS()->getType()),
AggValueSlot::IsAliased,
AggValueSlot::MayOverlap),
@@ -1184,11 +1176,9 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
}
// Codegen the RHS so that it stores directly into the LHS.
- AggValueSlot LHSSlot =
- AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed,
- needsGC(E->getLHS()->getType()),
- AggValueSlot::IsAliased,
- AggValueSlot::MayOverlap);
+ AggValueSlot LHSSlot = AggValueSlot::forLValue(
+ LHS, CGF, AggValueSlot::IsDestructed, needsGC(E->getLHS()->getType()),
+ AggValueSlot::IsAliased, AggValueSlot::MayOverlap);
// A non-volatile aggregate destination might have volatile member.
if (!LHSSlot.isVolatile() &&
CGF.hasVolatileMember(E->getLHS()->getType()))
@@ -1320,7 +1310,7 @@ AggExprEmitter::VisitLambdaExpr(LambdaExpr *E) {
llvm::Constant::getNullValue(CGF.Int8PtrTy),
CharUnits::One()); // placeholder
- CGF.pushDestroy(EHCleanup, LV.getAddress(), CurField->getType(),
+ CGF.pushDestroy(EHCleanup, LV.getAddress(CGF), CurField->getType(),
CGF.getDestroyer(DtorKind), false);
Cleanups.push_back(CGF.EHStack.stable_begin());
}
@@ -1408,12 +1398,11 @@ AggExprEmitter::EmitInitializationToLValue(Expr *E, LValue LV) {
CGF.EmitComplexExprIntoLValue(E, LV, /*isInit*/ true);
return;
case TEK_Aggregate:
- CGF.EmitAggExpr(E, AggValueSlot::forLValue(LV,
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- AggValueSlot::MayOverlap,
- Dest.isZeroed()));
+ CGF.EmitAggExpr(
+ E, AggValueSlot::forLValue(LV, CGF, AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased,
+ AggValueSlot::MayOverlap, Dest.isZeroed()));
return;
case TEK_Scalar:
if (LV.isSimple()) {
@@ -1449,7 +1438,7 @@ void AggExprEmitter::EmitNullInitializationToLValue(LValue lv) {
// There's a potential optimization opportunity in combining
// memsets; that would be easy for arrays, but relatively
// difficult for structures with the current code.
- CGF.EmitNullInitialization(lv.getAddress(), lv.getType());
+ CGF.EmitNullInitialization(lv.getAddress(CGF), lv.getType());
}
}
@@ -1606,7 +1595,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
= field->getType().isDestructedType()) {
assert(LV.isSimple());
if (CGF.needsEHCleanup(dtorKind)) {
- CGF.pushDestroy(EHCleanup, LV.getAddress(), field->getType(),
+ CGF.pushDestroy(EHCleanup, LV.getAddress(CGF), field->getType(),
CGF.getDestroyer(dtorKind), false);
addCleanup(CGF.EHStack.stable_begin());
pushedCleanup = true;
@@ -1617,7 +1606,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
// else, clean it up for -O0 builds and general tidiness.
if (!pushedCleanup && LV.isSimple())
if (llvm::GetElementPtrInst *GEP =
- dyn_cast<llvm::GetElementPtrInst>(LV.getPointer()))
+ dyn_cast<llvm::GetElementPtrInst>(LV.getPointer(CGF)))
if (GEP->use_empty())
GEP->eraseFromParent();
}
@@ -1699,9 +1688,8 @@ void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E,
if (InnerLoop) {
// If the subexpression is an ArrayInitLoopExpr, share its cleanup.
auto elementSlot = AggValueSlot::forLValue(
- elementLV, AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
+ elementLV, CGF, AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased,
AggValueSlot::DoesNotOverlap);
AggExprEmitter(CGF, elementSlot, false)
.VisitArrayInitLoopExpr(InnerLoop, outerBegin);
@@ -1864,10 +1852,10 @@ LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) {
assert(hasAggregateEvaluationKind(E->getType()) && "Invalid argument!");
Address Temp = CreateMemTemp(E->getType());
LValue LV = MakeAddrLValue(Temp, E->getType());
- EmitAggExpr(E, AggValueSlot::forLValue(LV, AggValueSlot::IsNotDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- AggValueSlot::DoesNotOverlap));
+ EmitAggExpr(E, AggValueSlot::forLValue(
+ LV, *this, AggValueSlot::IsNotDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased, AggValueSlot::DoesNotOverlap));
return LV;
}
@@ -1916,8 +1904,8 @@ void CodeGenFunction::EmitAggregateCopy(LValue Dest, LValue Src, QualType Ty,
bool isVolatile) {
assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex");
- Address DestPtr = Dest.getAddress();
- Address SrcPtr = Src.getAddress();
+ Address DestPtr = Dest.getAddress(*this);
+ Address SrcPtr = Src.getAddress(*this);
if (getLangOpts().CPlusPlus) {
if (const RecordType *RT = Ty->getAs<RecordType>()) {
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index 114d806d454b..42c1c34c57ad 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -129,11 +129,11 @@ RValue CodeGenFunction::EmitCXXPseudoDestructorExpr(
// If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar.
if (E->isArrow()) {
BaseValue = EmitPointerWithAlignment(BaseExpr);
- const PointerType *PTy = BaseExpr->getType()->getAs<PointerType>();
+ const auto *PTy = BaseExpr->getType()->castAs<PointerType>();
BaseQuals = PTy->getPointeeType().getQualifiers();
} else {
LValue BaseLV = EmitLValue(BaseExpr);
- BaseValue = BaseLV.getAddress();
+ BaseValue = BaseLV.getAddress(*this);
QualType BaseTy = BaseExpr->getType();
BaseQuals = BaseTy.getQualifiers();
}
@@ -241,16 +241,28 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
}
}
+ bool TrivialForCodegen =
+ MD->isTrivial() || (MD->isDefaulted() && MD->getParent()->isUnion());
+ bool TrivialAssignment =
+ TrivialForCodegen &&
+ (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) &&
+ !MD->getParent()->mayInsertExtraPadding();
+
// C++17 demands that we evaluate the RHS of a (possibly-compound) assignment
// operator before the LHS.
CallArgList RtlArgStorage;
CallArgList *RtlArgs = nullptr;
+ LValue TrivialAssignmentRHS;
if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(CE)) {
if (OCE->isAssignmentOp()) {
- RtlArgs = &RtlArgStorage;
- EmitCallArgs(*RtlArgs, MD->getType()->castAs<FunctionProtoType>(),
- drop_begin(CE->arguments(), 1), CE->getDirectCallee(),
- /*ParamsToSkip*/0, EvaluationOrder::ForceRightToLeft);
+ if (TrivialAssignment) {
+ TrivialAssignmentRHS = EmitLValue(CE->getArg(1));
+ } else {
+ RtlArgs = &RtlArgStorage;
+ EmitCallArgs(*RtlArgs, MD->getType()->castAs<FunctionProtoType>(),
+ drop_begin(CE->arguments(), 1), CE->getDirectCallee(),
+ /*ParamsToSkip*/0, EvaluationOrder::ForceRightToLeft);
+ }
}
}
@@ -271,32 +283,35 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
assert(ReturnValue.isNull() && "Constructor shouldn't have return value");
CallArgList Args;
commonEmitCXXMemberOrOperatorCall(
- *this, Ctor, This.getPointer(), /*ImplicitParam=*/nullptr,
+ *this, Ctor, This.getPointer(*this), /*ImplicitParam=*/nullptr,
/*ImplicitParamTy=*/QualType(), CE, Args, nullptr);
EmitCXXConstructorCall(Ctor, Ctor_Complete, /*ForVirtualBase=*/false,
- /*Delegating=*/false, This.getAddress(), Args,
+ /*Delegating=*/false, This.getAddress(*this), Args,
AggValueSlot::DoesNotOverlap, CE->getExprLoc(),
/*NewPointerIsChecked=*/false);
return RValue::get(nullptr);
}
- if (MD->isTrivial() || (MD->isDefaulted() && MD->getParent()->isUnion())) {
- if (isa<CXXDestructorDecl>(MD)) return RValue::get(nullptr);
- if (!MD->getParent()->mayInsertExtraPadding()) {
- if (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) {
- // We don't like to generate the trivial copy/move assignment operator
- // when it isn't necessary; just produce the proper effect here.
- LValue RHS = isa<CXXOperatorCallExpr>(CE)
- ? MakeNaturalAlignAddrLValue(
- (*RtlArgs)[0].getRValue(*this).getScalarVal(),
- (*(CE->arg_begin() + 1))->getType())
- : EmitLValue(*CE->arg_begin());
- EmitAggregateAssign(This, RHS, CE->getType());
- return RValue::get(This.getPointer());
- }
- llvm_unreachable("unknown trivial member function");
+ if (TrivialForCodegen) {
+ if (isa<CXXDestructorDecl>(MD))
+ return RValue::get(nullptr);
+
+ if (TrivialAssignment) {
+ // We don't like to generate the trivial copy/move assignment operator
+ // when it isn't necessary; just produce the proper effect here.
+ // It's important that we use the result of EmitLValue here rather than
+ // emitting call arguments, in order to preserve TBAA information from
+ // the RHS.
+ LValue RHS = isa<CXXOperatorCallExpr>(CE)
+ ? TrivialAssignmentRHS
+ : EmitLValue(*CE->arg_begin());
+ EmitAggregateAssign(This, RHS, CE->getType());
+ return RValue::get(This.getPointer(*this));
}
+
+ assert(MD->getParent()->mayInsertExtraPadding() &&
+ "unknown trivial member function");
}
// Compute the function type we're calling.
@@ -328,7 +343,8 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
if (IsImplicitObjectCXXThis || isa<DeclRefExpr>(IOA))
SkippedChecks.set(SanitizerKind::Null, true);
}
- EmitTypeCheck(CodeGenFunction::TCK_MemberCall, CallLoc, This.getPointer(),
+ EmitTypeCheck(CodeGenFunction::TCK_MemberCall, CallLoc,
+ This.getPointer(*this),
C.getRecordType(CalleeDecl->getParent()),
/*Alignment=*/CharUnits::Zero(), SkippedChecks);
@@ -345,9 +361,9 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
"Destructor shouldn't have explicit parameters");
assert(ReturnValue.isNull() && "Destructor shouldn't have return value");
if (UseVirtualCall) {
- CGM.getCXXABI().EmitVirtualDestructorCall(
- *this, Dtor, Dtor_Complete, This.getAddress(),
- cast<CXXMemberCallExpr>(CE));
+ CGM.getCXXABI().EmitVirtualDestructorCall(*this, Dtor, Dtor_Complete,
+ This.getAddress(*this),
+ cast<CXXMemberCallExpr>(CE));
} else {
GlobalDecl GD(Dtor, Dtor_Complete);
CGCallee Callee;
@@ -362,7 +378,7 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
QualType ThisTy =
IsArrow ? Base->getType()->getPointeeType() : Base->getType();
- EmitCXXDestructorCall(GD, Callee, This.getPointer(), ThisTy,
+ EmitCXXDestructorCall(GD, Callee, This.getPointer(*this), ThisTy,
/*ImplicitParam=*/nullptr,
/*ImplicitParamTy=*/QualType(), nullptr);
}
@@ -374,15 +390,14 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
CGCallee Callee;
if (UseVirtualCall) {
- Callee = CGCallee::forVirtual(CE, MD, This.getAddress(), Ty);
+ Callee = CGCallee::forVirtual(CE, MD, This.getAddress(*this), Ty);
} else {
if (SanOpts.has(SanitizerKind::CFINVCall) &&
MD->getParent()->isDynamicClass()) {
llvm::Value *VTable;
const CXXRecordDecl *RD;
- std::tie(VTable, RD) =
- CGM.getCXXABI().LoadVTablePtr(*this, This.getAddress(),
- CalleeDecl->getParent());
+ std::tie(VTable, RD) = CGM.getCXXABI().LoadVTablePtr(
+ *this, This.getAddress(*this), CalleeDecl->getParent());
EmitVTablePtrCheckForCall(RD, VTable, CFITCK_NVCall, CE->getBeginLoc());
}
@@ -401,12 +416,12 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
if (MD->isVirtual()) {
Address NewThisAddr =
CGM.getCXXABI().adjustThisArgumentForVirtualFunctionCall(
- *this, CalleeDecl, This.getAddress(), UseVirtualCall);
+ *this, CalleeDecl, This.getAddress(*this), UseVirtualCall);
This.setAddress(NewThisAddr);
}
return EmitCXXMemberOrOperatorCall(
- CalleeDecl, Callee, ReturnValue, This.getPointer(),
+ CalleeDecl, Callee, ReturnValue, This.getPointer(*this),
/*ImplicitParam=*/nullptr, QualType(), CE, RtlArgs);
}
@@ -428,7 +443,7 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
if (BO->getOpcode() == BO_PtrMemI)
This = EmitPointerWithAlignment(BaseExpr);
else
- This = EmitLValue(BaseExpr).getAddress();
+ This = EmitLValue(BaseExpr).getAddress(*this);
EmitTypeCheck(TCK_MemberCall, E->getExprLoc(), This.getPointer(),
QualType(MPT->getClass(), 0));
@@ -1412,8 +1427,7 @@ namespace {
}
void Emit(CodeGenFunction &CGF, Flags flags) override {
- const FunctionProtoType *FPT =
- OperatorDelete->getType()->getAs<FunctionProtoType>();
+ const auto *FPT = OperatorDelete->getType()->castAs<FunctionProtoType>();
CallArgList DeleteArgs;
// The first argument is always a void* (or C* for a destroying operator
@@ -1755,9 +1769,7 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
assert((!NumElements && CookieSize.isZero()) ||
DeleteFD->getOverloadedOperator() == OO_Array_Delete);
- const FunctionProtoType *DeleteFTy =
- DeleteFD->getType()->getAs<FunctionProtoType>();
-
+ const auto *DeleteFTy = DeleteFD->getType()->castAs<FunctionProtoType>();
CallArgList DeleteArgs;
auto Params = getUsualDeleteParams(DeleteFD);
@@ -2103,7 +2115,7 @@ static bool isGLValueFromPointerDeref(const Expr *E) {
static llvm::Value *EmitTypeidFromVTable(CodeGenFunction &CGF, const Expr *E,
llvm::Type *StdTypeInfoPtrTy) {
// Get the vtable pointer.
- Address ThisPtr = CGF.EmitLValue(E).getAddress();
+ Address ThisPtr = CGF.EmitLValue(E).getAddress(CGF);
QualType SrcRecordTy = E->getType();
diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index 385f87f12a9b..f7a4e9e94712 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "CGOpenMPRuntime.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "clang/AST/StmtVisitor.h"
@@ -348,7 +349,7 @@ ComplexPairTy ComplexExprEmitter::EmitLoadOfLValue(LValue lvalue,
if (lvalue.getType()->isAtomicType())
return CGF.EmitAtomicLoad(lvalue, loc).getComplexVal();
- Address SrcPtr = lvalue.getAddress();
+ Address SrcPtr = lvalue.getAddress(CGF);
bool isVolatile = lvalue.isVolatileQualified();
llvm::Value *Real = nullptr, *Imag = nullptr;
@@ -374,7 +375,7 @@ void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, LValue lvalue,
(!isInit && CGF.LValueIsSuitableForInlineAtomic(lvalue)))
return CGF.EmitAtomicStore(RValue::getComplex(Val), lvalue, isInit);
- Address Ptr = lvalue.getAddress();
+ Address Ptr = lvalue.getAddress(CGF);
Address RealPtr = CGF.emitAddrOfRealComponent(Ptr, lvalue.getType());
Address ImagPtr = CGF.emitAddrOfImagComponent(Ptr, lvalue.getType());
@@ -463,14 +464,14 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, Expr *Op,
case CK_LValueBitCast: {
LValue origLV = CGF.EmitLValue(Op);
- Address V = origLV.getAddress();
+ Address V = origLV.getAddress(CGF);
V = Builder.CreateElementBitCast(V, CGF.ConvertType(DestTy));
return EmitLoadOfLValue(CGF.MakeAddrLValue(V, DestTy), Op->getExprLoc());
}
case CK_LValueToRValueBitCast: {
LValue SourceLVal = CGF.EmitLValue(Op);
- Address Addr = Builder.CreateElementBitCast(SourceLVal.getAddress(),
+ Address Addr = Builder.CreateElementBitCast(SourceLVal.getAddress(CGF),
CGF.ConvertTypeForMem(DestTy));
LValue DestLV = CGF.MakeAddrLValue(Addr, DestTy);
DestLV.setTBAAInfo(TBAAAccessInfo::getMayAliasInfo());
@@ -1136,7 +1137,11 @@ ComplexPairTy CodeGenFunction::EmitLoadOfComplex(LValue src,
LValue CodeGenFunction::EmitComplexAssignmentLValue(const BinaryOperator *E) {
assert(E->getOpcode() == BO_Assign);
ComplexPairTy Val; // ignored
- return ComplexExprEmitter(*this).EmitBinAssignLValue(E, Val);
+ LValue LVal = ComplexExprEmitter(*this).EmitBinAssignLValue(E, Val);
+ if (getLangOpts().OpenMP)
+ CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(*this,
+ E->getLHS());
+ return LVal;
}
typedef ComplexPairTy (ComplexExprEmitter::*CompoundFunc)(
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index 96e8c9c0d0e6..46ed90a20264 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -10,20 +10,21 @@
//
//===----------------------------------------------------------------------===//
-#include "CodeGenFunction.h"
#include "CGCXXABI.h"
#include "CGObjCRuntime.h"
#include "CGRecordLayout.h"
+#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "ConstantEmitter.h"
#include "TargetInfo.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Builtins.h"
-#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Sequence.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
@@ -1173,7 +1174,7 @@ public:
llvm::Constant *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E,
QualType T) {
- return Visit(E->GetTemporaryExpr(), T);
+ return Visit(E->getSubExpr(), T);
}
llvm::Constant *EmitArrayInitialization(InitListExpr *ILE, QualType T) {
@@ -1728,7 +1729,7 @@ struct ConstantLValue {
/*implicit*/ ConstantLValue(llvm::Constant *value,
bool hasOffsetApplied = false)
- : Value(value), HasOffsetApplied(false) {}
+ : Value(value), HasOffsetApplied(hasOffsetApplied) {}
/*implicit*/ ConstantLValue(ConstantAddress address)
: ConstantLValue(address.getPointer()) {}
@@ -2003,8 +2004,8 @@ ConstantLValueEmitter::VisitMaterializeTemporaryExpr(
assert(E->getStorageDuration() == SD_Static);
SmallVector<const Expr *, 2> CommaLHSs;
SmallVector<SubobjectAdjustment, 2> Adjustments;
- const Expr *Inner = E->GetTemporaryExpr()
- ->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
+ const Expr *Inner =
+ E->getSubExpr()->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
return CGM.GetAddrOfGlobalTemporary(E, Inner);
}
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 55a413a2a717..3f23fe11e4f5 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -14,11 +14,13 @@
#include "CGCleanup.h"
#include "CGDebugInfo.h"
#include "CGObjCRuntime.h"
+#include "CGOpenMPRuntime.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "ConstantEmitter.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
@@ -34,6 +36,7 @@
#include "llvm/IR/GetElementPtrTypeIterator.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/IntrinsicsPowerPC.h"
#include "llvm/IR/Module.h"
#include <cstdarg>
@@ -615,7 +618,7 @@ public:
if (isa<MemberPointerType>(E->getType())) // never sugared
return CGF.CGM.getMemberPointerConstant(E);
- return EmitLValue(E->getSubExpr()).getPointer();
+ return EmitLValue(E->getSubExpr()).getPointer(CGF);
}
Value *VisitUnaryDeref(const UnaryOperator *E) {
if (E->getType()->isVoidType())
@@ -644,8 +647,8 @@ public:
auto &Ctx = CGF.getContext();
APValue Evaluated =
SLE->EvaluateInContext(Ctx, CGF.CurSourceLocExprScope.getDefaultExpr());
- return ConstantEmitter(CGF.CGM, &CGF)
- .emitAbstract(SLE->getLocation(), Evaluated, SLE->getType());
+ return ConstantEmitter(CGF).emitAbstract(SLE->getLocation(), Evaluated,
+ SLE->getType());
}
Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
@@ -795,17 +798,17 @@ public:
// Comparisons.
Value *EmitCompare(const BinaryOperator *E, llvm::CmpInst::Predicate UICmpOpc,
llvm::CmpInst::Predicate SICmpOpc,
- llvm::CmpInst::Predicate FCmpOpc);
-#define VISITCOMP(CODE, UI, SI, FP) \
+ llvm::CmpInst::Predicate FCmpOpc, bool IsSignaling);
+#define VISITCOMP(CODE, UI, SI, FP, SIG) \
Value *VisitBin##CODE(const BinaryOperator *E) { \
return EmitCompare(E, llvm::ICmpInst::UI, llvm::ICmpInst::SI, \
- llvm::FCmpInst::FP); }
- VISITCOMP(LT, ICMP_ULT, ICMP_SLT, FCMP_OLT)
- VISITCOMP(GT, ICMP_UGT, ICMP_SGT, FCMP_OGT)
- VISITCOMP(LE, ICMP_ULE, ICMP_SLE, FCMP_OLE)
- VISITCOMP(GE, ICMP_UGE, ICMP_SGE, FCMP_OGE)
- VISITCOMP(EQ, ICMP_EQ , ICMP_EQ , FCMP_OEQ)
- VISITCOMP(NE, ICMP_NE , ICMP_NE , FCMP_UNE)
+ llvm::FCmpInst::FP, SIG); }
+ VISITCOMP(LT, ICMP_ULT, ICMP_SLT, FCMP_OLT, true)
+ VISITCOMP(GT, ICMP_UGT, ICMP_SGT, FCMP_OGT, true)
+ VISITCOMP(LE, ICMP_ULE, ICMP_SLE, FCMP_OLE, true)
+ VISITCOMP(GE, ICMP_UGE, ICMP_SGE, FCMP_OGE, true)
+ VISITCOMP(EQ, ICMP_EQ , ICMP_EQ , FCMP_OEQ, false)
+ VISITCOMP(NE, ICMP_NE , ICMP_NE , FCMP_UNE, false)
#undef VISITCOMP
Value *VisitBinAssign (const BinaryOperator *E);
@@ -976,6 +979,11 @@ EmitIntegerTruncationCheckHelper(Value *Src, QualType SrcType, Value *Dst,
return std::make_pair(Kind, std::make_pair(Check, Mask));
}
+static bool PromotionIsPotentiallyEligibleForImplicitIntegerConversionCheck(
+ QualType SrcType, QualType DstType) {
+ return SrcType->isIntegerType() && DstType->isIntegerType();
+}
+
void ScalarExprEmitter::EmitIntegerTruncationCheck(Value *Src, QualType SrcType,
Value *Dst, QualType DstType,
SourceLocation Loc) {
@@ -984,7 +992,8 @@ void ScalarExprEmitter::EmitIntegerTruncationCheck(Value *Src, QualType SrcType,
// We only care about int->int conversions here.
// We ignore conversions to/from pointer and/or bool.
- if (!(SrcType->isIntegerType() && DstType->isIntegerType()))
+ if (!PromotionIsPotentiallyEligibleForImplicitIntegerConversionCheck(SrcType,
+ DstType))
return;
unsigned SrcBits = Src->getType()->getScalarSizeInBits();
@@ -1095,7 +1104,8 @@ void ScalarExprEmitter::EmitIntegerSignChangeCheck(Value *Src, QualType SrcType,
// We only care about int->int conversions here.
// We ignore conversions to/from pointer and/or bool.
- if (!(SrcType->isIntegerType() && DstType->isIntegerType()))
+ if (!PromotionIsPotentiallyEligibleForImplicitIntegerConversionCheck(SrcType,
+ DstType))
return;
bool SrcSigned = SrcType->isSignedIntegerOrEnumerationType();
@@ -1972,7 +1982,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
case CK_LValueBitCast:
case CK_ObjCObjectLValueCast: {
- Address Addr = EmitLValue(E).getAddress();
+ Address Addr = EmitLValue(E).getAddress(CGF);
Addr = Builder.CreateElementBitCast(Addr, CGF.ConvertTypeForMem(DestTy));
LValue LV = CGF.MakeAddrLValue(Addr, DestTy);
return EmitLoadOfLValue(LV, CE->getExprLoc());
@@ -1980,7 +1990,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
case CK_LValueToRValueBitCast: {
LValue SourceLVal = CGF.EmitLValue(E);
- Address Addr = Builder.CreateElementBitCast(SourceLVal.getAddress(),
+ Address Addr = Builder.CreateElementBitCast(SourceLVal.getAddress(CGF),
CGF.ConvertTypeForMem(DestTy));
LValue DestLV = CGF.MakeAddrLValue(Addr, DestTy);
DestLV.setTBAAInfo(TBAAAccessInfo::getMayAliasInfo());
@@ -2098,7 +2108,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
case CK_ArrayToPointerDecay:
return CGF.EmitArrayToPointerDecay(E).getPointer();
case CK_FunctionToPointerDecay:
- return EmitLValue(E).getPointer();
+ return EmitLValue(E).getPointer(CGF);
case CK_NullToPointer:
if (MustVisitNullValue(E))
@@ -2346,10 +2356,29 @@ llvm::Value *ScalarExprEmitter::EmitIncDecConsiderOverflowBehavior(
llvm_unreachable("Unknown SignedOverflowBehaviorTy");
}
+namespace {
+/// Handles check and update for lastprivate conditional variables.
+class OMPLastprivateConditionalUpdateRAII {
+private:
+ CodeGenFunction &CGF;
+ const UnaryOperator *E;
+
+public:
+ OMPLastprivateConditionalUpdateRAII(CodeGenFunction &CGF,
+ const UnaryOperator *E)
+ : CGF(CGF), E(E) {}
+ ~OMPLastprivateConditionalUpdateRAII() {
+ if (CGF.getLangOpts().OpenMP)
+ CGF.CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(
+ CGF, E->getSubExpr());
+ }
+};
+} // namespace
+
llvm::Value *
ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
bool isInc, bool isPre) {
-
+ OMPLastprivateConditionalUpdateRAII OMPRegion(CGF, E);
QualType type = E->getSubExpr()->getType();
llvm::PHINode *atomicPHI = nullptr;
llvm::Value *value;
@@ -2363,14 +2392,14 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
if (isInc && type->isBooleanType()) {
llvm::Value *True = CGF.EmitToMemory(Builder.getTrue(), type);
if (isPre) {
- Builder.CreateStore(True, LV.getAddress(), LV.isVolatileQualified())
- ->setAtomic(llvm::AtomicOrdering::SequentiallyConsistent);
+ Builder.CreateStore(True, LV.getAddress(CGF), LV.isVolatileQualified())
+ ->setAtomic(llvm::AtomicOrdering::SequentiallyConsistent);
return Builder.getTrue();
}
// For atomic bool increment, we just store true and return it for
// preincrement, do an atomic swap with true for postincrement
return Builder.CreateAtomicRMW(
- llvm::AtomicRMWInst::Xchg, LV.getPointer(), True,
+ llvm::AtomicRMWInst::Xchg, LV.getPointer(CGF), True,
llvm::AtomicOrdering::SequentiallyConsistent);
}
// Special case for atomic increment / decrement on integers, emit
@@ -2387,8 +2416,9 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
llvm::Instruction::Sub;
llvm::Value *amt = CGF.EmitToMemory(
llvm::ConstantInt::get(ConvertType(type), 1, true), type);
- llvm::Value *old = Builder.CreateAtomicRMW(aop,
- LV.getPointer(), amt, llvm::AtomicOrdering::SequentiallyConsistent);
+ llvm::Value *old =
+ Builder.CreateAtomicRMW(aop, LV.getPointer(CGF), amt,
+ llvm::AtomicOrdering::SequentiallyConsistent);
return isPre ? Builder.CreateBinOp(op, old, amt) : old;
}
value = EmitLoadOfLValue(LV, E->getExprLoc());
@@ -2419,9 +2449,51 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
// Most common case by far: integer increment.
} else if (type->isIntegerType()) {
- // Note that signed integer inc/dec with width less than int can't
- // overflow because of promotion rules; we're just eliding a few steps here.
- if (E->canOverflow() && type->isSignedIntegerOrEnumerationType()) {
+ QualType promotedType;
+ bool canPerformLossyDemotionCheck = false;
+ if (type->isPromotableIntegerType()) {
+ promotedType = CGF.getContext().getPromotedIntegerType(type);
+ assert(promotedType != type && "Shouldn't promote to the same type.");
+ canPerformLossyDemotionCheck = true;
+ canPerformLossyDemotionCheck &=
+ CGF.getContext().getCanonicalType(type) !=
+ CGF.getContext().getCanonicalType(promotedType);
+ canPerformLossyDemotionCheck &=
+ PromotionIsPotentiallyEligibleForImplicitIntegerConversionCheck(
+ type, promotedType);
+ assert((!canPerformLossyDemotionCheck ||
+ type->isSignedIntegerOrEnumerationType() ||
+ promotedType->isSignedIntegerOrEnumerationType() ||
+ ConvertType(type)->getScalarSizeInBits() ==
+ ConvertType(promotedType)->getScalarSizeInBits()) &&
+ "The following check expects that if we do promotion to different "
+ "underlying canonical type, at least one of the types (either "
+ "base or promoted) will be signed, or the bitwidths will match.");
+ }
+ if (CGF.SanOpts.hasOneOf(
+ SanitizerKind::ImplicitIntegerArithmeticValueChange) &&
+ canPerformLossyDemotionCheck) {
+ // While `x += 1` (for `x` with width less than int) is modeled as
+ // promotion+arithmetics+demotion, and we can catch lossy demotion with
+ // ease; inc/dec with width less than int can't overflow because of
+ // promotion rules, so we omit promotion+demotion, which means that we can
+ // not catch lossy "demotion". Because we still want to catch these cases
+ // when the sanitizer is enabled, we perform the promotion, then perform
+ // the increment/decrement in the wider type, and finally
+ // perform the demotion. This will catch lossy demotions.
+
+ value = EmitScalarConversion(value, type, promotedType, E->getExprLoc());
+ Value *amt = llvm::ConstantInt::get(value->getType(), amount, true);
+ value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec");
+ // Do pass non-default ScalarConversionOpts so that sanitizer check is
+ // emitted.
+ value = EmitScalarConversion(value, promotedType, type, E->getExprLoc(),
+ ScalarConversionOpts(CGF.SanOpts));
+
+ // Note that signed integer inc/dec with width less than int can't
+ // overflow because of promotion rules; we're just eliding a few steps
+ // here.
+ } else if (E->canOverflow() && type->isSignedIntegerOrEnumerationType()) {
value = EmitIncDecConsiderOverflowBehavior(E, value, isInc);
} else if (E->canOverflow() && type->isUnsignedIntegerType() &&
CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) {
@@ -2849,7 +2921,8 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) &&
CGF.getLangOpts().getSignedOverflowBehavior() !=
LangOptions::SOB_Trapping) {
- llvm::AtomicRMWInst::BinOp aop = llvm::AtomicRMWInst::BAD_BINOP;
+ llvm::AtomicRMWInst::BinOp AtomicOp = llvm::AtomicRMWInst::BAD_BINOP;
+ llvm::Instruction::BinaryOps Op;
switch (OpInfo.Opcode) {
// We don't have atomicrmw operands for *, %, /, <<, >>
case BO_MulAssign: case BO_DivAssign:
@@ -2858,30 +2931,40 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
case BO_ShrAssign:
break;
case BO_AddAssign:
- aop = llvm::AtomicRMWInst::Add;
+ AtomicOp = llvm::AtomicRMWInst::Add;
+ Op = llvm::Instruction::Add;
break;
case BO_SubAssign:
- aop = llvm::AtomicRMWInst::Sub;
+ AtomicOp = llvm::AtomicRMWInst::Sub;
+ Op = llvm::Instruction::Sub;
break;
case BO_AndAssign:
- aop = llvm::AtomicRMWInst::And;
+ AtomicOp = llvm::AtomicRMWInst::And;
+ Op = llvm::Instruction::And;
break;
case BO_XorAssign:
- aop = llvm::AtomicRMWInst::Xor;
+ AtomicOp = llvm::AtomicRMWInst::Xor;
+ Op = llvm::Instruction::Xor;
break;
case BO_OrAssign:
- aop = llvm::AtomicRMWInst::Or;
+ AtomicOp = llvm::AtomicRMWInst::Or;
+ Op = llvm::Instruction::Or;
break;
default:
llvm_unreachable("Invalid compound assignment type");
}
- if (aop != llvm::AtomicRMWInst::BAD_BINOP) {
- llvm::Value *amt = CGF.EmitToMemory(
+ if (AtomicOp != llvm::AtomicRMWInst::BAD_BINOP) {
+ llvm::Value *Amt = CGF.EmitToMemory(
EmitScalarConversion(OpInfo.RHS, E->getRHS()->getType(), LHSTy,
E->getExprLoc()),
LHSTy);
- Builder.CreateAtomicRMW(aop, LHSLV.getPointer(), amt,
+ Value *OldVal = Builder.CreateAtomicRMW(
+ AtomicOp, LHSLV.getPointer(CGF), Amt,
llvm::AtomicOrdering::SequentiallyConsistent);
+
+ // Since operation is atomic, the result type is guaranteed to be the
+ // same as the input in LLVM terms.
+ Result = Builder.CreateBinOp(Op, OldVal, Amt);
return LHSLV;
}
}
@@ -2934,6 +3017,9 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
else
CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV);
+ if (CGF.getLangOpts().OpenMP)
+ CGF.CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(CGF,
+ E->getLHS());
return LHSLV;
}
@@ -3201,10 +3287,10 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
expr->getRHS()))
return CGF.Builder.CreateIntToPtr(index, pointer->getType());
- if (width != DL.getTypeSizeInBits(PtrTy)) {
+ if (width != DL.getIndexTypeSizeInBits(PtrTy)) {
// Zero-extend or sign-extend the pointer value according to
// whether the index is signed or not.
- index = CGF.Builder.CreateIntCast(index, DL.getIntPtrType(PtrTy), isSigned,
+ index = CGF.Builder.CreateIntCast(index, DL.getIndexType(PtrTy), isSigned,
"idx.ext");
}
@@ -3258,7 +3344,7 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
// GNU void* casts amount to no-ops since our void* type is i8*, but this is
// future proof.
if (elementType->isVoidType() || elementType->isFunctionType()) {
- Value *result = CGF.Builder.CreateBitCast(pointer, CGF.VoidPtrTy);
+ Value *result = CGF.EmitCastToVoidPtr(pointer);
result = CGF.Builder.CreateGEP(result, index, "add.ptr");
return CGF.Builder.CreateBitCast(result, pointer->getType());
}
@@ -3282,17 +3368,10 @@ static Value* buildFMulAdd(llvm::BinaryOperator *MulOp, Value *Addend,
Value *MulOp0 = MulOp->getOperand(0);
Value *MulOp1 = MulOp->getOperand(1);
- if (negMul) {
- MulOp0 =
- Builder.CreateFSub(
- llvm::ConstantFP::getZeroValueForNegation(MulOp0->getType()), MulOp0,
- "neg");
- } else if (negAdd) {
- Addend =
- Builder.CreateFSub(
- llvm::ConstantFP::getZeroValueForNegation(Addend->getType()), Addend,
- "neg");
- }
+ if (negMul)
+ MulOp0 = Builder.CreateFNeg(MulOp0, "neg");
+ if (negAdd)
+ Addend = Builder.CreateFNeg(Addend, "neg");
Value *FMulAdd = Builder.CreateCall(
CGF.CGM.getIntrinsic(llvm::Intrinsic::fmuladd, Addend->getType()),
@@ -3725,7 +3804,8 @@ static llvm::Intrinsic::ID GetIntrinsic(IntrinsicType IT,
Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,
llvm::CmpInst::Predicate UICmpOpc,
llvm::CmpInst::Predicate SICmpOpc,
- llvm::CmpInst::Predicate FCmpOpc) {
+ llvm::CmpInst::Predicate FCmpOpc,
+ bool IsSignaling) {
TestAndClearIgnoreResultAssign();
Value *Result;
QualType LHSTy = E->getLHS()->getType();
@@ -3755,8 +3835,7 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,
*SecondVecArg = RHS;
QualType ElTy = LHSTy->castAs<VectorType>()->getElementType();
- const BuiltinType *BTy = ElTy->getAs<BuiltinType>();
- BuiltinType::Kind ElementKind = BTy->getKind();
+ BuiltinType::Kind ElementKind = ElTy->castAs<BuiltinType>()->getKind();
switch(E->getOpcode()) {
default: llvm_unreachable("is not a comparison operation");
@@ -3821,7 +3900,10 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,
if (BOInfo.isFixedPointBinOp()) {
Result = EmitFixedPointBinOp(BOInfo);
} else if (LHS->getType()->isFPOrFPVectorTy()) {
- Result = Builder.CreateFCmp(FCmpOpc, LHS, RHS, "cmp");
+ if (!IsSignaling)
+ Result = Builder.CreateFCmp(FCmpOpc, LHS, RHS, "cmp");
+ else
+ Result = Builder.CreateFCmpS(FCmpOpc, LHS, RHS, "cmp");
} else if (LHSTy->hasSignedIntegerRepresentation()) {
Result = Builder.CreateICmp(SICmpOpc, LHS, RHS, "cmp");
} else {
@@ -3878,6 +3960,8 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,
Value *ResultR, *ResultI;
if (CETy->isRealFloatingType()) {
+ // As complex comparisons can only be equality comparisons, they
+ // are never signaling comparisons.
ResultR = Builder.CreateFCmp(FCmpOpc, LHS.first, RHS.first, "cmp.r");
ResultI = Builder.CreateFCmp(FCmpOpc, LHS.second, RHS.second, "cmp.i");
} else {
@@ -3922,7 +4006,7 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
case Qualifiers::OCL_Weak:
RHS = Visit(E->getRHS());
LHS = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
- RHS = CGF.EmitARCStoreWeak(LHS.getAddress(), RHS, Ignore);
+ RHS = CGF.EmitARCStoreWeak(LHS.getAddress(CGF), RHS, Ignore);
break;
case Qualifiers::OCL_None:
@@ -4227,6 +4311,21 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
return tmp5;
}
+ if (condExpr->getType()->isVectorType()) {
+ CGF.incrementProfileCounter(E);
+
+ llvm::Value *CondV = CGF.EmitScalarExpr(condExpr);
+ llvm::Value *LHS = Visit(lhsExpr);
+ llvm::Value *RHS = Visit(rhsExpr);
+
+ llvm::Type *CondType = ConvertType(condExpr->getType());
+ auto *VecTy = cast<llvm::VectorType>(CondType);
+ llvm::Value *ZeroVec = llvm::Constant::getNullValue(VecTy);
+
+ CondV = Builder.CreateICmpNE(CondV, ZeroVec, "vector_cond");
+ return Builder.CreateSelect(CondV, LHS, RHS, "vector_select");
+ }
+
// If this is a really simple expression (like x ? 4 : 5), emit this as a
// select instead of as control flow. We can only do this if it is cheap and
// safe to evaluate the LHS and RHS unconditionally.
@@ -4483,7 +4582,7 @@ LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) {
if (BaseExpr->isRValue()) {
Addr = Address(EmitScalarExpr(BaseExpr), getPointerAlign());
} else {
- Addr = EmitLValue(BaseExpr).getAddress();
+ Addr = EmitLValue(BaseExpr).getAddress(*this);
}
// Cast the address to Class*.
diff --git a/clang/lib/CodeGen/CGLoopInfo.cpp b/clang/lib/CodeGen/CGLoopInfo.cpp
index c21d4feee7a8..e4b184eb8798 100644
--- a/clang/lib/CodeGen/CGLoopInfo.cpp
+++ b/clang/lib/CodeGen/CGLoopInfo.cpp
@@ -270,14 +270,6 @@ LoopInfo::createLoopVectorizeMetadata(const LoopAttributes &Attrs,
// Setting vectorize.width
if (Attrs.VectorizeWidth > 0) {
- // This implies vectorize.enable = true, but only add it when it is not
- // already enabled.
- if (Attrs.VectorizeEnable != LoopAttributes::Enable)
- Args.push_back(
- MDNode::get(Ctx, {MDString::get(Ctx, "llvm.loop.vectorize.enable"),
- ConstantAsMetadata::get(ConstantInt::get(
- llvm::Type::getInt1Ty(Ctx), 1))}));
-
Metadata *Vals[] = {
MDString::get(Ctx, "llvm.loop.vectorize.width"),
ConstantAsMetadata::get(ConstantInt::get(llvm::Type::getInt32Ty(Ctx),
@@ -294,17 +286,18 @@ LoopInfo::createLoopVectorizeMetadata(const LoopAttributes &Attrs,
Args.push_back(MDNode::get(Ctx, Vals));
}
- // Setting vectorize.enable
+ // vectorize.enable is set if:
+ // 1) loop hint vectorize.enable is set, or
+ // 2) it is implied when vectorize.predicate is set, or
+ // 3) it is implied when vectorize.width is set.
if (Attrs.VectorizeEnable != LoopAttributes::Unspecified ||
- IsVectorPredicateEnabled) {
- Metadata *Vals[] = {
- MDString::get(Ctx, "llvm.loop.vectorize.enable"),
- ConstantAsMetadata::get(ConstantInt::get(
- llvm::Type::getInt1Ty(Ctx),
- IsVectorPredicateEnabled
- ? true
- : (Attrs.VectorizeEnable == LoopAttributes::Enable)))};
- Args.push_back(MDNode::get(Ctx, Vals));
+ IsVectorPredicateEnabled ||
+ Attrs.VectorizeWidth > 1 ) {
+ bool AttrVal = Attrs.VectorizeEnable != LoopAttributes::Disable;
+ Args.push_back(
+ MDNode::get(Ctx, {MDString::get(Ctx, "llvm.loop.vectorize.enable"),
+ ConstantAsMetadata::get(ConstantInt::get(
+ llvm::Type::getInt1Ty(Ctx), AttrVal))}));
}
if (FollowupHasTransforms)
diff --git a/clang/lib/CodeGen/CGNonTrivialStruct.cpp b/clang/lib/CodeGen/CGNonTrivialStruct.cpp
index 05615aa12881..d5f378c52232 100644
--- a/clang/lib/CodeGen/CGNonTrivialStruct.cpp
+++ b/clang/lib/CodeGen/CGNonTrivialStruct.cpp
@@ -707,7 +707,7 @@ struct GenMoveConstructor : GenBinaryFunc<GenMoveConstructor, true> {
LValue SrcLV = CGF->MakeAddrLValue(Addrs[SrcIdx], QT);
llvm::Value *SrcVal =
CGF->EmitLoadOfLValue(SrcLV, SourceLocation()).getScalarVal();
- CGF->EmitStoreOfScalar(getNullForVariable(SrcLV.getAddress()), SrcLV);
+ CGF->EmitStoreOfScalar(getNullForVariable(SrcLV.getAddress(*CGF)), SrcLV);
CGF->EmitStoreOfScalar(SrcVal, CGF->MakeAddrLValue(Addrs[DstIdx], QT),
/* isInitialization */ true);
}
@@ -770,7 +770,7 @@ struct GenMoveAssignment : GenBinaryFunc<GenMoveAssignment, true> {
LValue SrcLV = CGF->MakeAddrLValue(Addrs[SrcIdx], QT);
llvm::Value *SrcVal =
CGF->EmitLoadOfLValue(SrcLV, SourceLocation()).getScalarVal();
- CGF->EmitStoreOfScalar(getNullForVariable(SrcLV.getAddress()), SrcLV);
+ CGF->EmitStoreOfScalar(getNullForVariable(SrcLV.getAddress(*CGF)), SrcLV);
LValue DstLV = CGF->MakeAddrLValue(Addrs[DstIdx], QT);
llvm::Value *DstVal =
CGF->EmitLoadOfLValue(DstLV, SourceLocation()).getScalarVal();
@@ -806,7 +806,8 @@ void CodeGenFunction::destroyNonTrivialCStruct(CodeGenFunction &CGF,
// such structure.
void CodeGenFunction::defaultInitNonTrivialCStructVar(LValue Dst) {
GenDefaultInitialize Gen(getContext());
- Address DstPtr = Builder.CreateBitCast(Dst.getAddress(), CGM.Int8PtrPtrTy);
+ Address DstPtr =
+ Builder.CreateBitCast(Dst.getAddress(*this), CGM.Int8PtrPtrTy);
Gen.setCGF(this);
QualType QT = Dst.getType();
QT = Dst.isVolatile() ? QT.withVolatile() : QT;
@@ -817,6 +818,7 @@ template <class G, size_t N>
static void callSpecialFunction(G &&Gen, StringRef FuncName, QualType QT,
bool IsVolatile, CodeGenFunction &CGF,
std::array<Address, N> Addrs) {
+ auto SetArtificialLoc = ApplyDebugLocation::CreateArtificial(CGF);
for (unsigned I = 0; I < N; ++I)
Addrs[I] = CGF.Builder.CreateBitCast(Addrs[I], CGF.CGM.Int8PtrPtrTy);
QT = IsVolatile ? QT.withVolatile() : QT;
@@ -849,7 +851,7 @@ getSpecialFunction(G &&Gen, StringRef FuncName, QualType QT, bool IsVolatile,
// Functions to emit calls to the special functions of a non-trivial C struct.
void CodeGenFunction::callCStructDefaultConstructor(LValue Dst) {
bool IsVolatile = Dst.isVolatile();
- Address DstPtr = Dst.getAddress();
+ Address DstPtr = Dst.getAddress(*this);
QualType QT = Dst.getType();
GenDefaultInitializeFuncName GenName(DstPtr.getAlignment(), getContext());
std::string FuncName = GenName.getName(QT, IsVolatile);
@@ -873,7 +875,7 @@ std::string CodeGenFunction::getNonTrivialDestructorStr(QualType QT,
void CodeGenFunction::callCStructDestructor(LValue Dst) {
bool IsVolatile = Dst.isVolatile();
- Address DstPtr = Dst.getAddress();
+ Address DstPtr = Dst.getAddress(*this);
QualType QT = Dst.getType();
GenDestructorFuncName GenName("__destructor_", DstPtr.getAlignment(),
getContext());
@@ -884,7 +886,7 @@ void CodeGenFunction::callCStructDestructor(LValue Dst) {
void CodeGenFunction::callCStructCopyConstructor(LValue Dst, LValue Src) {
bool IsVolatile = Dst.isVolatile() || Src.isVolatile();
- Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress();
+ Address DstPtr = Dst.getAddress(*this), SrcPtr = Src.getAddress(*this);
QualType QT = Dst.getType();
GenBinaryFuncName<false> GenName("__copy_constructor_", DstPtr.getAlignment(),
SrcPtr.getAlignment(), getContext());
@@ -898,7 +900,7 @@ void CodeGenFunction::callCStructCopyAssignmentOperator(LValue Dst, LValue Src
) {
bool IsVolatile = Dst.isVolatile() || Src.isVolatile();
- Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress();
+ Address DstPtr = Dst.getAddress(*this), SrcPtr = Src.getAddress(*this);
QualType QT = Dst.getType();
GenBinaryFuncName<false> GenName("__copy_assignment_", DstPtr.getAlignment(),
SrcPtr.getAlignment(), getContext());
@@ -909,7 +911,7 @@ void CodeGenFunction::callCStructCopyAssignmentOperator(LValue Dst, LValue Src
void CodeGenFunction::callCStructMoveConstructor(LValue Dst, LValue Src) {
bool IsVolatile = Dst.isVolatile() || Src.isVolatile();
- Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress();
+ Address DstPtr = Dst.getAddress(*this), SrcPtr = Src.getAddress(*this);
QualType QT = Dst.getType();
GenBinaryFuncName<true> GenName("__move_constructor_", DstPtr.getAlignment(),
SrcPtr.getAlignment(), getContext());
@@ -923,7 +925,7 @@ void CodeGenFunction::callCStructMoveAssignmentOperator(LValue Dst, LValue Src
) {
bool IsVolatile = Dst.isVolatile() || Src.isVolatile();
- Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress();
+ Address DstPtr = Dst.getAddress(*this), SrcPtr = Src.getAddress(*this);
QualType QT = Dst.getType();
GenBinaryFuncName<true> GenName("__move_assignment_", DstPtr.getAlignment(),
SrcPtr.getAlignment(), getContext());
diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp
index 1fa72678081a..90fca2836d99 100644
--- a/clang/lib/CodeGen/CGObjC.cpp
+++ b/clang/lib/CodeGen/CGObjC.cpp
@@ -17,6 +17,7 @@
#include "ConstantEmitter.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/Diagnostic.h"
@@ -430,6 +431,20 @@ tryGenerateSpecializedMessageSend(CodeGenFunction &CGF, QualType ResultType,
return None;
}
+CodeGen::RValue CGObjCRuntime::GeneratePossiblySpecializedMessageSend(
+ CodeGenFunction &CGF, ReturnValueSlot Return, QualType ResultType,
+ Selector Sel, llvm::Value *Receiver, const CallArgList &Args,
+ const ObjCInterfaceDecl *OID, const ObjCMethodDecl *Method,
+ bool isClassMessage) {
+ if (Optional<llvm::Value *> SpecializedResult =
+ tryGenerateSpecializedMessageSend(CGF, ResultType, Receiver, Args,
+ Sel, Method, isClassMessage)) {
+ return RValue::get(SpecializedResult.getValue());
+ }
+ return GenerateMessageSend(CGF, Return, ResultType, Sel, Receiver, Args, OID,
+ Method);
+}
+
/// 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.
@@ -446,38 +461,39 @@ tryEmitSpecializedAllocInit(CodeGenFunction &CGF, const ObjCMessageExpr *OME) {
Sel.getNameForSlot(0) != "init")
return None;
- // Okay, this is '[receiver init]', check if 'receiver' is '[cls alloc]' or
- // we are in an ObjC class method and 'receiver' is '[self alloc]'.
+ // 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;
Selector SubSel = SubOME->getSelector();
- // Check if we are in an ObjC class method and the receiver expression is
- // 'self'.
- const Expr *SelfInClassMethod = nullptr;
- if (const auto *CurMD = dyn_cast_or_null<ObjCMethodDecl>(CGF.CurFuncDecl))
- if (CurMD->isClassMethod())
- if ((SelfInClassMethod = SubOME->getInstanceReceiver()))
- if (!SelfInClassMethod->isObjCSelfExpr())
- SelfInClassMethod = nullptr;
-
- if ((SubOME->getReceiverKind() != ObjCMessageExpr::Class &&
- !SelfInClassMethod) || !SubOME->getType()->isObjCObjectPointerType() ||
+ if (!SubOME->getType()->isObjCObjectPointerType() ||
!SubSel.isUnarySelector() || SubSel.getNameForSlot(0) != "alloc")
return None;
- llvm::Value *Receiver;
- if (SelfInClassMethod) {
- Receiver = CGF.EmitScalarExpr(SelfInClassMethod);
- } else {
+ llvm::Value *Receiver = nullptr;
+ switch (SubOME->getReceiverKind()) {
+ case ObjCMessageExpr::Instance:
+ if (!SubOME->getInstanceReceiver()->getType()->isObjCClassType())
+ return None;
+ Receiver = CGF.EmitScalarExpr(SubOME->getInstanceReceiver());
+ break;
+
+ case ObjCMessageExpr::Class: {
QualType ReceiverType = SubOME->getClassReceiver();
- const ObjCObjectType *ObjTy = ReceiverType->getAs<ObjCObjectType>();
+ const ObjCObjectType *ObjTy = ReceiverType->castAs<ObjCObjectType>();
const ObjCInterfaceDecl *ID = ObjTy->getInterface();
assert(ID && "null interface should be impossible here");
Receiver = CGF.CGM.getObjCRuntime().GetClass(CGF, ID);
+ break;
+ }
+ case ObjCMessageExpr::SuperInstance:
+ case ObjCMessageExpr::SuperClass:
+ return None;
}
+
return CGF.EmitObjCAllocInit(Receiver, CGF.ConvertType(OME->getType()));
}
@@ -497,7 +513,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
method->getMethodFamily() == OMF_retain) {
if (auto lvalueExpr = findWeakLValue(E->getInstanceReceiver())) {
LValue lvalue = EmitLValue(lvalueExpr);
- llvm::Value *result = EmitARCLoadWeakRetained(lvalue.getAddress());
+ llvm::Value *result = EmitARCLoadWeakRetained(lvalue.getAddress(*this));
return AdjustObjCObjectType(*this, E->getType(), RValue::get(result));
}
}
@@ -525,10 +541,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
switch (E->getReceiverKind()) {
case ObjCMessageExpr::Instance:
ReceiverType = E->getInstanceReceiver()->getType();
- if (auto *OMD = dyn_cast_or_null<ObjCMethodDecl>(CurFuncDecl))
- if (OMD->isClassMethod())
- if (E->getInstanceReceiver()->isObjCSelfExpr())
- isClassMessage = true;
+ isClassMessage = ReceiverType->isObjCClassType();
if (retainSelf) {
TryEmitResult ter = tryEmitARCRetainScalarExpr(*this,
E->getInstanceReceiver());
@@ -540,9 +553,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
case ObjCMessageExpr::Class: {
ReceiverType = E->getClassReceiver();
- const ObjCObjectType *ObjTy = ReceiverType->getAs<ObjCObjectType>();
- assert(ObjTy && "Invalid Objective-C class message send");
- OID = ObjTy->getInterface();
+ OID = ReceiverType->castAs<ObjCObjectType>()->getInterface();
assert(OID && "Invalid Objective-C class message send");
Receiver = Runtime.GetClass(*this, OID);
isClassMessage = true;
@@ -611,16 +622,9 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
method);
} else {
// Call runtime methods directly if we can.
- if (Optional<llvm::Value *> SpecializedResult =
- tryGenerateSpecializedMessageSend(*this, ResultType, Receiver, Args,
- E->getSelector(), method,
- isClassMessage)) {
- result = RValue::get(SpecializedResult.getValue());
- } else {
- result = Runtime.GenerateMessageSend(*this, Return, ResultType,
- E->getSelector(), Receiver, Args,
- OID, method);
- }
+ result = Runtime.GeneratePossiblySpecializedMessageSend(
+ *this, Return, ResultType, E->getSelector(), Receiver, Args, OID,
+ method, isClassMessage);
}
// For delegate init calls in ARC, implicitly store the result of
@@ -683,7 +687,13 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
llvm::Function *Fn = CGM.getObjCRuntime().GenerateMethod(OMD, CD);
const CGFunctionInfo &FI = CGM.getTypes().arrangeObjCMethodDeclaration(OMD);
- CGM.SetInternalFunctionAttributes(OMD, Fn, FI);
+ if (OMD->isDirectMethod()) {
+ Fn->setVisibility(llvm::Function::HiddenVisibility);
+ CGM.SetLLVMFunctionAttributes(OMD, FI, Fn);
+ CGM.SetLLVMFunctionAttributesForDefinition(OMD, Fn);
+ } else {
+ CGM.SetInternalFunctionAttributes(OMD, Fn, FI);
+ }
args.push_back(OMD->getSelfDecl());
args.push_back(OMD->getCmdDecl());
@@ -696,6 +706,14 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
StartFunction(OMD, OMD->getReturnType(), Fn, FI, args,
OMD->getLocation(), StartLoc);
+ if (OMD->isDirectMethod()) {
+ // This function is a direct call, it has to implement a nil check
+ // on entry.
+ //
+ // TODO: possibly have several entry points to elide the check
+ CGM.getObjCRuntime().GenerateDirectMethodPrologue(*this, Fn, OMD, CD);
+ }
+
// In ARC, certain methods get an extra cleanup.
if (CGM.getLangOpts().ObjCAutoRefCount &&
OMD->isInstanceMethod() &&
@@ -728,8 +746,8 @@ static void emitStructGetterCall(CodeGenFunction &CGF, ObjCIvarDecl *ivar,
ASTContext &Context = CGF.getContext();
Address src =
- CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), CGF.LoadObjCSelf(), ivar, 0)
- .getAddress();
+ CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), CGF.LoadObjCSelf(), ivar, 0)
+ .getAddress(CGF);
// objc_copyStruct (ReturnValue, &structIvar,
// sizeof (Type of Ivar), isAtomic, false);
@@ -954,14 +972,13 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
const ObjCPropertyImplDecl *PID) {
llvm::Constant *AtomicHelperFn =
CodeGenFunction(CGM).GenerateObjCAtomicGetterCopyHelperFunction(PID);
- const ObjCPropertyDecl *PD = PID->getPropertyDecl();
- ObjCMethodDecl *OMD = PD->getGetterMethodDecl();
+ ObjCMethodDecl *OMD = PID->getGetterMethodDecl();
assert(OMD && "Invalid call to generate getter (empty method)");
StartObjCMethod(OMD, IMP->getClassInterface());
generateObjCGetterBody(IMP, PID, OMD, AtomicHelperFn);
- FinishFunction();
+ FinishFunction(OMD->getEndLoc());
}
static bool hasTrivialGetExpr(const ObjCPropertyImplDecl *propImpl) {
@@ -1002,8 +1019,8 @@ static void emitCPPObjectAtomicGetterCall(CodeGenFunction &CGF,
// The 2nd argument is the address of the ivar.
llvm::Value *ivarAddr =
- CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(),
- CGF.LoadObjCSelf(), ivar, 0).getPointer();
+ CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), CGF.LoadObjCSelf(), ivar, 0)
+ .getPointer(CGF);
ivarAddr = CGF.Builder.CreateBitCast(ivarAddr, CGF.Int8PtrTy);
args.add(RValue::get(ivarAddr), CGF.getContext().VoidPtrTy);
@@ -1041,7 +1058,7 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
const ObjCPropertyDecl *prop = propImpl->getPropertyDecl();
QualType propType = prop->getType();
- ObjCMethodDecl *getterMethod = prop->getGetterMethodDecl();
+ ObjCMethodDecl *getterMethod = propImpl->getGetterMethodDecl();
ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
@@ -1062,7 +1079,7 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
bitcastType = bitcastType->getPointerTo(); // addrspace 0 okay
// Perform an atomic load. This does not impose ordering constraints.
- Address ivarAddr = LV.getAddress();
+ Address ivarAddr = LV.getAddress(*this);
ivarAddr = Builder.CreateBitCast(ivarAddr, bitcastType);
llvm::LoadInst *load = Builder.CreateLoad(ivarAddr, "load");
load->setAtomic(llvm::AtomicOrdering::Unordered);
@@ -1163,14 +1180,14 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
case TEK_Scalar: {
llvm::Value *value;
if (propType->isReferenceType()) {
- value = LV.getAddress().getPointer();
+ value = LV.getAddress(*this).getPointer();
} else {
// We want to load and autoreleaseReturnValue ARC __weak ivars.
if (LV.getQuals().getObjCLifetime() == Qualifiers::OCL_Weak) {
if (getLangOpts().ObjCAutoRefCount) {
value = emitARCRetainLoadOfScalar(*this, LV, ivarType);
} else {
- value = EmitARCLoadWeak(LV.getAddress());
+ value = EmitARCLoadWeak(LV.getAddress(*this));
}
// Otherwise we want to do a simple load, suppressing the
@@ -1204,9 +1221,9 @@ static void emitStructSetterCall(CodeGenFunction &CGF, ObjCMethodDecl *OMD,
CallArgList args;
// The first argument is the address of the ivar.
- llvm::Value *ivarAddr = CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(),
- CGF.LoadObjCSelf(), ivar, 0)
- .getPointer();
+ llvm::Value *ivarAddr =
+ CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), CGF.LoadObjCSelf(), ivar, 0)
+ .getPointer(CGF);
ivarAddr = CGF.Builder.CreateBitCast(ivarAddr, CGF.Int8PtrTy);
args.add(RValue::get(ivarAddr), CGF.getContext().VoidPtrTy);
@@ -1215,7 +1232,7 @@ static void emitStructSetterCall(CodeGenFunction &CGF, ObjCMethodDecl *OMD,
DeclRefExpr argRef(CGF.getContext(), argVar, false,
argVar->getType().getNonReferenceType(), VK_LValue,
SourceLocation());
- llvm::Value *argAddr = CGF.EmitLValue(&argRef).getPointer();
+ llvm::Value *argAddr = CGF.EmitLValue(&argRef).getPointer(CGF);
argAddr = CGF.Builder.CreateBitCast(argAddr, CGF.Int8PtrTy);
args.add(RValue::get(argAddr), CGF.getContext().VoidPtrTy);
@@ -1251,8 +1268,8 @@ static void emitCPPObjectAtomicSetterCall(CodeGenFunction &CGF,
// The first argument is the address of the ivar.
llvm::Value *ivarAddr =
- CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(),
- CGF.LoadObjCSelf(), ivar, 0).getPointer();
+ CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), CGF.LoadObjCSelf(), ivar, 0)
+ .getPointer(CGF);
ivarAddr = CGF.Builder.CreateBitCast(ivarAddr, CGF.Int8PtrTy);
args.add(RValue::get(ivarAddr), CGF.getContext().VoidPtrTy);
@@ -1261,7 +1278,7 @@ static void emitCPPObjectAtomicSetterCall(CodeGenFunction &CGF,
DeclRefExpr argRef(CGF.getContext(), argVar, false,
argVar->getType().getNonReferenceType(), VK_LValue,
SourceLocation());
- llvm::Value *argAddr = CGF.EmitLValue(&argRef).getPointer();
+ llvm::Value *argAddr = CGF.EmitLValue(&argRef).getPointer(CGF);
argAddr = CGF.Builder.CreateBitCast(argAddr, CGF.Int8PtrTy);
args.add(RValue::get(argAddr), CGF.getContext().VoidPtrTy);
@@ -1311,9 +1328,8 @@ void
CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
const ObjCPropertyImplDecl *propImpl,
llvm::Constant *AtomicHelperFn) {
- const ObjCPropertyDecl *prop = propImpl->getPropertyDecl();
ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
- ObjCMethodDecl *setterMethod = prop->getSetterMethodDecl();
+ ObjCMethodDecl *setterMethod = propImpl->getSetterMethodDecl();
// Just use the setter expression if Sema gave us one and it's
// non-trivial.
@@ -1339,7 +1355,7 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
LValue ivarLValue =
EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, /*quals*/ 0);
- Address ivarAddr = ivarLValue.getAddress();
+ Address ivarAddr = ivarLValue.getAddress(*this);
// Currently, all atomic accesses have to be through integer
// types, so there's no point in trying to pick a prettier type.
@@ -1490,14 +1506,13 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
const ObjCPropertyImplDecl *PID) {
llvm::Constant *AtomicHelperFn =
CodeGenFunction(CGM).GenerateObjCAtomicSetterCopyHelperFunction(PID);
- const ObjCPropertyDecl *PD = PID->getPropertyDecl();
- ObjCMethodDecl *OMD = PD->getSetterMethodDecl();
+ ObjCMethodDecl *OMD = PID->getSetterMethodDecl();
assert(OMD && "Invalid call to generate setter (empty method)");
StartObjCMethod(OMD, IMP->getClassInterface());
generateObjCSetterBody(IMP, PID, AtomicHelperFn);
- FinishFunction();
+ FinishFunction(OMD->getEndLoc());
}
namespace {
@@ -1517,7 +1532,7 @@ namespace {
void Emit(CodeGenFunction &CGF, Flags flags) override {
LValue lvalue
= CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), addr, ivar, /*CVR*/ 0);
- CGF.emitDestroy(lvalue.getAddress(), ivar->getType(), destroyer,
+ CGF.emitDestroy(lvalue.getAddress(CGF), ivar->getType(), destroyer,
flags.isForNormalCleanup() && useEHCleanupForArray);
}
};
@@ -1584,7 +1599,7 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
LValue LV = EmitLValueForIvar(TypeOfSelfObject(),
LoadObjCSelf(), Ivar, 0);
EmitAggExpr(IvarInit->getInit(),
- AggValueSlot::forLValue(LV, AggValueSlot::IsDestructed,
+ AggValueSlot::forLValue(LV, *this, AggValueSlot::IsDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased,
AggValueSlot::DoesNotOverlap));
@@ -2309,7 +2324,7 @@ llvm::Value *CodeGenFunction::EmitARCStoreStrong(LValue dst,
!isBlock &&
(dst.getAlignment().isZero() ||
dst.getAlignment() >= CharUnits::fromQuantity(PointerAlignInBytes))) {
- return EmitARCStoreStrongCall(dst.getAddress(), newValue, ignored);
+ return EmitARCStoreStrongCall(dst.getAddress(*this), newValue, ignored);
}
// Otherwise, split it out.
@@ -2708,7 +2723,7 @@ static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF,
result = CGF.EmitLoadOfLValue(lvalue, SourceLocation()).getScalarVal();
} else {
assert(type.getObjCLifetime() == Qualifiers::OCL_Weak);
- result = CGF.EmitARCLoadWeakRetained(lvalue.getAddress());
+ result = CGF.EmitARCLoadWeakRetained(lvalue.getAddress(CGF));
}
return TryEmitResult(result, !shouldRetain);
}
@@ -2732,7 +2747,7 @@ static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF,
SourceLocation()).getScalarVal();
// Set the source pointer to NULL.
- CGF.EmitStoreOfScalar(getNullForVariable(lv.getAddress()), lv);
+ CGF.EmitStoreOfScalar(getNullForVariable(lv.getAddress(CGF)), lv);
return TryEmitResult(result, true);
}
diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp
index d2c089d0360e..a27b6d4ed637 100644
--- a/clang/lib/CodeGen/CGObjCGNU.cpp
+++ b/clang/lib/CodeGen/CGObjCGNU.cpp
@@ -13,19 +13,20 @@
//
//===----------------------------------------------------------------------===//
-#include "CGObjCRuntime.h"
+#include "CGCXXABI.h"
#include "CGCleanup.h"
+#include "CGObjCRuntime.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
-#include "CGCXXABI.h"
-#include "clang/CodeGen/ConstantInitBuilder.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/CodeGen/ConstantInitBuilder.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/IR/DataLayout.h"
@@ -606,6 +607,9 @@ public:
llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD) override;
+ void GenerateDirectMethodPrologue(CodeGenFunction &CGF, llvm::Function *Fn,
+ const ObjCMethodDecl *OMD,
+ const ObjCContainerDecl *CD) override;
void GenerateCategory(const ObjCCategoryImplDecl *CMD) override;
void GenerateClass(const ObjCImplementationDecl *ClassDecl) override;
void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) override;
@@ -1232,6 +1236,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
// The first Interface we find may be a @class,
// which should only be treated as the source of
// truth in the absence of a true declaration.
+ assert(OID && "Failed to find ObjCInterfaceDecl");
const ObjCInterfaceDecl *OIDDef = OID->getDefinition();
if (OIDDef != nullptr)
OID = OIDDef;
@@ -1880,13 +1885,12 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
for (auto *propImpl : OID->property_impls())
if (propImpl->getPropertyImplementation() ==
ObjCPropertyImplDecl::Synthesize) {
- ObjCPropertyDecl *prop = propImpl->getPropertyDecl();
- auto addIfExists = [&](const ObjCMethodDecl* OMD) {
- if (OMD)
+ auto addIfExists = [&](const ObjCMethodDecl *OMD) {
+ if (OMD && OMD->hasBody())
InstanceMethods.push_back(OMD);
};
- addIfExists(prop->getGetterMethodDecl());
- addIfExists(prop->getSetterMethodDecl());
+ addIfExists(propImpl->getGetterMethodDecl());
+ addIfExists(propImpl->getSetterMethodDecl());
}
if (InstanceMethods.size() == 0)
@@ -3033,6 +3037,7 @@ llvm::Value *CGObjCGNU::GenerateProtocolRef(CodeGenFunction &CGF,
llvm::Constant *&protocol = ExistingProtocols[PD->getNameAsString()];
if (!protocol)
GenerateProtocol(PD);
+ assert(protocol && "Unknown protocol");
llvm::Type *T =
CGM.getTypes().ConvertType(CGM.getContext().getObjCProtoType());
return CGF.Builder.CreateBitCast(protocol, llvm::PointerType::getUnqual(T));
@@ -3494,13 +3499,12 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
for (auto *propertyImpl : OID->property_impls())
if (propertyImpl->getPropertyImplementation() ==
ObjCPropertyImplDecl::Synthesize) {
- ObjCPropertyDecl *property = propertyImpl->getPropertyDecl();
auto addPropertyMethod = [&](const ObjCMethodDecl *accessor) {
if (accessor)
InstanceMethods.push_back(accessor);
};
- addPropertyMethod(property->getGetterMethodDecl());
- addPropertyMethod(property->getSetterMethodDecl());
+ addPropertyMethod(propertyImpl->getGetterMethodDecl());
+ addPropertyMethod(propertyImpl->getSetterMethodDecl());
}
llvm::Constant *Properties = GeneratePropertyList(OID, ClassDecl);
@@ -3873,6 +3877,13 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD,
return Method;
}
+void CGObjCGNU::GenerateDirectMethodPrologue(CodeGenFunction &CGF,
+ llvm::Function *Fn,
+ const ObjCMethodDecl *OMD,
+ const ObjCContainerDecl *CD) {
+ // GNU runtime doesn't support direct calls at this time
+}
+
llvm::FunctionCallee CGObjCGNU::GetPropertyGetFunction() {
return GetPropertyFn;
}
diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp
index 8e28b2f05c16..f36c28a85a68 100644
--- a/clang/lib/CodeGen/CGObjCMac.cpp
+++ b/clang/lib/CodeGen/CGObjCMac.cpp
@@ -16,8 +16,8 @@
#include "CGRecordLayout.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
-#include "clang/CodeGen/ConstantInitBuilder.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/RecordLayout.h"
@@ -25,6 +25,7 @@
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/LangOptions.h"
#include "clang/CodeGen/CGFunctionInfo.h"
+#include "clang/CodeGen/ConstantInitBuilder.h"
#include "llvm/ADT/CachedHashString.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SetVector.h"
@@ -874,6 +875,10 @@ protected:
/// this translation unit.
llvm::DenseMap<const ObjCMethodDecl*, llvm::Function*> MethodDefinitions;
+ /// DirectMethodDefinitions - map of direct methods which have been defined in
+ /// this translation unit.
+ llvm::DenseMap<const ObjCMethodDecl*, llvm::Function*> DirectMethodDefinitions;
+
/// PropertyNames - uniqued method variable names.
llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> PropertyNames;
@@ -923,7 +928,8 @@ protected:
/// \param[out] NameOut - The return value.
void GetNameForMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD,
- SmallVectorImpl<char> &NameOut);
+ SmallVectorImpl<char> &NameOut,
+ bool ignoreCategoryNamespace = false);
/// GetMethodVarName - Return a unique constant for the given
/// selector's name. The return value has type char *.
@@ -1065,7 +1071,7 @@ protected:
CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
- llvm::Value *Sel,
+ Selector Sel,
llvm::Value *Arg0,
QualType Arg0Ty,
bool IsSuper,
@@ -1092,6 +1098,13 @@ public:
llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD=nullptr) override;
+ llvm::Function *GenerateDirectMethod(const ObjCMethodDecl *OMD,
+ const ObjCContainerDecl *CD);
+
+ void GenerateDirectMethodPrologue(CodeGenFunction &CGF, llvm::Function *Fn,
+ const ObjCMethodDecl *OMD,
+ const ObjCContainerDecl *CD) override;
+
void GenerateProtocol(const ObjCProtocolDecl *PD) override;
/// GetOrEmitProtocol - Get the protocol object for the given
@@ -1303,7 +1316,7 @@ private:
/// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy,
/// for the given selector.
llvm::Value *EmitSelector(CodeGenFunction &CGF, Selector Sel);
- Address EmitSelectorAddr(CodeGenFunction &CGF, Selector Sel);
+ Address EmitSelectorAddr(Selector Sel);
public:
CGObjCMac(CodeGen::CodeGenModule &cgm);
@@ -1531,7 +1544,7 @@ private:
/// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy,
/// for the given selector.
llvm::Value *EmitSelector(CodeGenFunction &CGF, Selector Sel);
- Address EmitSelectorAddr(CodeGenFunction &CGF, Selector Sel);
+ Address EmitSelectorAddr(Selector Sel);
/// GetInterfaceEHType - Get the cached ehtype for the given Objective-C
/// interface. The return value has type EHTypePtrTy.
@@ -1573,9 +1586,13 @@ private:
// base of the ivar access is a parameter to an Objective C method.
// However, because the parameters are not available in the current
// interface, we cannot perform this check.
+ //
+ // Note that for direct methods, because objc_msgSend is skipped,
+ // and that the method may be inlined, this optimization actually
+ // can't be performed.
if (const ObjCMethodDecl *MD =
dyn_cast_or_null<ObjCMethodDecl>(CGF.CurFuncDecl))
- if (MD->isInstanceMethod())
+ if (MD->isInstanceMethod() && !MD->isDirectMethod())
if (const ObjCInterfaceDecl *ID = MD->getClassInterface())
return IV->getContainingInterface()->isSuperClassOf(ID);
return false;
@@ -1619,7 +1636,7 @@ public:
llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel) override
{ return EmitSelector(CGF, Sel); }
Address GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) override
- { return EmitSelectorAddr(CGF, Sel); }
+ { return EmitSelectorAddr(Sel); }
/// The NeXT/Apple runtimes do not support typed selectors; just emit an
/// untyped one.
@@ -1887,7 +1904,7 @@ llvm::Value *CGObjCMac::GetSelector(CodeGenFunction &CGF, Selector Sel) {
return EmitSelector(CGF, Sel);
}
Address CGObjCMac::GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) {
- return EmitSelectorAddr(CGF, Sel);
+ return EmitSelectorAddr(Sel);
}
llvm::Value *CGObjCMac::GetSelector(CodeGenFunction &CGF, const ObjCMethodDecl
*Method) {
@@ -2103,10 +2120,9 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType());
Target = CGF.Builder.CreateBitCast(Target, ClassTy);
CGF.Builder.CreateStore(Target, CGF.Builder.CreateStructGEP(ObjCSuper, 1));
- return EmitMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF, Sel),
- ObjCSuper.getPointer(), ObjCTypes.SuperPtrCTy,
- true, CallArgs, Method, Class, ObjCTypes);
+ return EmitMessageSend(CGF, Return, ResultType, Sel, ObjCSuper.getPointer(),
+ ObjCTypes.SuperPtrCTy, true, CallArgs, Method, Class,
+ ObjCTypes);
}
/// Generate code for a message send expression.
@@ -2118,10 +2134,9 @@ CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
const CallArgList &CallArgs,
const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method) {
- return EmitMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF, Sel),
- Receiver, CGF.getContext().getObjCIdType(),
- false, CallArgs, Method, Class, ObjCTypes);
+ return EmitMessageSend(CGF, Return, ResultType, Sel, Receiver,
+ CGF.getContext().getObjCIdType(), false, CallArgs,
+ Method, Class, ObjCTypes);
}
static bool isWeakLinkedClass(const ObjCInterfaceDecl *ID) {
@@ -2137,7 +2152,7 @@ CodeGen::RValue
CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
- llvm::Value *Sel,
+ Selector Sel,
llvm::Value *Arg0,
QualType Arg0Ty,
bool IsSuper,
@@ -2145,11 +2160,24 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
const ObjCMethodDecl *Method,
const ObjCInterfaceDecl *ClassReceiver,
const ObjCCommonTypesHelper &ObjCTypes) {
+ CodeGenTypes &Types = CGM.getTypes();
+ auto selTy = CGF.getContext().getObjCSelType();
+ llvm::Value *SelValue;
+
+ if (Method && Method->isDirectMethod()) {
+ // Direct methods will synthesize the proper `_cmd` internally,
+ // so just don't bother with setting the `_cmd` argument.
+ assert(!IsSuper);
+ SelValue = llvm::UndefValue::get(Types.ConvertType(selTy));
+ } else {
+ SelValue = GetSelector(CGF, Sel);
+ }
+
CallArgList ActualArgs;
if (!IsSuper)
Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy);
ActualArgs.add(RValue::get(Arg0), Arg0Ty);
- ActualArgs.add(RValue::get(Sel), CGF.getContext().getObjCSelType());
+ ActualArgs.add(RValue::get(SelValue), selTy);
ActualArgs.addFrom(CallArgs);
// If we're calling a method, use the formal signature.
@@ -2190,7 +2218,9 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
bool RequiresNullCheck = false;
llvm::FunctionCallee Fn = nullptr;
- if (CGM.ReturnSlotInterferesWithArgs(MSI.CallInfo)) {
+ if (Method && Method->isDirectMethod()) {
+ Fn = GenerateDirectMethod(Method, Method->getClassInterface());
+ } else if (CGM.ReturnSlotInterferesWithArgs(MSI.CallInfo)) {
if (ReceiverCanBeNull) RequiresNullCheck = true;
Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper)
: ObjCTypes.getSendStretFn(IsSuper);
@@ -3215,9 +3245,6 @@ PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo*,16> &PropertySet,
SmallVectorImpl<const ObjCPropertyDecl *> &Properties,
const ObjCProtocolDecl *Proto,
bool IsClassProperty) {
- for (const auto *P : Proto->protocols())
- PushProtocolProperties(PropertySet, Properties, P, IsClassProperty);
-
for (const auto *PD : Proto->properties()) {
if (IsClassProperty != PD->isClassProperty())
continue;
@@ -3225,6 +3252,9 @@ PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo*,16> &PropertySet,
continue;
Properties.push_back(PD);
}
+
+ for (const auto *P : Proto->protocols())
+ PushProtocolProperties(PropertySet, Properties, P, IsClassProperty);
}
/*
@@ -3297,6 +3327,8 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name,
values.addInt(ObjCTypes.IntTy, Properties.size());
auto propertiesArray = values.beginArray(ObjCTypes.PropertyTy);
for (auto PD : Properties) {
+ if (PD->isDirectProperty())
+ continue;
auto property = propertiesArray.beginStruct(ObjCTypes.PropertyTy);
property.add(GetPropertyName(PD->getIdentifier()));
property.add(GetPropertyTypeString(PD, Container));
@@ -3372,7 +3404,8 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
};
SmallVector<const ObjCMethodDecl *, 16> Methods[NumMethodLists];
for (const auto *MD : OCD->methods()) {
- Methods[unsigned(MD->isClassMethod())].push_back(MD);
+ if (!MD->isDirectMethod())
+ Methods[unsigned(MD->isClassMethod())].push_back(MD);
}
Values.add(GetClassName(OCD->getName()));
@@ -3554,17 +3587,18 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
};
SmallVector<const ObjCMethodDecl *, 16> Methods[NumMethodLists];
for (const auto *MD : ID->methods()) {
- Methods[unsigned(MD->isClassMethod())].push_back(MD);
+ if (!MD->isDirectMethod())
+ Methods[unsigned(MD->isClassMethod())].push_back(MD);
}
for (const auto *PID : ID->property_impls()) {
if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) {
- ObjCPropertyDecl *PD = PID->getPropertyDecl();
-
- if (ObjCMethodDecl *MD = PD->getGetterMethodDecl())
+ if (PID->getPropertyDecl()->isDirectProperty())
+ continue;
+ if (ObjCMethodDecl *MD = PID->getGetterMethodDecl())
if (GetMethodDefinition(MD))
Methods[InstanceMethods].push_back(MD);
- if (ObjCMethodDecl *MD = PD->getSetterMethodDecl())
+ if (ObjCMethodDecl *MD = PID->getSetterMethodDecl())
if (GetMethodDefinition(MD))
Methods[InstanceMethods].push_back(MD);
}
@@ -3959,7 +3993,8 @@ llvm::Constant *CGObjCMac::emitMethodList(Twine name, MethodListType MLT,
values.addInt(ObjCTypes.IntTy, methods.size());
auto methodArray = values.beginArray(ObjCTypes.MethodTy);
for (auto MD : methods) {
- emitMethodConstant(methodArray, MD);
+ if (!MD->isDirectMethod())
+ emitMethodConstant(methodArray, MD);
}
methodArray.finishAndAddTo(values);
@@ -3970,22 +4005,133 @@ llvm::Constant *CGObjCMac::emitMethodList(Twine name, MethodListType MLT,
llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD) {
+ llvm::Function *Method;
+
+ if (OMD->isDirectMethod()) {
+ Method = GenerateDirectMethod(OMD, CD);
+ } else {
+ SmallString<256> Name;
+ GetNameForMethod(OMD, CD, Name);
+
+ CodeGenTypes &Types = CGM.getTypes();
+ llvm::FunctionType *MethodTy =
+ Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD));
+ Method =
+ llvm::Function::Create(MethodTy, llvm::GlobalValue::InternalLinkage,
+ Name.str(), &CGM.getModule());
+ }
+
+ MethodDefinitions.insert(std::make_pair(OMD, Method));
+
+ return Method;
+}
+
+llvm::Function *
+CGObjCCommonMac::GenerateDirectMethod(const ObjCMethodDecl *OMD,
+ const ObjCContainerDecl *CD) {
+ auto I = DirectMethodDefinitions.find(OMD->getCanonicalDecl());
+ if (I != DirectMethodDefinitions.end())
+ return I->second;
+
SmallString<256> Name;
- GetNameForMethod(OMD, CD, Name);
+ GetNameForMethod(OMD, CD, Name, /*ignoreCategoryNamespace*/true);
CodeGenTypes &Types = CGM.getTypes();
llvm::FunctionType *MethodTy =
Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD));
llvm::Function *Method =
- llvm::Function::Create(MethodTy,
- llvm::GlobalValue::InternalLinkage,
- Name.str(),
- &CGM.getModule());
- MethodDefinitions.insert(std::make_pair(OMD, Method));
+ llvm::Function::Create(MethodTy, llvm::GlobalValue::ExternalLinkage,
+ Name.str(), &CGM.getModule());
+ DirectMethodDefinitions.insert(std::make_pair(OMD->getCanonicalDecl(), Method));
return Method;
}
+void CGObjCCommonMac::GenerateDirectMethodPrologue(
+ CodeGenFunction &CGF, llvm::Function *Fn, const ObjCMethodDecl *OMD,
+ const ObjCContainerDecl *CD) {
+ auto &Builder = CGF.Builder;
+ bool ReceiverCanBeNull = true;
+ auto selfAddr = CGF.GetAddrOfLocalVar(OMD->getSelfDecl());
+ auto selfValue = Builder.CreateLoad(selfAddr);
+
+ // Generate:
+ //
+ // /* for class methods only to force class lazy initialization */
+ // self = [self self];
+ //
+ // /* unless the receiver is never NULL */
+ // if (self == nil) {
+ // return (ReturnType){ };
+ // }
+ //
+ // _cmd = @selector(...)
+ // ...
+
+ if (OMD->isClassMethod()) {
+ const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(CD);
+ assert(OID &&
+ "GenerateDirectMethod() should be called with the Class Interface");
+ Selector SelfSel = GetNullarySelector("self", CGM.getContext());
+ auto ResultType = CGF.getContext().getObjCIdType();
+ RValue result;
+ CallArgList Args;
+
+ // TODO: If this method is inlined, the caller might know that `self` is
+ // already initialized; for example, it might be an ordinary Objective-C
+ // method which always receives an initialized `self`, or it might have just
+ // forced initialization on its own.
+ //
+ // We should find a way to eliminate this unnecessary initialization in such
+ // cases in LLVM.
+ result = GeneratePossiblySpecializedMessageSend(
+ CGF, ReturnValueSlot(), ResultType, SelfSel, selfValue, Args, OID,
+ nullptr, true);
+ Builder.CreateStore(result.getScalarVal(), selfAddr);
+
+ // Nullable `Class` expressions cannot be messaged with a direct method
+ // so the only reason why the receive can be null would be because
+ // of weak linking.
+ ReceiverCanBeNull = isWeakLinkedClass(OID);
+ }
+
+ if (ReceiverCanBeNull) {
+ llvm::BasicBlock *SelfIsNilBlock =
+ CGF.createBasicBlock("objc_direct_method.self_is_nil");
+ llvm::BasicBlock *ContBlock =
+ CGF.createBasicBlock("objc_direct_method.cont");
+
+ // if (self == nil) {
+ auto selfTy = cast<llvm::PointerType>(selfValue->getType());
+ auto Zero = llvm::ConstantPointerNull::get(selfTy);
+
+ llvm::MDBuilder MDHelper(CGM.getLLVMContext());
+ Builder.CreateCondBr(Builder.CreateICmpEQ(selfValue, Zero), SelfIsNilBlock,
+ ContBlock, MDHelper.createBranchWeights(1, 1 << 20));
+
+ CGF.EmitBlock(SelfIsNilBlock);
+
+ // return (ReturnType){ };
+ auto retTy = OMD->getReturnType();
+ Builder.SetInsertPoint(SelfIsNilBlock);
+ if (!retTy->isVoidType()) {
+ CGF.EmitNullInitialization(CGF.ReturnValue, retTy);
+ }
+ CGF.EmitBranchThroughCleanup(CGF.ReturnBlock);
+ // }
+
+ // rest of the body
+ CGF.EmitBlock(ContBlock);
+ Builder.SetInsertPoint(ContBlock);
+ }
+
+ // only synthesize _cmd if it's referenced
+ if (OMD->getCmdDecl()->isUsed()) {
+ Builder.CreateStore(GetSelector(CGF, OMD),
+ CGF.GetAddrOfLocalVar(OMD->getCmdDecl()));
+ }
+}
+
llvm::GlobalVariable *CGObjCCommonMac::CreateMetadataVar(Twine Name,
ConstantStructBuilder &Init,
StringRef Section,
@@ -5118,11 +5264,11 @@ llvm::Value *CGObjCMac::EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) {
}
llvm::Value *CGObjCMac::EmitSelector(CodeGenFunction &CGF, Selector Sel) {
- return CGF.Builder.CreateLoad(EmitSelectorAddr(CGF, Sel));
+ return CGF.Builder.CreateLoad(EmitSelectorAddr(Sel));
}
-Address CGObjCMac::EmitSelectorAddr(CodeGenFunction &CGF, Selector Sel) {
- CharUnits Align = CGF.getPointerAlign();
+Address CGObjCMac::EmitSelectorAddr(Selector Sel) {
+ CharUnits Align = CGM.getPointerAlign();
llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
if (!Entry) {
@@ -5542,14 +5688,16 @@ CGObjCCommonMac::GetPropertyTypeString(const ObjCPropertyDecl *PD,
void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D,
const ObjCContainerDecl *CD,
- SmallVectorImpl<char> &Name) {
+ SmallVectorImpl<char> &Name,
+ bool ignoreCategoryNamespace) {
llvm::raw_svector_ostream OS(Name);
assert (CD && "Missing container decl in GetNameForMethod");
OS << '\01' << (D->isInstanceMethod() ? '-' : '+')
<< '[' << CD->getName();
- if (const ObjCCategoryImplDecl *CID =
- dyn_cast<ObjCCategoryImplDecl>(D->getDeclContext()))
- OS << '(' << *CID << ')';
+ if (!ignoreCategoryNamespace)
+ if (const ObjCCategoryImplDecl *CID =
+ dyn_cast<ObjCCategoryImplDecl>(D->getDeclContext()))
+ OS << '(' << *CID << ')';
OS << ' ' << D->getSelector().getAsString() << ']';
}
@@ -6228,23 +6376,12 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
SmallVector<const ObjCMethodDecl*, 16> methods;
if (flags & NonFragileABI_Class_Meta) {
for (const auto *MD : ID->class_methods())
- methods.push_back(MD);
+ if (!MD->isDirectMethod())
+ methods.push_back(MD);
} else {
for (const auto *MD : ID->instance_methods())
- methods.push_back(MD);
-
- for (const auto *PID : ID->property_impls()) {
- if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize){
- ObjCPropertyDecl *PD = PID->getPropertyDecl();
-
- if (auto MD = PD->getGetterMethodDecl())
- if (GetMethodDefinition(MD))
- methods.push_back(MD);
- if (auto MD = PD->getSetterMethodDecl())
- if (GetMethodDefinition(MD))
- methods.push_back(MD);
- }
- }
+ if (!MD->isDirectMethod())
+ methods.push_back(MD);
}
values.add(emitMethodList(ID->getObjCRuntimeNameAsString(),
@@ -6565,6 +6702,8 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
SmallVector<const ObjCMethodDecl *, 16> instanceMethods;
SmallVector<const ObjCMethodDecl *, 8> classMethods;
for (const auto *MD : OCD->methods()) {
+ if (MD->isDirectMethod())
+ continue;
if (MD->isInstanceMethod()) {
instanceMethods.push_back(MD);
} else {
@@ -6707,9 +6846,8 @@ CGObjCNonFragileABIMac::emitMethodList(Twine name, MethodListType kind,
// method_count
values.addInt(ObjCTypes.IntTy, methods.size());
auto methodArray = values.beginArray(ObjCTypes.MethodTy);
- for (auto MD : methods) {
+ for (auto MD : methods)
emitMethodConstant(methodArray, MD, forProtocol);
- }
methodArray.finishAndAddTo(values);
llvm::GlobalVariable *GV = finishAndCreateGlobal(values, prefix + name, CGM);
@@ -7234,8 +7372,7 @@ CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
? EmitVTableMessageSend(CGF, Return, ResultType, Sel,
Receiver, CGF.getContext().getObjCIdType(),
false, CallArgs, Method)
- : EmitMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF, Sel),
+ : EmitMessageSend(CGF, Return, ResultType, Sel,
Receiver, CGF.getContext().getObjCIdType(),
false, CallArgs, Method, Class, ObjCTypes);
}
@@ -7466,15 +7603,14 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
? EmitVTableMessageSend(CGF, Return, ResultType, Sel,
ObjCSuper.getPointer(), ObjCTypes.SuperPtrCTy,
true, CallArgs, Method)
- : EmitMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF, Sel),
+ : EmitMessageSend(CGF, Return, ResultType, Sel,
ObjCSuper.getPointer(), ObjCTypes.SuperPtrCTy,
true, CallArgs, Method, Class, ObjCTypes);
}
llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CodeGenFunction &CGF,
Selector Sel) {
- Address Addr = EmitSelectorAddr(CGF, Sel);
+ Address Addr = EmitSelectorAddr(Sel);
llvm::LoadInst* LI = CGF.Builder.CreateLoad(Addr);
LI->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
@@ -7482,11 +7618,9 @@ llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CodeGenFunction &CGF,
return LI;
}
-Address CGObjCNonFragileABIMac::EmitSelectorAddr(CodeGenFunction &CGF,
- Selector Sel) {
+Address CGObjCNonFragileABIMac::EmitSelectorAddr(Selector Sel) {
llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
-
- CharUnits Align = CGF.getPointerAlign();
+ CharUnits Align = CGM.getPointerAlign();
if (!Entry) {
llvm::Constant *Casted =
llvm::ConstantExpr::getBitCast(GetMethodVarName(Sel),
diff --git a/clang/lib/CodeGen/CGObjCRuntime.h b/clang/lib/CodeGen/CGObjCRuntime.h
index 471816cb5988..f0b3525cfde2 100644
--- a/clang/lib/CodeGen/CGObjCRuntime.h
+++ b/clang/lib/CodeGen/CGObjCRuntime.h
@@ -169,6 +169,21 @@ public:
const ObjCInterfaceDecl *Class = nullptr,
const ObjCMethodDecl *Method = nullptr) = 0;
+ /// Generate an Objective-C message send operation.
+ ///
+ /// This variant allows for the call to be substituted with an optimized
+ /// variant.
+ CodeGen::RValue
+ GeneratePossiblySpecializedMessageSend(CodeGenFunction &CGF,
+ ReturnValueSlot Return,
+ QualType ResultType,
+ Selector Sel,
+ llvm::Value *Receiver,
+ const CallArgList& Args,
+ const ObjCInterfaceDecl *OID,
+ const ObjCMethodDecl *Method,
+ bool isClassMessage);
+
/// Generate an Objective-C message send operation to the super
/// class initiated in a method for Class and with the given Self
/// object.
@@ -205,6 +220,12 @@ public:
virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD) = 0;
+ /// Generates prologue for direct Objective-C Methods.
+ virtual void GenerateDirectMethodPrologue(CodeGenFunction &CGF,
+ llvm::Function *Fn,
+ const ObjCMethodDecl *OMD,
+ const ObjCContainerDecl *CD) = 0;
+
/// Return the runtime function for getting properties.
virtual llvm::FunctionCallee GetPropertyGetFunction() = 0;
diff --git a/clang/lib/CodeGen/CGOpenCLRuntime.cpp b/clang/lib/CodeGen/CGOpenCLRuntime.cpp
index 191a95c62992..dbe375294d17 100644
--- a/clang/lib/CodeGen/CGOpenCLRuntime.cpp
+++ b/clang/lib/CodeGen/CGOpenCLRuntime.cpp
@@ -96,7 +96,7 @@ llvm::PointerType *CGOpenCLRuntime::getSamplerType(const Type *T) {
}
llvm::Value *CGOpenCLRuntime::getPipeElemSize(const Expr *PipeArg) {
- const PipeType *PipeTy = PipeArg->getType()->getAs<PipeType>();
+ const PipeType *PipeTy = PipeArg->getType()->castAs<PipeType>();
// The type of the last (implicit) argument to be passed.
llvm::Type *Int32Ty = llvm::IntegerType::getInt32Ty(CGM.getLLVMContext());
unsigned TypeSize = CGM.getContext()
@@ -106,7 +106,7 @@ llvm::Value *CGOpenCLRuntime::getPipeElemSize(const Expr *PipeArg) {
}
llvm::Value *CGOpenCLRuntime::getPipeElemAlign(const Expr *PipeArg) {
- const PipeType *PipeTy = PipeArg->getType()->getAs<PipeType>();
+ const PipeType *PipeTy = PipeArg->getType()->castAs<PipeType>();
// The type of the last (implicit) argument to be passed.
llvm::Type *Int32Ty = llvm::IntegerType::getInt32Ty(CGM.getLLVMContext());
unsigned TypeSize = CGM.getContext()
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
index 2a13a2a58156..97b17799a03e 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -10,17 +10,22 @@
//
//===----------------------------------------------------------------------===//
+#include "CGOpenMPRuntime.h"
#include "CGCXXABI.h"
#include "CGCleanup.h"
-#include "CGOpenMPRuntime.h"
#include "CGRecordLayout.h"
#include "CodeGenFunction.h"
-#include "clang/CodeGen/ConstantInitBuilder.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/OpenMPClause.h"
#include "clang/AST/StmtOpenMP.h"
+#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/BitmaskEnum.h"
+#include "clang/CodeGen/ConstantInitBuilder.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SetOperations.h"
#include "llvm/Bitcode/BitcodeReader.h"
+#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/Value.h"
@@ -30,6 +35,7 @@
using namespace clang;
using namespace CodeGen;
+using namespace llvm::omp;
namespace {
/// Base class for handling code generation inside OpenMP regions.
@@ -356,7 +362,7 @@ public:
VD->getType().getNonReferenceType(), VK_LValue,
C.getLocation());
PrivScope.addPrivate(
- VD, [&CGF, &DRE]() { return CGF.EmitLValue(&DRE).getAddress(); });
+ VD, [&CGF, &DRE]() { return CGF.EmitLValue(&DRE).getAddress(CGF); });
}
(void)PrivScope.Privatize();
}
@@ -727,10 +733,6 @@ enum OpenMPRTLFunction {
OMPRTL__tgt_target_teams_nowait,
// Call to void __tgt_register_requires(int64_t flags);
OMPRTL__tgt_register_requires,
- // Call to void __tgt_register_lib(__tgt_bin_desc *desc);
- OMPRTL__tgt_register_lib,
- // Call to void __tgt_unregister_lib(__tgt_bin_desc *desc);
- OMPRTL__tgt_unregister_lib,
// Call to void __tgt_target_data_begin(int64_t device_id, int32_t arg_num,
// void** args_base, void **args, int64_t *arg_sizes, int64_t *arg_types);
OMPRTL__tgt_target_data_begin,
@@ -841,7 +843,7 @@ static void emitInitWithReductionInitializer(CodeGenFunction &CGF,
RValue::getComplex(CGF.EmitLoadOfComplex(LV, DRD->getLocation()));
break;
case TEK_Aggregate:
- InitRVal = RValue::getAggregate(LV.getAddress());
+ InitRVal = RValue::getAggregate(LV.getAddress(CGF));
break;
}
OpaqueValueExpr OVE(DRD->getLocation(), Ty, VK_RValue);
@@ -965,7 +967,7 @@ void ReductionCodeGen::emitAggregateInitialization(
EmitDeclareReductionInit,
EmitDeclareReductionInit ? ClausesData[N].ReductionOp
: PrivateVD->getInit(),
- DRD, SharedLVal.getAddress());
+ DRD, SharedLVal.getAddress(CGF));
}
ReductionCodeGen::ReductionCodeGen(ArrayRef<const Expr *> Shareds,
@@ -1006,13 +1008,13 @@ void ReductionCodeGen::emitAggregateType(CodeGenFunction &CGF, unsigned N) {
}
llvm::Value *Size;
llvm::Value *SizeInChars;
- auto *ElemType =
- cast<llvm::PointerType>(SharedAddresses[N].first.getPointer()->getType())
- ->getElementType();
+ auto *ElemType = cast<llvm::PointerType>(
+ SharedAddresses[N].first.getPointer(CGF)->getType())
+ ->getElementType();
auto *ElemSizeOf = llvm::ConstantExpr::getSizeOf(ElemType);
if (AsArraySection) {
- Size = CGF.Builder.CreatePtrDiff(SharedAddresses[N].second.getPointer(),
- SharedAddresses[N].first.getPointer());
+ Size = CGF.Builder.CreatePtrDiff(SharedAddresses[N].second.getPointer(CGF),
+ SharedAddresses[N].first.getPointer(CGF));
Size = CGF.Builder.CreateNUWAdd(
Size, llvm::ConstantInt::get(Size->getType(), /*V=*/1));
SizeInChars = CGF.Builder.CreateNUWMul(Size, ElemSizeOf);
@@ -1062,7 +1064,7 @@ void ReductionCodeGen::emitInitialization(
PrivateAddr, CGF.ConvertTypeForMem(PrivateType));
QualType SharedType = SharedAddresses[N].first.getType();
SharedLVal = CGF.MakeAddrLValue(
- CGF.Builder.CreateElementBitCast(SharedLVal.getAddress(),
+ CGF.Builder.CreateElementBitCast(SharedLVal.getAddress(CGF),
CGF.ConvertTypeForMem(SharedType)),
SharedType, SharedAddresses[N].first.getBaseInfo(),
CGF.CGM.getTBAAInfoForSubobject(SharedAddresses[N].first, SharedType));
@@ -1070,7 +1072,7 @@ void ReductionCodeGen::emitInitialization(
emitAggregateInitialization(CGF, N, PrivateAddr, SharedLVal, DRD);
} else if (DRD && (DRD->getInitializer() || !PrivateVD->hasInit())) {
emitInitWithReductionInitializer(CGF, DRD, ClausesData[N].ReductionOp,
- PrivateAddr, SharedLVal.getAddress(),
+ PrivateAddr, SharedLVal.getAddress(CGF),
SharedLVal.getType());
} else if (!DefaultInit(CGF) && PrivateVD->hasInit() &&
!CGF.isTrivialInitializer(PrivateVD->getInit())) {
@@ -1107,15 +1109,15 @@ static LValue loadToBegin(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy,
while ((BaseTy->isPointerType() || BaseTy->isReferenceType()) &&
!CGF.getContext().hasSameType(BaseTy, ElTy)) {
if (const auto *PtrTy = BaseTy->getAs<PointerType>()) {
- BaseLV = CGF.EmitLoadOfPointerLValue(BaseLV.getAddress(), PtrTy);
+ BaseLV = CGF.EmitLoadOfPointerLValue(BaseLV.getAddress(CGF), PtrTy);
} else {
- LValue RefLVal = CGF.MakeAddrLValue(BaseLV.getAddress(), BaseTy);
+ LValue RefLVal = CGF.MakeAddrLValue(BaseLV.getAddress(CGF), BaseTy);
BaseLV = CGF.EmitLoadOfReferenceLValue(RefLVal);
}
BaseTy = BaseTy->getPointeeType();
}
return CGF.MakeAddrLValue(
- CGF.Builder.CreateElementBitCast(BaseLV.getAddress(),
+ CGF.Builder.CreateElementBitCast(BaseLV.getAddress(CGF),
CGF.ConvertTypeForMem(ElTy)),
BaseLV.getType(), BaseLV.getBaseInfo(),
CGF.CGM.getTBAAInfoForSubobject(BaseLV, BaseLV.getType()));
@@ -1179,15 +1181,15 @@ Address ReductionCodeGen::adjustPrivateAddress(CodeGenFunction &CGF, unsigned N,
loadToBegin(CGF, OrigVD->getType(), SharedAddresses[N].first.getType(),
OriginalBaseLValue);
llvm::Value *Adjustment = CGF.Builder.CreatePtrDiff(
- BaseLValue.getPointer(), SharedAddresses[N].first.getPointer());
+ BaseLValue.getPointer(CGF), SharedAddresses[N].first.getPointer(CGF));
llvm::Value *PrivatePointer =
CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
PrivateAddr.getPointer(),
- SharedAddresses[N].first.getAddress().getType());
+ SharedAddresses[N].first.getAddress(CGF).getType());
llvm::Value *Ptr = CGF.Builder.CreateGEP(PrivatePointer, Adjustment);
return castToBase(CGF, OrigVD->getType(),
SharedAddresses[N].first.getType(),
- OriginalBaseLValue.getAddress().getType(),
+ OriginalBaseLValue.getAddress(CGF).getType(),
OriginalBaseLValue.getAlignment(), Ptr);
}
BaseDecls.emplace_back(
@@ -1276,7 +1278,7 @@ bool CGOpenMPRuntime::tryEmitDeclareVariant(const GlobalDecl &NewGD,
llvm::GlobalValue *Addr = CGM.GetGlobalValue(NewMangledName);
if (Addr && !Addr->isDeclaration()) {
const auto *D = cast<FunctionDecl>(OldGD.getDecl());
- const CGFunctionInfo &FI = CGM.getTypes().arrangeGlobalDeclaration(OldGD);
+ const CGFunctionInfo &FI = CGM.getTypes().arrangeGlobalDeclaration(NewGD);
llvm::Type *DeclTy = CGM.getTypes().GetFunctionType(FI);
// Create a reference to the named value. This ensures that it is emitted
@@ -1380,12 +1382,12 @@ emitCombinerOrInitializer(CodeGenModule &CGM, QualType Ty,
Address AddrIn = CGF.GetAddrOfLocalVar(&OmpInParm);
Scope.addPrivate(In, [&CGF, AddrIn, PtrTy]() {
return CGF.EmitLoadOfPointerLValue(AddrIn, PtrTy->castAs<PointerType>())
- .getAddress();
+ .getAddress(CGF);
});
Address AddrOut = CGF.GetAddrOfLocalVar(&OmpOutParm);
Scope.addPrivate(Out, [&CGF, AddrOut, PtrTy]() {
return CGF.EmitLoadOfPointerLValue(AddrOut, PtrTy->castAs<PointerType>())
- .getAddress();
+ .getAddress(CGF);
});
(void)Scope.Privatize();
if (!IsCombiner && Out->hasInit() &&
@@ -1436,6 +1438,52 @@ CGOpenMPRuntime::getUserDefinedReduction(const OMPDeclareReductionDecl *D) {
return UDRMap.lookup(D);
}
+namespace {
+// Temporary RAII solution to perform a push/pop stack event on the OpenMP IR
+// Builder if one is present.
+struct PushAndPopStackRAII {
+ PushAndPopStackRAII(llvm::OpenMPIRBuilder *OMPBuilder, CodeGenFunction &CGF,
+ bool HasCancel)
+ : OMPBuilder(OMPBuilder) {
+ if (!OMPBuilder)
+ return;
+
+ // The following callback is the crucial part of clangs cleanup process.
+ //
+ // NOTE:
+ // Once the OpenMPIRBuilder is used to create parallel regions (and
+ // similar), the cancellation destination (Dest below) is determined via
+ // IP. That means if we have variables to finalize we split the block at IP,
+ // use the new block (=BB) as destination to build a JumpDest (via
+ // getJumpDestInCurrentScope(BB)) which then is fed to
+ // EmitBranchThroughCleanup. Furthermore, there will not be the need
+ // to push & pop an FinalizationInfo object.
+ // The FiniCB will still be needed but at the point where the
+ // OpenMPIRBuilder is asked to construct a parallel (or similar) construct.
+ auto FiniCB = [&CGF](llvm::OpenMPIRBuilder::InsertPointTy IP) {
+ assert(IP.getBlock()->end() == IP.getPoint() &&
+ "Clang CG should cause non-terminated block!");
+ CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
+ CGF.Builder.restoreIP(IP);
+ CodeGenFunction::JumpDest Dest =
+ CGF.getOMPCancelDestination(OMPD_parallel);
+ CGF.EmitBranchThroughCleanup(Dest);
+ };
+
+ // TODO: Remove this once we emit parallel regions through the
+ // OpenMPIRBuilder as it can do this setup internally.
+ llvm::OpenMPIRBuilder::FinalizationInfo FI(
+ {FiniCB, OMPD_parallel, HasCancel});
+ OMPBuilder->pushFinalizationCB(std::move(FI));
+ }
+ ~PushAndPopStackRAII() {
+ if (OMPBuilder)
+ OMPBuilder->popFinalizationCB();
+ }
+ llvm::OpenMPIRBuilder *OMPBuilder;
+};
+} // namespace
+
static llvm::Function *emitParallelOrTeamsOutlinedFunction(
CodeGenModule &CGM, const OMPExecutableDirective &D, const CapturedStmt *CS,
const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind,
@@ -1460,6 +1508,11 @@ static llvm::Function *emitParallelOrTeamsOutlinedFunction(
else if (const auto *OPFD =
dyn_cast<OMPTargetTeamsDistributeParallelForDirective>(&D))
HasCancel = OPFD->hasCancel();
+
+ // TODO: Temporarily inform the OpenMPIRBuilder, if any, about the new
+ // parallel region to make cancellation barriers work properly.
+ llvm::OpenMPIRBuilder *OMPBuilder = CGM.getOpenMPIRBuilder();
+ PushAndPopStackRAII PSR(OMPBuilder, CGF, HasCancel);
CGOpenMPOutlinedRegionInfo CGInfo(*CS, ThreadIDVar, CodeGen, InnermostKind,
HasCancel, OutlinedHelperName);
CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
@@ -1495,7 +1548,7 @@ llvm::Function *CGOpenMPRuntime::emitTaskOutlinedFunction(
UpLoc, ThreadID,
CGF.EmitLoadOfPointerLValue(CGF.GetAddrOfLocalVar(TaskTVar),
TaskTVar->getType()->castAs<PointerType>())
- .getPointer()};
+ .getPointer(CGF)};
CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_omp_task), TaskArgs);
};
CGOpenMPTaskOutlinedRegionInfo::UntiedTaskActionTy Action(Tied, PartIDVar,
@@ -1706,9 +1759,10 @@ llvm::Value *CGOpenMPRuntime::getThreadID(CodeGenFunction &CGF,
if (!CGF.EHStack.requiresLandingPad() || !CGF.getLangOpts().Exceptions ||
!CGF.getLangOpts().CXXExceptions ||
CGF.Builder.GetInsertBlock() == TopBlock ||
- !isa<llvm::Instruction>(LVal.getPointer()) ||
- cast<llvm::Instruction>(LVal.getPointer())->getParent() == TopBlock ||
- cast<llvm::Instruction>(LVal.getPointer())->getParent() ==
+ !isa<llvm::Instruction>(LVal.getPointer(CGF)) ||
+ cast<llvm::Instruction>(LVal.getPointer(CGF))->getParent() ==
+ TopBlock ||
+ cast<llvm::Instruction>(LVal.getPointer(CGF))->getParent() ==
CGF.Builder.GetInsertBlock()) {
ThreadID = CGF.EmitLoadOfScalar(LVal, Loc);
// If value loaded in entry block, cache it and use it everywhere in
@@ -2422,26 +2476,6 @@ llvm::FunctionCallee CGOpenMPRuntime::createRuntimeFunction(unsigned Function) {
RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_register_requires");
break;
}
- case OMPRTL__tgt_register_lib: {
- // Build void __tgt_register_lib(__tgt_bin_desc *desc);
- QualType ParamTy =
- CGM.getContext().getPointerType(getTgtBinaryDescriptorQTy());
- llvm::Type *TypeParams[] = {CGM.getTypes().ConvertTypeForMem(ParamTy)};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_register_lib");
- break;
- }
- case OMPRTL__tgt_unregister_lib: {
- // Build void __tgt_unregister_lib(__tgt_bin_desc *desc);
- QualType ParamTy =
- CGM.getContext().getPointerType(getTgtBinaryDescriptorQTy());
- llvm::Type *TypeParams[] = {CGM.getTypes().ConvertTypeForMem(ParamTy)};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_unregister_lib");
- break;
- }
case OMPRTL__tgt_target_data_begin: {
// Build void __tgt_target_data_begin(int64_t device_id, int32_t arg_num,
// void** args_base, void **args, int64_t *arg_sizes, int64_t *arg_types);
@@ -2988,10 +3022,15 @@ Address CGOpenMPRuntime::getAddrOfArtificialThreadPrivate(CodeGenFunction &CGF,
QualType VarType,
StringRef Name) {
std::string Suffix = getName({"artificial", ""});
- std::string CacheSuffix = getName({"cache", ""});
llvm::Type *VarLVType = CGF.ConvertTypeForMem(VarType);
llvm::Value *GAddr =
getOrCreateInternalVariable(VarLVType, Twine(Name).concat(Suffix));
+ if (CGM.getLangOpts().OpenMP && CGM.getLangOpts().OpenMPUseTLS &&
+ CGM.getTarget().isTLSSupported()) {
+ cast<llvm::GlobalVariable>(GAddr)->setThreadLocal(/*Val=*/true);
+ return Address(GAddr, CGM.getContext().getTypeAlignInChars(VarType));
+ }
+ std::string CacheSuffix = getName({"cache", ""});
llvm::Value *Args[] = {
emitUpdateLocation(CGF, SourceLocation()),
getThreadID(CGF, SourceLocation()),
@@ -3005,12 +3044,12 @@ Address CGOpenMPRuntime::getAddrOfArtificialThreadPrivate(CodeGenFunction &CGF,
CGF.EmitRuntimeCall(
createRuntimeFunction(OMPRTL__kmpc_threadprivate_cached), Args),
VarLVType->getPointerTo(/*AddrSpace=*/0)),
- CGM.getPointerAlign());
+ CGM.getContext().getTypeAlignInChars(VarType));
}
-void CGOpenMPRuntime::emitOMPIfClause(CodeGenFunction &CGF, const Expr *Cond,
- const RegionCodeGenTy &ThenGen,
- const RegionCodeGenTy &ElseGen) {
+void CGOpenMPRuntime::emitIfClause(CodeGenFunction &CGF, const Expr *Cond,
+ const RegionCodeGenTy &ThenGen,
+ const RegionCodeGenTy &ElseGen) {
CodeGenFunction::LexicalScope ConditionScope(CGF, Cond->getSourceRange());
// If the condition constant folds and can be elided, try to avoid emitting
@@ -3100,7 +3139,7 @@ void CGOpenMPRuntime::emitParallelCall(CodeGenFunction &CGF, SourceLocation Loc,
EndArgs);
};
if (IfCond) {
- emitOMPIfClause(CGF, IfCond, ThenGen, ElseGen);
+ emitIfClause(CGF, IfCond, ThenGen, ElseGen);
} else {
RegionCodeGenTy ThenRCG(ThenGen);
ThenRCG(CGF);
@@ -3118,7 +3157,7 @@ Address CGOpenMPRuntime::emitThreadIDAddress(CodeGenFunction &CGF,
if (auto *OMPRegionInfo =
dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo))
if (OMPRegionInfo->getThreadIDVariable())
- return OMPRegionInfo->getThreadIDVariableLValue(CGF).getAddress();
+ return OMPRegionInfo->getThreadIDVariableLValue(CGF).getAddress(CGF);
llvm::Value *ThreadID = getThreadID(CGF, Loc);
QualType Int32Ty =
@@ -3394,7 +3433,8 @@ void CGOpenMPRuntime::emitSingleRegion(CodeGenFunction &CGF,
Address Elem = CGF.Builder.CreateConstArrayGEP(CopyprivateList, I);
CGF.Builder.CreateStore(
CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- CGF.EmitLValue(CopyprivateVars[I]).getPointer(), CGF.VoidPtrTy),
+ CGF.EmitLValue(CopyprivateVars[I]).getPointer(CGF),
+ CGF.VoidPtrTy),
Elem);
}
// Build function that copies private values from single region to all other
@@ -3476,6 +3516,16 @@ void CGOpenMPRuntime::getDefaultScheduleAndChunk(
void CGOpenMPRuntime::emitBarrierCall(CodeGenFunction &CGF, SourceLocation Loc,
OpenMPDirectiveKind Kind, bool EmitChecks,
bool ForceSimpleCall) {
+ // Check if we should use the OMPBuilder
+ auto *OMPRegionInfo =
+ dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo);
+ llvm::OpenMPIRBuilder *OMPBuilder = CGF.CGM.getOpenMPIRBuilder();
+ if (OMPBuilder) {
+ CGF.Builder.restoreIP(OMPBuilder->CreateBarrier(
+ CGF.Builder, Kind, ForceSimpleCall, EmitChecks));
+ return;
+ }
+
if (!CGF.HaveInsertPoint())
return;
// Build call __kmpc_cancel_barrier(loc, thread_id);
@@ -3485,8 +3535,7 @@ void CGOpenMPRuntime::emitBarrierCall(CodeGenFunction &CGF, SourceLocation Loc,
// thread_id);
llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc, Flags),
getThreadID(CGF, Loc)};
- if (auto *OMPRegionInfo =
- dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
+ if (OMPRegionInfo) {
if (!ForceSimpleCall && OMPRegionInfo->hasCancel()) {
llvm::Value *Result = CGF.EmitRuntimeCall(
createRuntimeFunction(OMPRTL__kmpc_cancel_barrier), Args);
@@ -3616,7 +3665,9 @@ static int addMonoNonMonoModifier(CodeGenModule &CGM, OpenMPSchedType Schedule,
if (CGM.getLangOpts().OpenMP >= 50 && Modifier == 0) {
if (!(Schedule == OMP_sch_static_chunked || Schedule == OMP_sch_static ||
Schedule == OMP_sch_static_balanced_chunked ||
- Schedule == OMP_ord_static_chunked || Schedule == OMP_ord_static))
+ Schedule == OMP_ord_static_chunked || Schedule == OMP_ord_static ||
+ Schedule == OMP_dist_sch_static_chunked ||
+ Schedule == OMP_dist_sch_static))
Modifier = OMP_sch_modifier_nonmonotonic;
}
return Schedule | Modifier;
@@ -3807,37 +3858,15 @@ void CGOpenMPRuntime::emitNumThreadsClause(CodeGenFunction &CGF,
}
void CGOpenMPRuntime::emitProcBindClause(CodeGenFunction &CGF,
- OpenMPProcBindClauseKind ProcBind,
+ ProcBindKind ProcBind,
SourceLocation Loc) {
if (!CGF.HaveInsertPoint())
return;
- // Constants for proc bind value accepted by the runtime.
- enum ProcBindTy {
- ProcBindFalse = 0,
- ProcBindTrue,
- ProcBindMaster,
- ProcBindClose,
- ProcBindSpread,
- ProcBindIntel,
- ProcBindDefault
- } RuntimeProcBind;
- switch (ProcBind) {
- case OMPC_PROC_BIND_master:
- RuntimeProcBind = ProcBindMaster;
- break;
- case OMPC_PROC_BIND_close:
- RuntimeProcBind = ProcBindClose;
- break;
- case OMPC_PROC_BIND_spread:
- RuntimeProcBind = ProcBindSpread;
- break;
- case OMPC_PROC_BIND_unknown:
- llvm_unreachable("Unsupported proc_bind value.");
- }
+ assert(ProcBind != OMP_PROC_BIND_unknown && "Unsupported proc_bind value.");
// Build call __kmpc_push_proc_bind(&loc, global_tid, proc_bind)
llvm::Value *Args[] = {
emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
- llvm::ConstantInt::get(CGM.IntTy, RuntimeProcBind, /*isSigned=*/true)};
+ llvm::ConstantInt::get(CGM.IntTy, unsigned(ProcBind), /*isSigned=*/true)};
CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_push_proc_bind), Args);
}
@@ -4327,57 +4356,6 @@ QualType CGOpenMPRuntime::getTgtOffloadEntryQTy() {
return TgtOffloadEntryQTy;
}
-QualType CGOpenMPRuntime::getTgtDeviceImageQTy() {
- // These are the types we need to build:
- // struct __tgt_device_image{
- // void *ImageStart; // Pointer to the target code start.
- // void *ImageEnd; // Pointer to the target code end.
- // // We also add the host entries to the device image, as it may be useful
- // // for the target runtime to have access to that information.
- // __tgt_offload_entry *EntriesBegin; // Begin of the table with all
- // // the entries.
- // __tgt_offload_entry *EntriesEnd; // End of the table with all the
- // // entries (non inclusive).
- // };
- if (TgtDeviceImageQTy.isNull()) {
- ASTContext &C = CGM.getContext();
- RecordDecl *RD = C.buildImplicitRecord("__tgt_device_image");
- RD->startDefinition();
- addFieldToRecordDecl(C, RD, C.VoidPtrTy);
- addFieldToRecordDecl(C, RD, C.VoidPtrTy);
- addFieldToRecordDecl(C, RD, C.getPointerType(getTgtOffloadEntryQTy()));
- addFieldToRecordDecl(C, RD, C.getPointerType(getTgtOffloadEntryQTy()));
- RD->completeDefinition();
- TgtDeviceImageQTy = C.getRecordType(RD);
- }
- return TgtDeviceImageQTy;
-}
-
-QualType CGOpenMPRuntime::getTgtBinaryDescriptorQTy() {
- // struct __tgt_bin_desc{
- // int32_t NumDevices; // Number of devices supported.
- // __tgt_device_image *DeviceImages; // Arrays of device images
- // // (one per device).
- // __tgt_offload_entry *EntriesBegin; // Begin of the table with all the
- // // entries.
- // __tgt_offload_entry *EntriesEnd; // End of the table with all the
- // // entries (non inclusive).
- // };
- if (TgtBinaryDescriptorQTy.isNull()) {
- ASTContext &C = CGM.getContext();
- RecordDecl *RD = C.buildImplicitRecord("__tgt_bin_desc");
- RD->startDefinition();
- addFieldToRecordDecl(
- C, RD, C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/true));
- addFieldToRecordDecl(C, RD, C.getPointerType(getTgtDeviceImageQTy()));
- addFieldToRecordDecl(C, RD, C.getPointerType(getTgtOffloadEntryQTy()));
- addFieldToRecordDecl(C, RD, C.getPointerType(getTgtOffloadEntryQTy()));
- RD->completeDefinition();
- TgtBinaryDescriptorQTy = C.getRecordType(RD);
- }
- return TgtBinaryDescriptorQTy;
-}
-
namespace {
struct PrivateHelpersTy {
PrivateHelpersTy(const VarDecl *Original, const VarDecl *PrivateCopy,
@@ -4537,7 +4515,7 @@ emitProxyTaskFunction(CodeGenModule &CGM, SourceLocation Loc,
const auto *KmpTaskTQTyRD = cast<RecordDecl>(KmpTaskTQTy->getAsTagDecl());
auto PartIdFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTPartId);
LValue PartIdLVal = CGF.EmitLValueForField(Base, *PartIdFI);
- llvm::Value *PartidParam = PartIdLVal.getPointer();
+ llvm::Value *PartidParam = PartIdLVal.getPointer(CGF);
auto SharedsFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTShareds);
LValue SharedsLVal = CGF.EmitLValueForField(Base, *SharedsFI);
@@ -4550,7 +4528,7 @@ emitProxyTaskFunction(CodeGenModule &CGM, SourceLocation Loc,
if (PrivatesFI != KmpTaskTWithPrivatesQTyRD->field_end()) {
LValue PrivatesLVal = CGF.EmitLValueForField(TDBase, *PrivatesFI);
PrivatesParam = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- PrivatesLVal.getPointer(), CGF.VoidPtrTy);
+ PrivatesLVal.getPointer(CGF), CGF.VoidPtrTy);
} else {
PrivatesParam = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
}
@@ -4559,7 +4537,7 @@ emitProxyTaskFunction(CodeGenModule &CGM, SourceLocation Loc,
TaskPrivatesMap,
CGF.Builder
.CreatePointerBitCastOrAddrSpaceCast(
- TDBase.getAddress(), CGF.VoidPtrTy)
+ TDBase.getAddress(CGF), CGF.VoidPtrTy)
.getPointer()};
SmallVector<llvm::Value *, 16> CallArgs(std::begin(CommonArgs),
std::end(CommonArgs));
@@ -4637,7 +4615,7 @@ static llvm::Value *emitDestructorsFunction(CodeGenModule &CGM,
if (QualType::DestructionKind DtorKind =
Field->getType().isDestructedType()) {
LValue FieldLValue = CGF.EmitLValueForField(Base, Field);
- CGF.pushDestroy(DtorKind, FieldLValue.getAddress(), Field->getType());
+ CGF.pushDestroy(DtorKind, FieldLValue.getAddress(CGF), Field->getType());
}
}
CGF.FinishFunction();
@@ -4735,8 +4713,8 @@ emitTaskPrivateMappingFunction(CodeGenModule &CGM, SourceLocation Loc,
LValue RefLVal =
CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(VD), VD->getType());
LValue RefLoadLVal = CGF.EmitLoadOfPointerLValue(
- RefLVal.getAddress(), RefLVal.getType()->castAs<PointerType>());
- CGF.EmitStoreOfScalar(FieldLVal.getPointer(), RefLoadLVal);
+ RefLVal.getAddress(CGF), RefLVal.getType()->castAs<PointerType>());
+ CGF.EmitStoreOfScalar(FieldLVal.getPointer(CGF), RefLoadLVal);
++Counter;
}
CGF.FinishFunction();
@@ -4801,7 +4779,8 @@ static void emitPrivatesInit(CodeGenFunction &CGF,
} else {
SharedRefLValue = CGF.EmitLValueForField(SrcBase, SharedField);
SharedRefLValue = CGF.MakeAddrLValue(
- Address(SharedRefLValue.getPointer(), C.getDeclAlign(OriginalVD)),
+ Address(SharedRefLValue.getPointer(CGF),
+ C.getDeclAlign(OriginalVD)),
SharedRefLValue.getType(), LValueBaseInfo(AlignmentSource::Decl),
SharedRefLValue.getTBAAInfo());
}
@@ -4814,7 +4793,8 @@ static void emitPrivatesInit(CodeGenFunction &CGF,
// Initialize firstprivate array using element-by-element
// initialization.
CGF.EmitOMPAggregateAssign(
- PrivateLValue.getAddress(), SharedRefLValue.getAddress(), Type,
+ PrivateLValue.getAddress(CGF), SharedRefLValue.getAddress(CGF),
+ Type,
[&CGF, Elem, Init, &CapturesInfo](Address DestElement,
Address SrcElement) {
// Clean up any temporaries needed by the initialization.
@@ -4832,8 +4812,8 @@ static void emitPrivatesInit(CodeGenFunction &CGF,
}
} else {
CodeGenFunction::OMPPrivateScope InitScope(CGF);
- InitScope.addPrivate(Elem, [SharedRefLValue]() -> Address {
- return SharedRefLValue.getAddress();
+ InitScope.addPrivate(Elem, [SharedRefLValue, &CGF]() -> Address {
+ return SharedRefLValue.getAddress(CGF);
});
(void)InitScope.Privatize();
CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CapturesInfo);
@@ -5233,10 +5213,10 @@ void CGOpenMPRuntime::emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc,
dyn_cast<OMPArraySectionExpr>(E->IgnoreParenImpCasts())) {
LValue UpAddrLVal =
CGF.EmitOMPArraySectionExpr(ASE, /*IsLowerBound=*/false);
- llvm::Value *UpAddr =
- CGF.Builder.CreateConstGEP1_32(UpAddrLVal.getPointer(), /*Idx0=*/1);
+ llvm::Value *UpAddr = CGF.Builder.CreateConstGEP1_32(
+ UpAddrLVal.getPointer(CGF), /*Idx0=*/1);
llvm::Value *LowIntPtr =
- CGF.Builder.CreatePtrToInt(Addr.getPointer(), CGM.SizeTy);
+ CGF.Builder.CreatePtrToInt(Addr.getPointer(CGF), CGM.SizeTy);
llvm::Value *UpIntPtr = CGF.Builder.CreatePtrToInt(UpAddr, CGM.SizeTy);
Size = CGF.Builder.CreateNUWSub(UpIntPtr, LowIntPtr);
} else {
@@ -5249,7 +5229,7 @@ void CGOpenMPRuntime::emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc,
LValue BaseAddrLVal = CGF.EmitLValueForField(
Base, *std::next(KmpDependInfoRD->field_begin(), BaseAddr));
CGF.EmitStoreOfScalar(
- CGF.Builder.CreatePtrToInt(Addr.getPointer(), CGF.IntPtrTy),
+ CGF.Builder.CreatePtrToInt(Addr.getPointer(CGF), CGF.IntPtrTy),
BaseAddrLVal);
// deps[i].len = sizeof(<Dependences[i].second>);
LValue LenLVal = CGF.EmitLValueForField(
@@ -5366,7 +5346,7 @@ void CGOpenMPRuntime::emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc,
};
if (IfCond) {
- emitOMPIfClause(CGF, IfCond, ThenCodeGen, ElseCodeGen);
+ emitIfClause(CGF, IfCond, ThenCodeGen, ElseCodeGen);
} else {
RegionCodeGenTy ThenRCG(ThenCodeGen);
ThenRCG(CGF);
@@ -5403,21 +5383,24 @@ void CGOpenMPRuntime::emitTaskLoopCall(CodeGenFunction &CGF, SourceLocation Loc,
*std::next(Result.KmpTaskTQTyRD->field_begin(), KmpTaskTLowerBound));
const auto *LBVar =
cast<VarDecl>(cast<DeclRefExpr>(D.getLowerBoundVariable())->getDecl());
- CGF.EmitAnyExprToMem(LBVar->getInit(), LBLVal.getAddress(), LBLVal.getQuals(),
+ CGF.EmitAnyExprToMem(LBVar->getInit(), LBLVal.getAddress(CGF),
+ LBLVal.getQuals(),
/*IsInitializer=*/true);
LValue UBLVal = CGF.EmitLValueForField(
Result.TDBase,
*std::next(Result.KmpTaskTQTyRD->field_begin(), KmpTaskTUpperBound));
const auto *UBVar =
cast<VarDecl>(cast<DeclRefExpr>(D.getUpperBoundVariable())->getDecl());
- CGF.EmitAnyExprToMem(UBVar->getInit(), UBLVal.getAddress(), UBLVal.getQuals(),
+ CGF.EmitAnyExprToMem(UBVar->getInit(), UBLVal.getAddress(CGF),
+ UBLVal.getQuals(),
/*IsInitializer=*/true);
LValue StLVal = CGF.EmitLValueForField(
Result.TDBase,
*std::next(Result.KmpTaskTQTyRD->field_begin(), KmpTaskTStride));
const auto *StVar =
cast<VarDecl>(cast<DeclRefExpr>(D.getStrideVariable())->getDecl());
- CGF.EmitAnyExprToMem(StVar->getInit(), StLVal.getAddress(), StLVal.getQuals(),
+ CGF.EmitAnyExprToMem(StVar->getInit(), StLVal.getAddress(CGF),
+ StLVal.getQuals(),
/*IsInitializer=*/true);
// Store reductions address.
LValue RedLVal = CGF.EmitLValueForField(
@@ -5426,7 +5409,7 @@ void CGOpenMPRuntime::emitTaskLoopCall(CodeGenFunction &CGF, SourceLocation Loc,
if (Data.Reductions) {
CGF.EmitStoreOfScalar(Data.Reductions, RedLVal);
} else {
- CGF.EmitNullInitialization(RedLVal.getAddress(),
+ CGF.EmitNullInitialization(RedLVal.getAddress(CGF),
CGF.getContext().VoidPtrTy);
}
enum { NoSchedule = 0, Grainsize = 1, NumTasks = 2 };
@@ -5435,11 +5418,11 @@ void CGOpenMPRuntime::emitTaskLoopCall(CodeGenFunction &CGF, SourceLocation Loc,
ThreadID,
Result.NewTask,
IfVal,
- LBLVal.getPointer(),
- UBLVal.getPointer(),
+ LBLVal.getPointer(CGF),
+ UBLVal.getPointer(CGF),
CGF.EmitLoadOfScalar(StLVal, Loc),
llvm::ConstantInt::getSigned(
- CGF.IntTy, 1), // Always 1 because taskgroup emitted by the compiler
+ CGF.IntTy, 1), // Always 1 because taskgroup emitted by the compiler
llvm::ConstantInt::getSigned(
CGF.IntTy, Data.Schedule.getPointer()
? Data.Schedule.getInt() ? NumTasks : Grainsize
@@ -5751,7 +5734,7 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
Address Elem = CGF.Builder.CreateConstArrayGEP(ReductionList, Idx);
CGF.Builder.CreateStore(
CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- CGF.EmitLValue(RHSExprs[I]).getPointer(), CGF.VoidPtrTy),
+ CGF.EmitLValue(RHSExprs[I]).getPointer(CGF), CGF.VoidPtrTy),
Elem);
if ((*IPriv)->getType()->isVariablyModifiedType()) {
// Store array size.
@@ -6179,7 +6162,7 @@ static llvm::Value *emitReduceFiniFunction(CodeGenModule &CGM,
// Emit the finalizer body:
// <destroy>(<type>* %0)
RCG.emitCleanups(CGF, N, PrivateAddr);
- CGF.FinishFunction();
+ CGF.FinishFunction(Loc);
return Fn;
}
@@ -6231,7 +6214,7 @@ llvm::Value *CGOpenMPRuntime::emitTaskReductionInit(
LValue SharedLVal = CGF.EmitLValueForField(ElemLVal, SharedFD);
RCG.emitSharedLValue(CGF, Cnt);
llvm::Value *CastedShared =
- CGF.EmitCastToVoidPtr(RCG.getSharedLValue(Cnt).getPointer());
+ CGF.EmitCastToVoidPtr(RCG.getSharedLValue(Cnt).getPointer(CGF));
CGF.EmitStoreOfScalar(CastedShared, SharedLVal);
RCG.emitAggregateType(CGF, Cnt);
llvm::Value *SizeValInChars;
@@ -6274,7 +6257,8 @@ llvm::Value *CGOpenMPRuntime::emitTaskReductionInit(
llvm::ConstantInt::get(CGM.Int32Ty, /*V=*/1, /*isSigned=*/true),
FlagsLVal);
} else
- CGF.EmitNullInitialization(FlagsLVal.getAddress(), FlagsLVal.getType());
+ CGF.EmitNullInitialization(FlagsLVal.getAddress(CGF),
+ FlagsLVal.getType());
}
// Build call void *__kmpc_task_reduction_init(int gtid, int num_data, void
// *data);
@@ -6310,7 +6294,7 @@ void CGOpenMPRuntime::emitTaskReductionFixups(CodeGenFunction &CGF,
generateUniqueName(CGM, "reduction", RCG.getRefExpr(N)));
CGF.Builder.CreateStore(
CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- RCG.getSharedLValue(N).getPointer(), CGM.VoidPtrTy),
+ RCG.getSharedLValue(N).getPointer(CGF), CGM.VoidPtrTy),
SharedAddr, /*IsVolatile=*/false);
}
}
@@ -6321,12 +6305,12 @@ Address CGOpenMPRuntime::getTaskReductionItem(CodeGenFunction &CGF,
LValue SharedLVal) {
// Build call void *__kmpc_task_reduction_get_th_data(int gtid, void *tg, void
// *d);
- llvm::Value *Args[] = {
- CGF.Builder.CreateIntCast(getThreadID(CGF, Loc), CGM.IntTy,
- /*isSigned=*/true),
- ReductionsPtr,
- CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(SharedLVal.getPointer(),
- CGM.VoidPtrTy)};
+ llvm::Value *Args[] = {CGF.Builder.CreateIntCast(getThreadID(CGF, Loc),
+ CGM.IntTy,
+ /*isSigned=*/true),
+ ReductionsPtr,
+ CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ SharedLVal.getPointer(CGF), CGM.VoidPtrTy)};
return Address(
CGF.EmitRuntimeCall(
createRuntimeFunction(OMPRTL__kmpc_task_reduction_get_th_data), Args),
@@ -6449,8 +6433,8 @@ void CGOpenMPRuntime::emitCancelCall(CodeGenFunction &CGF, SourceLocation Loc,
CGF.EmitBlock(ContBB, /*IsFinished=*/true);
};
if (IfCond) {
- emitOMPIfClause(CGF, IfCond, ThenGen,
- [](CodeGenFunction &, PrePostActionTy &) {});
+ emitIfClause(CGF, IfCond, ThenGen,
+ [](CodeGenFunction &, PrePostActionTy &) {});
} else {
RegionCodeGenTy ThenRCG(ThenGen);
ThenRCG(CGF);
@@ -6663,6 +6647,7 @@ emitNumTeamsForTargetDirective(CodeGenFunction &CGF,
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:
@@ -6708,6 +6693,7 @@ emitNumTeamsForTargetDirective(CodeGenFunction &CGF,
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:
break;
@@ -6972,6 +6958,7 @@ emitNumThreadsForTargetDirective(CodeGenFunction &CGF,
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:
@@ -7017,6 +7004,7 @@ emitNumThreadsForTargetDirective(CodeGenFunction &CGF,
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:
break;
@@ -7509,11 +7497,11 @@ private:
} else if ((AE && isa<CXXThisExpr>(AE->getBase()->IgnoreParenImpCasts())) ||
(OASE &&
isa<CXXThisExpr>(OASE->getBase()->IgnoreParenImpCasts()))) {
- BP = CGF.EmitOMPSharedLValue(AssocExpr).getAddress();
+ BP = CGF.EmitOMPSharedLValue(AssocExpr).getAddress(CGF);
} else {
// The base is the reference to the variable.
// BP = &Var.
- BP = CGF.EmitOMPSharedLValue(AssocExpr).getAddress();
+ BP = CGF.EmitOMPSharedLValue(AssocExpr).getAddress(CGF);
if (const auto *VD =
dyn_cast_or_null<VarDecl>(I->getAssociatedDeclaration())) {
if (llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
@@ -7607,8 +7595,8 @@ private:
isa<OMPArraySectionExpr>(Next->getAssociatedExpression())) &&
"Unexpected expression");
- Address LB =
- CGF.EmitOMPSharedLValue(I->getAssociatedExpression()).getAddress();
+ Address LB = CGF.EmitOMPSharedLValue(I->getAssociatedExpression())
+ .getAddress(CGF);
// If this component is a pointer inside the base struct then we don't
// need to create any entry for it - it will be combined with the object
@@ -7655,7 +7643,7 @@ private:
if (MC.getAssociatedDeclaration()) {
ComponentLB =
CGF.EmitOMPSharedLValue(MC.getAssociatedExpression())
- .getAddress();
+ .getAddress(CGF);
Size = CGF.Builder.CreatePtrDiff(
CGF.EmitCastToVoidPtr(ComponentLB.getPointer()),
CGF.EmitCastToVoidPtr(LB.getPointer()));
@@ -7938,17 +7926,17 @@ public:
"Expect a executable directive");
const auto *CurExecDir = CurDir.get<const OMPExecutableDirective *>();
for (const auto *C : CurExecDir->getClausesOfKind<OMPMapClause>())
- for (const auto &L : C->component_lists()) {
+ for (const auto L : C->component_lists()) {
InfoGen(L.first, L.second, C->getMapType(), C->getMapTypeModifiers(),
/*ReturnDevicePointer=*/false, C->isImplicit());
}
for (const auto *C : CurExecDir->getClausesOfKind<OMPToClause>())
- for (const auto &L : C->component_lists()) {
+ for (const auto L : C->component_lists()) {
InfoGen(L.first, L.second, OMPC_MAP_to, llvm::None,
/*ReturnDevicePointer=*/false, C->isImplicit());
}
for (const auto *C : CurExecDir->getClausesOfKind<OMPFromClause>())
- for (const auto &L : C->component_lists()) {
+ for (const auto L : C->component_lists()) {
InfoGen(L.first, L.second, OMPC_MAP_from, llvm::None,
/*ReturnDevicePointer=*/false, C->isImplicit());
}
@@ -7964,7 +7952,7 @@ public:
for (const auto *C :
CurExecDir->getClausesOfKind<OMPUseDevicePtrClause>()) {
- for (const auto &L : C->component_lists()) {
+ for (const auto L : C->component_lists()) {
assert(!L.second.empty() && "Not expecting empty list of components!");
const ValueDecl *VD = L.second.back().getAssociatedDeclaration();
VD = cast<ValueDecl>(VD->getCanonicalDecl());
@@ -8059,7 +8047,7 @@ public:
auto CI = DeferredInfo.find(M.first);
if (CI != DeferredInfo.end()) {
for (const DeferredDevicePtrEntryTy &L : CI->second) {
- llvm::Value *BasePtr = this->CGF.EmitLValue(L.IE).getPointer();
+ llvm::Value *BasePtr = this->CGF.EmitLValue(L.IE).getPointer(CGF);
llvm::Value *Ptr = this->CGF.EmitLoadOfScalar(
this->CGF.EmitLValue(L.IE), L.IE->getExprLoc());
CurBasePointers.emplace_back(BasePtr, L.VD);
@@ -8117,7 +8105,7 @@ public:
for (const auto *C : CurMapperDir->clauselists()) {
const auto *MC = cast<OMPMapClause>(C);
- for (const auto &L : MC->component_lists()) {
+ for (const auto L : MC->component_lists()) {
InfoGen(L.first, L.second, MC->getMapType(), MC->getMapTypeModifiers(),
/*ReturnDevicePointer=*/false, MC->isImplicit());
}
@@ -8181,9 +8169,10 @@ public:
LValue ThisLVal =
CGF.EmitLValueForFieldInitialization(VDLVal, ThisCapture);
LValue ThisLValVal = CGF.EmitLValueForField(VDLVal, ThisCapture);
- LambdaPointers.try_emplace(ThisLVal.getPointer(), VDLVal.getPointer());
- BasePointers.push_back(ThisLVal.getPointer());
- Pointers.push_back(ThisLValVal.getPointer());
+ LambdaPointers.try_emplace(ThisLVal.getPointer(CGF),
+ VDLVal.getPointer(CGF));
+ BasePointers.push_back(ThisLVal.getPointer(CGF));
+ Pointers.push_back(ThisLValVal.getPointer(CGF));
Sizes.push_back(
CGF.Builder.CreateIntCast(CGF.getTypeSize(CGF.getContext().VoidPtrTy),
CGF.Int64Ty, /*isSigned=*/true));
@@ -8201,17 +8190,19 @@ public:
LValue VarLVal = CGF.EmitLValueForFieldInitialization(VDLVal, It->second);
if (LC.getCaptureKind() == LCK_ByRef) {
LValue VarLValVal = CGF.EmitLValueForField(VDLVal, It->second);
- LambdaPointers.try_emplace(VarLVal.getPointer(), VDLVal.getPointer());
- BasePointers.push_back(VarLVal.getPointer());
- Pointers.push_back(VarLValVal.getPointer());
+ LambdaPointers.try_emplace(VarLVal.getPointer(CGF),
+ VDLVal.getPointer(CGF));
+ BasePointers.push_back(VarLVal.getPointer(CGF));
+ Pointers.push_back(VarLValVal.getPointer(CGF));
Sizes.push_back(CGF.Builder.CreateIntCast(
CGF.getTypeSize(
VD->getType().getCanonicalType().getNonReferenceType()),
CGF.Int64Ty, /*isSigned=*/true));
} else {
RValue VarRVal = CGF.EmitLoadOfLValue(VarLVal, RD->getLocation());
- LambdaPointers.try_emplace(VarLVal.getPointer(), VDLVal.getPointer());
- BasePointers.push_back(VarLVal.getPointer());
+ LambdaPointers.try_emplace(VarLVal.getPointer(CGF),
+ VDLVal.getPointer(CGF));
+ BasePointers.push_back(VarLVal.getPointer(CGF));
Pointers.push_back(VarRVal.getScalarVal());
Sizes.push_back(llvm::ConstantInt::get(CGF.Int64Ty, 0));
}
@@ -8286,7 +8277,7 @@ public:
"Expect a executable directive");
const auto *CurExecDir = CurDir.get<const OMPExecutableDirective *>();
for (const auto *C : CurExecDir->getClausesOfKind<OMPMapClause>()) {
- for (const auto &L : C->decl_component_lists(VD)) {
+ for (const auto L : C->decl_component_lists(VD)) {
assert(L.first == VD &&
"We got information for the wrong declaration??");
assert(!L.second.empty() &&
@@ -8439,7 +8430,7 @@ public:
// Map other list items in the map clause which are not captured variables
// but "declare target link" global variables.
for (const auto *C : CurExecDir->getClausesOfKind<OMPMapClause>()) {
- for (const auto &L : C->component_lists()) {
+ for (const auto L : C->component_lists()) {
if (!L.first)
continue;
const auto *VD = dyn_cast<VarDecl>(L.first);
@@ -8517,7 +8508,7 @@ public:
CGF.CGM.getOpenMPRuntime().registerTargetFirstprivateCopy(CGF, VD);
// Copy the value of the original variable to the new global copy.
CGF.Builder.CreateMemCpy(
- CGF.MakeNaturalAlignAddrLValue(Addr, ElementType).getAddress(),
+ CGF.MakeNaturalAlignAddrLValue(Addr, ElementType).getAddress(CGF),
Address(CV, CGF.getContext().getTypeAlignInChars(ElementType)),
CurSizes.back(), /*IsVolatile=*/false);
// Use new global variable as the base pointers.
@@ -8746,6 +8737,7 @@ getNestedDistributeDirective(ASTContext &Ctx, const OMPExecutableDirective &D) {
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:
@@ -8791,6 +8783,7 @@ getNestedDistributeDirective(ASTContext &Ctx, const OMPExecutableDirective &D) {
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:
llvm_unreachable("Unexpected directive.");
@@ -8926,7 +8919,7 @@ void CGOpenMPRuntime::emitUserDefinedMapper(const OMPDeclareMapperDecl *D,
Scope.addPrivate(MapperVarDecl, [&MapperCGF, PtrCurrent, PtrTy]() {
return MapperCGF
.EmitLoadOfPointerLValue(PtrCurrent, PtrTy->castAs<PointerType>())
- .getAddress();
+ .getAddress(MapperCGF);
});
(void)Scope.Privatize();
@@ -9423,7 +9416,7 @@ void CGOpenMPRuntime::emitTargetCall(
// specify target triples.
if (OutlinedFnID) {
if (IfCond) {
- emitOMPIfClause(CGF, IfCond, TargetThenGen, TargetElseGen);
+ emitIfClause(CGF, IfCond, TargetThenGen, TargetElseGen);
} else {
RegionCodeGenTy ThenRCG(TargetThenGen);
ThenRCG(CGF);
@@ -9506,6 +9499,7 @@ void CGOpenMPRuntime::scanForTargetRegionsFunctions(const Stmt *S,
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:
@@ -9551,6 +9545,7 @@ void CGOpenMPRuntime::scanForTargetRegionsFunctions(const Stmt *S,
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:
llvm_unreachable("Unknown target directive for OpenMP device codegen.");
@@ -9591,9 +9586,9 @@ bool CGOpenMPRuntime::emitTargetFunctions(GlobalDecl GD) {
}
const ValueDecl *VD = cast<ValueDecl>(GD.getDecl());
- StringRef Name = CGM.getMangledName(GD);
// Try to detect target regions in the function.
if (const auto *FD = dyn_cast<FunctionDecl>(VD)) {
+ StringRef Name = CGM.getMangledName(GD);
scanForTargetRegionsFunctions(FD->getBody(), Name);
Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
OMPDeclareTargetDeclAttr::getDeviceType(FD);
@@ -9604,7 +9599,7 @@ bool CGOpenMPRuntime::emitTargetFunctions(GlobalDecl GD) {
// Do not to emit function if it is not marked as declare target.
return !OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD) &&
- AlreadyEmittedTargetFunctions.count(Name) == 0;
+ AlreadyEmittedTargetDecls.count(VD) == 0;
}
bool CGOpenMPRuntime::emitTargetGlobalVariable(GlobalDecl GD) {
@@ -9835,20 +9830,20 @@ bool CGOpenMPRuntime::markAsGlobalTarget(GlobalDecl GD) {
if (!CGM.getLangOpts().OpenMPIsDevice || !ShouldMarkAsGlobal)
return true;
- StringRef Name = CGM.getMangledName(GD);
const auto *D = cast<FunctionDecl>(GD.getDecl());
// Do not to emit function if it is marked as declare target as it was already
// emitted.
if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(D)) {
- if (D->hasBody() && AlreadyEmittedTargetFunctions.count(Name) == 0) {
- if (auto *F = dyn_cast_or_null<llvm::Function>(CGM.GetGlobalValue(Name)))
+ if (D->hasBody() && AlreadyEmittedTargetDecls.count(D) == 0) {
+ if (auto *F = dyn_cast_or_null<llvm::Function>(
+ CGM.GetGlobalValue(CGM.getMangledName(GD))))
return !F->isDeclaration();
return false;
}
return true;
}
- return !AlreadyEmittedTargetFunctions.insert(Name).second;
+ return !AlreadyEmittedTargetDecls.insert(D).second;
}
llvm::Function *CGOpenMPRuntime::emitRequiresDirectiveRegFun() {
@@ -10050,7 +10045,7 @@ void CGOpenMPRuntime::emitTargetDataCalls(
auto &&EndElseGen = [](CodeGenFunction &CGF, PrePostActionTy &) {};
if (IfCond) {
- emitOMPIfClause(CGF, IfCond, BeginThenGen, BeginElseGen);
+ emitIfClause(CGF, IfCond, BeginThenGen, BeginElseGen);
} else {
RegionCodeGenTy RCG(BeginThenGen);
RCG(CGF);
@@ -10064,7 +10059,7 @@ void CGOpenMPRuntime::emitTargetDataCalls(
}
if (IfCond) {
- emitOMPIfClause(CGF, IfCond, EndThenGen, EndElseGen);
+ emitIfClause(CGF, IfCond, EndThenGen, EndElseGen);
} else {
RegionCodeGenTy RCG(EndThenGen);
RCG(CGF);
@@ -10127,6 +10122,7 @@ void CGOpenMPRuntime::emitTargetDataStandAloneCall(
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:
@@ -10169,6 +10165,7 @@ void CGOpenMPRuntime::emitTargetDataStandAloneCall(
case OMPD_master_taskloop:
case OMPD_master_taskloop_simd:
case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_master_taskloop_simd:
case OMPD_target:
case OMPD_target_simd:
case OMPD_target_teams_distribute:
@@ -10220,8 +10217,8 @@ void CGOpenMPRuntime::emitTargetDataStandAloneCall(
};
if (IfCond) {
- emitOMPIfClause(CGF, IfCond, TargetThenGen,
- [](CodeGenFunction &CGF, PrePostActionTy &) {});
+ emitIfClause(CGF, IfCond, TargetThenGen,
+ [](CodeGenFunction &CGF, PrePostActionTy &) {});
} else {
RegionCodeGenTy ThenRCG(TargetThenGen);
ThenRCG(CGF);
@@ -10759,8 +10756,7 @@ void CGOpenMPRuntime::emitDeclareSimdFunction(const FunctionDecl *FD,
ExprLoc = VLENExpr->getExprLoc();
}
OMPDeclareSimdDeclAttr::BranchStateTy State = Attr->getBranchState();
- if (CGM.getTriple().getArch() == llvm::Triple::x86 ||
- CGM.getTriple().getArch() == llvm::Triple::x86_64) {
+ if (CGM.getTriple().isX86()) {
emitX86DeclareSimdFunction(FD, Fn, VLENVal, ParamAttrs, State);
} else if (CGM.getTriple().getArch() == llvm::Triple::aarch64) {
unsigned VLEN = VLENVal.getExtValue();
@@ -11018,12 +11014,18 @@ Address CGOpenMPRuntime::getAddressOfLocalVariable(CodeGenFunction &CGF,
return Address(Addr, Align);
}
+namespace {
+using OMPContextSelectorData =
+ OpenMPCtxSelectorData<ArrayRef<StringRef>, llvm::APSInt>;
+using CompleteOMPContextSelectorData = SmallVector<OMPContextSelectorData, 4>;
+} // anonymous namespace
+
/// Checks current context and returns true if it matches the context selector.
-template <OMPDeclareVariantAttr::CtxSelectorSetType CtxSet,
- OMPDeclareVariantAttr::CtxSelectorType Ctx>
-static bool checkContext(const OMPDeclareVariantAttr *A) {
- assert(CtxSet != OMPDeclareVariantAttr::CtxSetUnknown &&
- Ctx != OMPDeclareVariantAttr::CtxUnknown &&
+template <OpenMPContextSelectorSetKind CtxSet, OpenMPContextSelectorKind Ctx,
+ typename... Arguments>
+static bool checkContext(const OMPContextSelectorData &Data,
+ Arguments... Params) {
+ assert(Data.CtxSet != OMP_CTX_SET_unknown && Data.Ctx != OMP_CTX_unknown &&
"Unknown context selector or context selector set.");
return false;
}
@@ -11031,89 +11033,233 @@ static bool checkContext(const OMPDeclareVariantAttr *A) {
/// Checks for implementation={vendor(<vendor>)} context selector.
/// \returns true iff <vendor>="llvm", false otherwise.
template <>
-bool checkContext<OMPDeclareVariantAttr::CtxSetImplementation,
- OMPDeclareVariantAttr::CtxVendor>(
- const OMPDeclareVariantAttr *A) {
- return llvm::all_of(A->implVendors(),
+bool checkContext<OMP_CTX_SET_implementation, OMP_CTX_vendor>(
+ const OMPContextSelectorData &Data) {
+ return llvm::all_of(Data.Names,
[](StringRef S) { return !S.compare_lower("llvm"); });
}
-static bool greaterCtxScore(ASTContext &Ctx, const Expr *LHS, const Expr *RHS) {
- // If both scores are unknown, choose the very first one.
- if (!LHS && !RHS)
- return true;
- // If only one is known, return this one.
- if (LHS && !RHS)
- return true;
- if (!LHS && RHS)
- return false;
- llvm::APSInt LHSVal = LHS->EvaluateKnownConstInt(Ctx);
- llvm::APSInt RHSVal = RHS->EvaluateKnownConstInt(Ctx);
- return llvm::APSInt::compareValues(LHSVal, RHSVal) >= 0;
+/// Checks for device={kind(<kind>)} context selector.
+/// \returns true if <kind>="host" and compilation is for host.
+/// true if <kind>="nohost" and compilation is for device.
+/// true if <kind>="cpu" and compilation is for Arm, X86 or PPC CPU.
+/// true if <kind>="gpu" and compilation is for NVPTX or AMDGCN.
+/// false otherwise.
+template <>
+bool checkContext<OMP_CTX_SET_device, OMP_CTX_kind, CodeGenModule &>(
+ const OMPContextSelectorData &Data, CodeGenModule &CGM) {
+ for (StringRef Name : Data.Names) {
+ if (!Name.compare_lower("host")) {
+ if (CGM.getLangOpts().OpenMPIsDevice)
+ return false;
+ continue;
+ }
+ if (!Name.compare_lower("nohost")) {
+ if (!CGM.getLangOpts().OpenMPIsDevice)
+ return false;
+ continue;
+ }
+ switch (CGM.getTriple().getArch()) {
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
+ case llvm::Triple::aarch64_32:
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ if (Name.compare_lower("cpu"))
+ return false;
+ break;
+ case llvm::Triple::amdgcn:
+ case llvm::Triple::nvptx:
+ case llvm::Triple::nvptx64:
+ if (Name.compare_lower("gpu"))
+ return false;
+ break;
+ case llvm::Triple::UnknownArch:
+ case llvm::Triple::arc:
+ case llvm::Triple::avr:
+ case llvm::Triple::bpfel:
+ case llvm::Triple::bpfeb:
+ case llvm::Triple::hexagon:
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ case llvm::Triple::msp430:
+ case llvm::Triple::r600:
+ case llvm::Triple::riscv32:
+ case llvm::Triple::riscv64:
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcv9:
+ case llvm::Triple::sparcel:
+ case llvm::Triple::systemz:
+ case llvm::Triple::tce:
+ case llvm::Triple::tcele:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ case llvm::Triple::xcore:
+ case llvm::Triple::le32:
+ case llvm::Triple::le64:
+ case llvm::Triple::amdil:
+ case llvm::Triple::amdil64:
+ case llvm::Triple::hsail:
+ case llvm::Triple::hsail64:
+ case llvm::Triple::spir:
+ case llvm::Triple::spir64:
+ case llvm::Triple::kalimba:
+ case llvm::Triple::shave:
+ case llvm::Triple::lanai:
+ case llvm::Triple::wasm32:
+ case llvm::Triple::wasm64:
+ case llvm::Triple::renderscript32:
+ case llvm::Triple::renderscript64:
+ case llvm::Triple::ve:
+ return false;
+ }
+ }
+ return true;
}
-namespace {
-/// Comparator for the priority queue for context selector.
-class OMPDeclareVariantAttrComparer
- : public std::greater<const OMPDeclareVariantAttr *> {
-private:
- ASTContext &Ctx;
+static bool matchesContext(CodeGenModule &CGM,
+ const CompleteOMPContextSelectorData &ContextData) {
+ for (const OMPContextSelectorData &Data : ContextData) {
+ switch (Data.Ctx) {
+ case OMP_CTX_vendor:
+ assert(Data.CtxSet == OMP_CTX_SET_implementation &&
+ "Expected implementation context selector set.");
+ if (!checkContext<OMP_CTX_SET_implementation, OMP_CTX_vendor>(Data))
+ return false;
+ break;
+ case OMP_CTX_kind:
+ assert(Data.CtxSet == OMP_CTX_SET_device &&
+ "Expected device context selector set.");
+ if (!checkContext<OMP_CTX_SET_device, OMP_CTX_kind, CodeGenModule &>(Data,
+ CGM))
+ return false;
+ break;
+ case OMP_CTX_unknown:
+ llvm_unreachable("Unknown context selector kind.");
+ }
+ }
+ return true;
+}
-public:
- OMPDeclareVariantAttrComparer(ASTContext &Ctx) : Ctx(Ctx) {}
- bool operator()(const OMPDeclareVariantAttr *LHS,
- const OMPDeclareVariantAttr *RHS) const {
- const Expr *LHSExpr = nullptr;
- const Expr *RHSExpr = nullptr;
- if (LHS->getCtxScore() == OMPDeclareVariantAttr::ScoreSpecified)
- LHSExpr = LHS->getScore();
- if (RHS->getCtxScore() == OMPDeclareVariantAttr::ScoreSpecified)
- RHSExpr = RHS->getScore();
- return greaterCtxScore(Ctx, LHSExpr, RHSExpr);
+static CompleteOMPContextSelectorData
+translateAttrToContextSelectorData(ASTContext &C,
+ const OMPDeclareVariantAttr *A) {
+ CompleteOMPContextSelectorData Data;
+ for (unsigned I = 0, E = A->scores_size(); I < E; ++I) {
+ Data.emplace_back();
+ auto CtxSet = static_cast<OpenMPContextSelectorSetKind>(
+ *std::next(A->ctxSelectorSets_begin(), I));
+ auto Ctx = static_cast<OpenMPContextSelectorKind>(
+ *std::next(A->ctxSelectors_begin(), I));
+ Data.back().CtxSet = CtxSet;
+ Data.back().Ctx = Ctx;
+ const Expr *Score = *std::next(A->scores_begin(), I);
+ Data.back().Score = Score->EvaluateKnownConstInt(C);
+ switch (Ctx) {
+ case OMP_CTX_vendor:
+ assert(CtxSet == OMP_CTX_SET_implementation &&
+ "Expected implementation context selector set.");
+ Data.back().Names =
+ llvm::makeArrayRef(A->implVendors_begin(), A->implVendors_end());
+ break;
+ case OMP_CTX_kind:
+ assert(CtxSet == OMP_CTX_SET_device &&
+ "Expected device context selector set.");
+ Data.back().Names =
+ llvm::makeArrayRef(A->deviceKinds_begin(), A->deviceKinds_end());
+ break;
+ case OMP_CTX_unknown:
+ llvm_unreachable("Unknown context selector kind.");
+ }
}
-};
-} // anonymous namespace
+ return Data;
+}
+
+static bool isStrictSubset(const CompleteOMPContextSelectorData &LHS,
+ const CompleteOMPContextSelectorData &RHS) {
+ llvm::SmallDenseMap<std::pair<int, int>, llvm::StringSet<>, 4> RHSData;
+ for (const OMPContextSelectorData &D : RHS) {
+ auto &Pair = RHSData.FindAndConstruct(std::make_pair(D.CtxSet, D.Ctx));
+ Pair.getSecond().insert(D.Names.begin(), D.Names.end());
+ }
+ bool AllSetsAreEqual = true;
+ for (const OMPContextSelectorData &D : LHS) {
+ auto It = RHSData.find(std::make_pair(D.CtxSet, D.Ctx));
+ if (It == RHSData.end())
+ return false;
+ if (D.Names.size() > It->getSecond().size())
+ return false;
+ if (llvm::set_union(It->getSecond(), D.Names))
+ return false;
+ AllSetsAreEqual =
+ AllSetsAreEqual && (D.Names.size() == It->getSecond().size());
+ }
+
+ return LHS.size() != RHS.size() || !AllSetsAreEqual;
+}
+
+static bool greaterCtxScore(const CompleteOMPContextSelectorData &LHS,
+ const CompleteOMPContextSelectorData &RHS) {
+ // Score is calculated as sum of all scores + 1.
+ llvm::APSInt LHSScore(llvm::APInt(64, 1), /*isUnsigned=*/false);
+ bool RHSIsSubsetOfLHS = isStrictSubset(RHS, LHS);
+ if (RHSIsSubsetOfLHS) {
+ LHSScore = llvm::APSInt::get(0);
+ } else {
+ for (const OMPContextSelectorData &Data : LHS) {
+ if (Data.Score.getBitWidth() > LHSScore.getBitWidth()) {
+ LHSScore = LHSScore.extend(Data.Score.getBitWidth()) + Data.Score;
+ } else if (Data.Score.getBitWidth() < LHSScore.getBitWidth()) {
+ LHSScore += Data.Score.extend(LHSScore.getBitWidth());
+ } else {
+ LHSScore += Data.Score;
+ }
+ }
+ }
+ llvm::APSInt RHSScore(llvm::APInt(64, 1), /*isUnsigned=*/false);
+ if (!RHSIsSubsetOfLHS && isStrictSubset(LHS, RHS)) {
+ RHSScore = llvm::APSInt::get(0);
+ } else {
+ for (const OMPContextSelectorData &Data : RHS) {
+ if (Data.Score.getBitWidth() > RHSScore.getBitWidth()) {
+ RHSScore = RHSScore.extend(Data.Score.getBitWidth()) + Data.Score;
+ } else if (Data.Score.getBitWidth() < RHSScore.getBitWidth()) {
+ RHSScore += Data.Score.extend(RHSScore.getBitWidth());
+ } else {
+ RHSScore += Data.Score;
+ }
+ }
+ }
+ return llvm::APSInt::compareValues(LHSScore, RHSScore) >= 0;
+}
/// Finds the variant function that matches current context with its context
/// selector.
-static const FunctionDecl *getDeclareVariantFunction(ASTContext &Ctx,
+static const FunctionDecl *getDeclareVariantFunction(CodeGenModule &CGM,
const FunctionDecl *FD) {
if (!FD->hasAttrs() || !FD->hasAttr<OMPDeclareVariantAttr>())
return FD;
// Iterate through all DeclareVariant attributes and check context selectors.
- auto &&Comparer = [&Ctx](const OMPDeclareVariantAttr *LHS,
- const OMPDeclareVariantAttr *RHS) {
- const Expr *LHSExpr = nullptr;
- const Expr *RHSExpr = nullptr;
- if (LHS->getCtxScore() == OMPDeclareVariantAttr::ScoreSpecified)
- LHSExpr = LHS->getScore();
- if (RHS->getCtxScore() == OMPDeclareVariantAttr::ScoreSpecified)
- RHSExpr = RHS->getScore();
- return greaterCtxScore(Ctx, LHSExpr, RHSExpr);
- };
const OMPDeclareVariantAttr *TopMostAttr = nullptr;
+ CompleteOMPContextSelectorData TopMostData;
for (const auto *A : FD->specific_attrs<OMPDeclareVariantAttr>()) {
- const OMPDeclareVariantAttr *SelectedAttr = nullptr;
- switch (A->getCtxSelectorSet()) {
- case OMPDeclareVariantAttr::CtxSetImplementation:
- switch (A->getCtxSelector()) {
- case OMPDeclareVariantAttr::CtxVendor:
- if (checkContext<OMPDeclareVariantAttr::CtxSetImplementation,
- OMPDeclareVariantAttr::CtxVendor>(A))
- SelectedAttr = A;
- break;
- case OMPDeclareVariantAttr::CtxUnknown:
- llvm_unreachable(
- "Unknown context selector in implementation selector set.");
- }
- break;
- case OMPDeclareVariantAttr::CtxSetUnknown:
- llvm_unreachable("Unknown context selector set.");
- }
+ CompleteOMPContextSelectorData Data =
+ translateAttrToContextSelectorData(CGM.getContext(), A);
+ if (!matchesContext(CGM, Data))
+ continue;
// If the attribute matches the context, find the attribute with the highest
// score.
- if (SelectedAttr && (!TopMostAttr || !Comparer(TopMostAttr, SelectedAttr)))
- TopMostAttr = SelectedAttr;
+ if (!TopMostAttr || !greaterCtxScore(TopMostData, Data)) {
+ TopMostAttr = A;
+ TopMostData.swap(Data);
+ }
}
if (!TopMostAttr)
return FD;
@@ -11129,7 +11275,7 @@ bool CGOpenMPRuntime::emitDeclareVariant(GlobalDecl GD, bool IsForDefinition) {
llvm::GlobalValue *Orig = CGM.GetGlobalValue(MangledName);
if (Orig && !Orig->isDeclaration())
return false;
- const FunctionDecl *NewFD = getDeclareVariantFunction(CGM.getContext(), D);
+ const FunctionDecl *NewFD = getDeclareVariantFunction(CGM, D);
// Emit original function if it does not have declare variant attribute or the
// context does not match.
if (NewFD == D)
@@ -11143,6 +11289,320 @@ bool CGOpenMPRuntime::emitDeclareVariant(GlobalDecl GD, bool IsForDefinition) {
return true;
}
+CGOpenMPRuntime::NontemporalDeclsRAII::NontemporalDeclsRAII(
+ CodeGenModule &CGM, const OMPLoopDirective &S)
+ : CGM(CGM), NeedToPush(S.hasClausesOfKind<OMPNontemporalClause>()) {
+ assert(CGM.getLangOpts().OpenMP && "Not in OpenMP mode.");
+ if (!NeedToPush)
+ return;
+ NontemporalDeclsSet &DS =
+ CGM.getOpenMPRuntime().NontemporalDeclsStack.emplace_back();
+ for (const auto *C : S.getClausesOfKind<OMPNontemporalClause>()) {
+ for (const Stmt *Ref : C->private_refs()) {
+ const auto *SimpleRefExpr = cast<Expr>(Ref)->IgnoreParenImpCasts();
+ const ValueDecl *VD;
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(SimpleRefExpr)) {
+ VD = DRE->getDecl();
+ } else {
+ const auto *ME = cast<MemberExpr>(SimpleRefExpr);
+ assert((ME->isImplicitCXXThis() ||
+ isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts())) &&
+ "Expected member of current class.");
+ VD = ME->getMemberDecl();
+ }
+ DS.insert(VD);
+ }
+ }
+}
+
+CGOpenMPRuntime::NontemporalDeclsRAII::~NontemporalDeclsRAII() {
+ if (!NeedToPush)
+ return;
+ CGM.getOpenMPRuntime().NontemporalDeclsStack.pop_back();
+}
+
+bool CGOpenMPRuntime::isNontemporalDecl(const ValueDecl *VD) const {
+ assert(CGM.getLangOpts().OpenMP && "Not in OpenMP mode.");
+
+ return llvm::any_of(
+ CGM.getOpenMPRuntime().NontemporalDeclsStack,
+ [VD](const NontemporalDeclsSet &Set) { return Set.count(VD) > 0; });
+}
+
+CGOpenMPRuntime::LastprivateConditionalRAII::LastprivateConditionalRAII(
+ CodeGenFunction &CGF, const OMPExecutableDirective &S, LValue IVLVal)
+ : CGM(CGF.CGM),
+ NeedToPush(llvm::any_of(S.getClausesOfKind<OMPLastprivateClause>(),
+ [](const OMPLastprivateClause *C) {
+ return C->getKind() ==
+ OMPC_LASTPRIVATE_conditional;
+ })) {
+ assert(CGM.getLangOpts().OpenMP && "Not in OpenMP mode.");
+ if (!NeedToPush)
+ return;
+ LastprivateConditionalData &Data =
+ CGM.getOpenMPRuntime().LastprivateConditionalStack.emplace_back();
+ for (const auto *C : S.getClausesOfKind<OMPLastprivateClause>()) {
+ if (C->getKind() != OMPC_LASTPRIVATE_conditional)
+ continue;
+
+ for (const Expr *Ref : C->varlists()) {
+ Data.DeclToUniqeName.try_emplace(
+ cast<DeclRefExpr>(Ref->IgnoreParenImpCasts())->getDecl(),
+ generateUniqueName(CGM, "pl_cond", Ref));
+ }
+ }
+ Data.IVLVal = IVLVal;
+ // In simd only mode or for simd directives no need to generate threadprivate
+ // references for the loop iteration counter, we can use the original one
+ // since outlining cannot happen in simd regions.
+ if (CGF.getLangOpts().OpenMPSimd ||
+ isOpenMPSimdDirective(S.getDirectiveKind())) {
+ Data.UseOriginalIV = true;
+ return;
+ }
+ llvm::SmallString<16> Buffer;
+ llvm::raw_svector_ostream OS(Buffer);
+ PresumedLoc PLoc =
+ CGM.getContext().getSourceManager().getPresumedLoc(S.getBeginLoc());
+ assert(PLoc.isValid() && "Source location is expected to be always valid.");
+
+ llvm::sys::fs::UniqueID ID;
+ if (auto EC = llvm::sys::fs::getUniqueID(PLoc.getFilename(), ID))
+ CGM.getDiags().Report(diag::err_cannot_open_file)
+ << PLoc.getFilename() << EC.message();
+ OS << "$pl_cond_" << ID.getDevice() << "_" << ID.getFile() << "_"
+ << PLoc.getLine() << "_" << PLoc.getColumn() << "$iv";
+ Data.IVName = OS.str();
+}
+
+CGOpenMPRuntime::LastprivateConditionalRAII::~LastprivateConditionalRAII() {
+ if (!NeedToPush)
+ return;
+ CGM.getOpenMPRuntime().LastprivateConditionalStack.pop_back();
+}
+
+void CGOpenMPRuntime::initLastprivateConditionalCounter(
+ CodeGenFunction &CGF, const OMPExecutableDirective &S) {
+ if (CGM.getLangOpts().OpenMPSimd ||
+ !llvm::any_of(S.getClausesOfKind<OMPLastprivateClause>(),
+ [](const OMPLastprivateClause *C) {
+ return C->getKind() == OMPC_LASTPRIVATE_conditional;
+ }))
+ return;
+ const CGOpenMPRuntime::LastprivateConditionalData &Data =
+ LastprivateConditionalStack.back();
+ if (Data.UseOriginalIV)
+ return;
+ // Global loop counter. Required to handle inner parallel-for regions.
+ // global_iv = iv;
+ Address GlobIVAddr = CGM.getOpenMPRuntime().getAddrOfArtificialThreadPrivate(
+ CGF, Data.IVLVal.getType(), Data.IVName);
+ LValue GlobIVLVal = CGF.MakeAddrLValue(GlobIVAddr, Data.IVLVal.getType());
+ llvm::Value *IVVal = CGF.EmitLoadOfScalar(Data.IVLVal, S.getBeginLoc());
+ CGF.EmitStoreOfScalar(IVVal, GlobIVLVal);
+}
+
+namespace {
+/// Checks if the lastprivate conditional variable is referenced in LHS.
+class LastprivateConditionalRefChecker final
+ : public ConstStmtVisitor<LastprivateConditionalRefChecker, bool> {
+ CodeGenFunction &CGF;
+ ArrayRef<CGOpenMPRuntime::LastprivateConditionalData> LPM;
+ const Expr *FoundE = nullptr;
+ const Decl *FoundD = nullptr;
+ StringRef UniqueDeclName;
+ LValue IVLVal;
+ StringRef IVName;
+ SourceLocation Loc;
+ bool UseOriginalIV = false;
+
+public:
+ bool VisitDeclRefExpr(const DeclRefExpr *E) {
+ for (const CGOpenMPRuntime::LastprivateConditionalData &D :
+ llvm::reverse(LPM)) {
+ auto It = D.DeclToUniqeName.find(E->getDecl());
+ if (It == D.DeclToUniqeName.end())
+ continue;
+ FoundE = E;
+ FoundD = E->getDecl()->getCanonicalDecl();
+ UniqueDeclName = It->getSecond();
+ IVLVal = D.IVLVal;
+ IVName = D.IVName;
+ UseOriginalIV = D.UseOriginalIV;
+ break;
+ }
+ return FoundE == E;
+ }
+ bool VisitMemberExpr(const MemberExpr *E) {
+ if (!CGF.IsWrappedCXXThis(E->getBase()))
+ return false;
+ for (const CGOpenMPRuntime::LastprivateConditionalData &D :
+ llvm::reverse(LPM)) {
+ auto It = D.DeclToUniqeName.find(E->getMemberDecl());
+ if (It == D.DeclToUniqeName.end())
+ continue;
+ FoundE = E;
+ FoundD = E->getMemberDecl()->getCanonicalDecl();
+ UniqueDeclName = It->getSecond();
+ IVLVal = D.IVLVal;
+ IVName = D.IVName;
+ UseOriginalIV = D.UseOriginalIV;
+ break;
+ }
+ return FoundE == E;
+ }
+ bool VisitStmt(const Stmt *S) {
+ for (const Stmt *Child : S->children()) {
+ if (!Child)
+ continue;
+ if (const auto *E = dyn_cast<Expr>(Child))
+ if (!E->isGLValue())
+ continue;
+ if (Visit(Child))
+ return true;
+ }
+ return false;
+ }
+ explicit LastprivateConditionalRefChecker(
+ CodeGenFunction &CGF,
+ ArrayRef<CGOpenMPRuntime::LastprivateConditionalData> LPM)
+ : CGF(CGF), LPM(LPM) {}
+ std::tuple<const Expr *, const Decl *, StringRef, LValue, StringRef, bool>
+ getFoundData() const {
+ return std::make_tuple(FoundE, FoundD, UniqueDeclName, IVLVal, IVName,
+ UseOriginalIV);
+ }
+};
+} // namespace
+
+void CGOpenMPRuntime::checkAndEmitLastprivateConditional(CodeGenFunction &CGF,
+ const Expr *LHS) {
+ if (CGF.getLangOpts().OpenMP < 50)
+ return;
+ LastprivateConditionalRefChecker Checker(CGF, LastprivateConditionalStack);
+ if (!Checker.Visit(LHS))
+ return;
+ const Expr *FoundE;
+ const Decl *FoundD;
+ StringRef UniqueDeclName;
+ LValue IVLVal;
+ StringRef IVName;
+ bool UseOriginalIV;
+ std::tie(FoundE, FoundD, UniqueDeclName, IVLVal, IVName, UseOriginalIV) =
+ Checker.getFoundData();
+
+ // 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, UniqueDeclName + "$iv");
+ cast<llvm::GlobalVariable>(LastIV)->setAlignment(
+ IVLVal.getAlignment().getAsAlign());
+ LValue LastIVLVal = CGF.MakeNaturalAlignAddrLValue(LastIV, IVLVal.getType());
+
+ // Private address of the lastprivate conditional in the current context.
+ // priv_a
+ LValue LVal = CGF.EmitLValue(FoundE);
+ // Last value of the lastprivate conditional.
+ // decltype(priv_a) last_a;
+ llvm::Constant *Last = getOrCreateInternalVariable(
+ LVal.getAddress(CGF).getElementType(), UniqueDeclName);
+ cast<llvm::GlobalVariable>(Last)->setAlignment(
+ LVal.getAlignment().getAsAlign());
+ LValue LastLVal =
+ CGF.MakeAddrLValue(Last, LVal.getType(), LVal.getAlignment());
+
+ // Global loop counter. Required to handle inner parallel-for regions.
+ // global_iv
+ if (!UseOriginalIV) {
+ Address IVAddr =
+ getAddrOfArtificialThreadPrivate(CGF, IVLVal.getType(), IVName);
+ IVLVal = CGF.MakeAddrLValue(IVAddr, IVLVal.getType());
+ }
+ llvm::Value *IVVal = CGF.EmitLoadOfScalar(IVLVal, FoundE->getExprLoc());
+
+ // #pragma omp critical(a)
+ // if (last_iv <= iv) {
+ // last_iv = iv;
+ // last_a = priv_a;
+ // }
+ auto &&CodeGen = [&LastIVLVal, &IVLVal, IVVal, &LVal, &LastLVal,
+ FoundE](CodeGenFunction &CGF, PrePostActionTy &Action) {
+ Action.Enter(CGF);
+ llvm::Value *LastIVVal =
+ CGF.EmitLoadOfScalar(LastIVLVal, FoundE->getExprLoc());
+ // (last_iv <= global_iv) ? Check if the variable is updated and store new
+ // value in global var.
+ llvm::Value *CmpRes;
+ if (IVLVal.getType()->isSignedIntegerType()) {
+ CmpRes = CGF.Builder.CreateICmpSLE(LastIVVal, IVVal);
+ } else {
+ assert(IVLVal.getType()->isUnsignedIntegerType() &&
+ "Loop iteration variable must be integer.");
+ CmpRes = CGF.Builder.CreateICmpULE(LastIVVal, IVVal);
+ }
+ llvm::BasicBlock *ThenBB = CGF.createBasicBlock("lp_cond_then");
+ llvm::BasicBlock *ExitBB = CGF.createBasicBlock("lp_cond_exit");
+ CGF.Builder.CreateCondBr(CmpRes, ThenBB, ExitBB);
+ // {
+ CGF.EmitBlock(ThenBB);
+
+ // last_iv = global_iv;
+ CGF.EmitStoreOfScalar(IVVal, LastIVLVal);
+
+ // last_a = priv_a;
+ switch (CGF.getEvaluationKind(LVal.getType())) {
+ case TEK_Scalar: {
+ llvm::Value *PrivVal = CGF.EmitLoadOfScalar(LVal, FoundE->getExprLoc());
+ CGF.EmitStoreOfScalar(PrivVal, LastLVal);
+ break;
+ }
+ case TEK_Complex: {
+ CodeGenFunction::ComplexPairTy PrivVal =
+ CGF.EmitLoadOfComplex(LVal, FoundE->getExprLoc());
+ CGF.EmitStoreOfComplex(PrivVal, LastLVal, /*isInit=*/false);
+ break;
+ }
+ case TEK_Aggregate:
+ llvm_unreachable(
+ "Aggregates are not supported in lastprivate conditional.");
+ }
+ // }
+ CGF.EmitBranch(ExitBB);
+ // There is no need to emit line number for unconditional branch.
+ (void)ApplyDebugLocation::CreateEmpty(CGF);
+ CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
+ };
+
+ if (CGM.getLangOpts().OpenMPSimd) {
+ // Do not emit as a critical region as no parallel region could be emitted.
+ RegionCodeGenTy ThenRCG(CodeGen);
+ ThenRCG(CGF);
+ } else {
+ emitCriticalRegion(CGF, UniqueDeclName, CodeGen, FoundE->getExprLoc());
+ }
+}
+
+void CGOpenMPRuntime::emitLastprivateConditionalFinalUpdate(
+ CodeGenFunction &CGF, LValue PrivLVal, const VarDecl *VD,
+ SourceLocation Loc) {
+ if (CGF.getLangOpts().OpenMP < 50)
+ return;
+ auto It = LastprivateConditionalStack.back().DeclToUniqeName.find(VD);
+ assert(It != LastprivateConditionalStack.back().DeclToUniqeName.end() &&
+ "Unknown lastprivate conditional variable.");
+ StringRef UniqueName = It->getSecond();
+ llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(UniqueName);
+ // The variable was not updated in the region - exit.
+ if (!GV)
+ return;
+ LValue LPLVal = CGF.MakeAddrLValue(
+ GV, PrivLVal.getType().getNonReferenceType(), PrivLVal.getAlignment());
+ llvm::Value *Res = CGF.EmitLoadOfScalar(LPLVal, Loc);
+ CGF.EmitStoreOfScalar(Res, PrivLVal);
+}
+
llvm::Function *CGOpenMPSIMDRuntime::emitParallelOutlinedFunction(
const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) {
@@ -11265,7 +11725,7 @@ void CGOpenMPSIMDRuntime::emitNumThreadsClause(CodeGenFunction &CGF,
}
void CGOpenMPSIMDRuntime::emitProcBindClause(CodeGenFunction &CGF,
- OpenMPProcBindClauseKind ProcBind,
+ ProcBindKind ProcBind,
SourceLocation Loc) {
llvm_unreachable("Not supported in SIMD-only mode");
}
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.h b/clang/lib/CodeGen/CGOpenMPRuntime.h
index bf8e0ac80909..8159f5e8b790 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.h
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.h
@@ -20,8 +20,10 @@
#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/Frontend/OpenMP/OMPConstants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/ValueHandle.h"
@@ -211,6 +213,43 @@ public:
~DisableAutoDeclareTargetRAII();
};
+ /// Manages list of nontemporal decls for the specified directive.
+ class NontemporalDeclsRAII {
+ CodeGenModule &CGM;
+ const bool NeedToPush;
+
+ public:
+ NontemporalDeclsRAII(CodeGenModule &CGM, const OMPLoopDirective &S);
+ ~NontemporalDeclsRAII();
+ };
+
+ /// Maps the expression for the lastprivate variable to the global copy used
+ /// to store new value because original variables are not mapped in inner
+ /// parallel regions. Only private copies are captured but we need also to
+ /// store private copy in shared address.
+ /// Also, stores the expression for the private loop counter and it
+ /// threaprivate name.
+ struct LastprivateConditionalData {
+ llvm::SmallDenseMap<CanonicalDeclPtr<const Decl>, SmallString<16>>
+ DeclToUniqeName;
+ LValue IVLVal;
+ SmallString<16> IVName;
+ /// True if original lvalue for loop counter can be used in codegen (simd
+ /// region or simd only mode) and no need to create threadprivate
+ /// references.
+ bool UseOriginalIV = false;
+ };
+ /// Manages list of lastprivate conditional decls for the specified directive.
+ class LastprivateConditionalRAII {
+ CodeGenModule &CGM;
+ const bool NeedToPush;
+
+ public:
+ LastprivateConditionalRAII(CodeGenFunction &CGF,
+ const OMPExecutableDirective &S, LValue IVLVal);
+ ~LastprivateConditionalRAII();
+ };
+
protected:
CodeGenModule &CGM;
StringRef FirstSeparator, Separator;
@@ -241,17 +280,6 @@ protected:
bool IsOffloadEntry,
const RegionCodeGenTy &CodeGen);
- /// Emits code for OpenMP 'if' clause using specified \a CodeGen
- /// function. Here is the logic:
- /// if (Cond) {
- /// ThenGen();
- /// } else {
- /// ElseGen();
- /// }
- void emitOMPIfClause(CodeGenFunction &CGF, const Expr *Cond,
- const RegionCodeGenTy &ThenGen,
- const RegionCodeGenTy &ElseGen);
-
/// Emits object of ident_t type with info for source location.
/// \param Flags Flags for OpenMP location.
///
@@ -411,29 +439,10 @@ private:
/// // (function or global)
/// char *name; // Name of the function or global.
/// size_t size; // Size of the entry info (0 if it a function).
+ /// int32_t flags;
+ /// int32_t reserved;
/// };
QualType TgtOffloadEntryQTy;
- /// struct __tgt_device_image{
- /// void *ImageStart; // Pointer to the target code start.
- /// void *ImageEnd; // Pointer to the target code end.
- /// // We also add the host entries to the device image, as it may be useful
- /// // for the target runtime to have access to that information.
- /// __tgt_offload_entry *EntriesBegin; // Begin of the table with all
- /// // the entries.
- /// __tgt_offload_entry *EntriesEnd; // End of the table with all the
- /// // entries (non inclusive).
- /// };
- QualType TgtDeviceImageQTy;
- /// struct __tgt_bin_desc{
- /// int32_t NumDevices; // Number of devices supported.
- /// __tgt_device_image *DeviceImages; // Arrays of device images
- /// // (one per device).
- /// __tgt_offload_entry *EntriesBegin; // Begin of the table with all the
- /// // entries.
- /// __tgt_offload_entry *EntriesEnd; // End of the table with all the
- /// // entries (non inclusive).
- /// };
- QualType TgtBinaryDescriptorQTy;
/// Entity that registers the offloading constants that were emitted so
/// far.
class OffloadEntriesInfoManagerTy {
@@ -645,8 +654,8 @@ private:
OffloadEntriesInfoManagerTy OffloadEntriesInfoManager;
bool ShouldMarkAsGlobal = true;
- /// List of the emitted functions.
- llvm::StringSet<> AlreadyEmittedTargetFunctions;
+ /// List of the emitted declarations.
+ llvm::DenseSet<CanonicalDeclPtr<const Decl>> AlreadyEmittedTargetDecls;
/// List of the global variables with their addresses that should not be
/// emitted for the target.
llvm::StringMap<llvm::WeakTrackingVH> EmittedNonTargetVariables;
@@ -661,6 +670,16 @@ private:
std::pair<GlobalDecl, GlobalDecl>>
DeferredVariantFunction;
+ using NontemporalDeclsSet = llvm::SmallDenseSet<CanonicalDeclPtr<const Decl>>;
+ /// Stack for list of declarations in current context marked as nontemporal.
+ /// The set is the union of all current stack elements.
+ llvm::SmallVector<NontemporalDeclsSet, 4> NontemporalDeclsStack;
+
+ /// Stack for list of addresses of declarations in current context marked as
+ /// lastprivate conditional. The set is the union of all current stack
+ /// elements.
+ llvm::SmallVector<LastprivateConditionalData, 4> LastprivateConditionalStack;
+
/// Flag for keeping track of weather a requires unified_shared_memory
/// directive is present.
bool HasRequiresUnifiedSharedMemory = false;
@@ -679,12 +698,6 @@ private:
/// Returns __tgt_offload_entry type.
QualType getTgtOffloadEntryQTy();
- /// Returns __tgt_device_image type.
- QualType getTgtDeviceImageQTy();
-
- /// Returns __tgt_bin_desc type.
- QualType getTgtBinaryDescriptorQTy();
-
/// Start scanning from statement \a S and and emit all target regions
/// found along the way.
/// \param S Starting statement.
@@ -819,6 +832,17 @@ public:
virtual ~CGOpenMPRuntime() {}
virtual void clear();
+ /// Emits code for OpenMP 'if' clause using specified \a CodeGen
+ /// function. Here is the logic:
+ /// if (Cond) {
+ /// ThenGen();
+ /// } else {
+ /// ElseGen();
+ /// }
+ void emitIfClause(CodeGenFunction &CGF, const Expr *Cond,
+ const RegionCodeGenTy &ThenGen,
+ const RegionCodeGenTy &ElseGen);
+
/// Checks if the \p Body is the \a CompoundStmt and returns its child
/// statement iff there is only one that is not evaluatable at the compile
/// time.
@@ -1146,7 +1170,7 @@ public:
/// Emit call to void __kmpc_push_proc_bind(ident_t *loc, kmp_int32
/// global_tid, int proc_bind) to generate code for 'proc_bind' clause.
virtual void emitProcBindClause(CodeGenFunction &CGF,
- OpenMPProcBindClauseKind ProcBind,
+ llvm::omp::ProcBindKind ProcBind,
SourceLocation Loc);
/// Returns address of the threadprivate variable for the current
@@ -1663,6 +1687,40 @@ public:
/// Emits the definition of the declare variant function.
virtual bool emitDeclareVariant(GlobalDecl GD, bool IsForDefinition);
+
+ /// Checks if the \p VD variable is marked as nontemporal declaration in
+ /// current context.
+ bool isNontemporalDecl(const ValueDecl *VD) const;
+
+ /// Initializes global counter for lastprivate conditional.
+ virtual void
+ initLastprivateConditionalCounter(CodeGenFunction &CGF,
+ const OMPExecutableDirective &S);
+
+ /// Checks if the provided \p LVal is lastprivate conditional and emits the
+ /// code to update the value of the original variable.
+ /// \code
+ /// lastprivate(conditional: a)
+ /// ...
+ /// <type> a;
+ /// lp_a = ...;
+ /// #pragma omp critical(a)
+ /// if (last_iv_a <= iv) {
+ /// last_iv_a = iv;
+ /// global_a = lp_a;
+ /// }
+ /// \endcode
+ virtual void checkAndEmitLastprivateConditional(CodeGenFunction &CGF,
+ const Expr *LHS);
+
+ /// Gets the address of the global copy used for lastprivate conditional
+ /// update, if any.
+ /// \param PrivLVal LValue for the private copy.
+ /// \param VD Original lastprivate declaration.
+ virtual void emitLastprivateConditionalFinalUpdate(CodeGenFunction &CGF,
+ LValue PrivLVal,
+ const VarDecl *VD,
+ SourceLocation Loc);
};
/// Class supports emissionof SIMD-only code.
@@ -1891,7 +1949,7 @@ public:
/// Emit call to void __kmpc_push_proc_bind(ident_t *loc, kmp_int32
/// global_tid, int proc_bind) to generate code for 'proc_bind' clause.
void emitProcBindClause(CodeGenFunction &CGF,
- OpenMPProcBindClauseKind ProcBind,
+ llvm::omp::ProcBindKind ProcBind,
SourceLocation Loc) override;
/// Returns address of the threadprivate variable for the current
diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp
index 708260429f68..d00d84b79cfe 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp
@@ -13,14 +13,17 @@
#include "CGOpenMPRuntimeNVPTX.h"
#include "CodeGenFunction.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Cuda.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/IR/IntrinsicsNVPTX.h"
using namespace clang;
using namespace CodeGen;
+using namespace llvm::omp;
namespace {
enum OpenMPRTLFunctionNVPTX {
@@ -761,6 +764,7 @@ static bool hasNestedSPMDDirective(ASTContext &Ctx,
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:
@@ -806,6 +810,7 @@ static bool hasNestedSPMDDirective(ASTContext &Ctx,
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:
llvm_unreachable("Unexpected directive.");
@@ -835,6 +840,7 @@ static bool supportsSPMDExecutionMode(ASTContext &Ctx,
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:
@@ -880,6 +886,7 @@ static bool supportsSPMDExecutionMode(ASTContext &Ctx,
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:
break;
@@ -1002,6 +1009,7 @@ static bool hasNestedLightweightDirective(ASTContext &Ctx,
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:
@@ -1047,6 +1055,7 @@ static bool hasNestedLightweightDirective(ASTContext &Ctx,
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:
llvm_unreachable("Unexpected directive.");
@@ -1082,6 +1091,7 @@ static bool supportsLightweightRuntime(ASTContext &Ctx,
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:
@@ -1127,6 +1137,7 @@ static bool supportsLightweightRuntime(ASTContext &Ctx,
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:
break;
@@ -1799,9 +1810,8 @@ CGOpenMPRuntimeNVPTX::createNVPTXRuntimeFunction(unsigned Function) {
llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
auto *FnTy =
llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name*/ "__kmpc_barrier");
- cast<llvm::Function>(RTLFn.getCallee())
- ->addFnAttr(llvm::Attribute::Convergent);
+ RTLFn =
+ CGM.CreateConvergentRuntimeFunction(FnTy, /*Name*/ "__kmpc_barrier");
break;
}
case OMPRTL__kmpc_barrier_simple_spmd: {
@@ -1810,24 +1820,22 @@ CGOpenMPRuntimeNVPTX::createNVPTXRuntimeFunction(unsigned Function) {
llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
auto *FnTy =
llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn =
- CGM.CreateRuntimeFunction(FnTy, /*Name*/ "__kmpc_barrier_simple_spmd");
- cast<llvm::Function>(RTLFn.getCallee())
- ->addFnAttr(llvm::Attribute::Convergent);
+ RTLFn = CGM.CreateConvergentRuntimeFunction(
+ FnTy, /*Name*/ "__kmpc_barrier_simple_spmd");
break;
}
case OMPRTL_NVPTX__kmpc_warp_active_thread_mask: {
// Build int32_t __kmpc_warp_active_thread_mask(void);
auto *FnTy =
llvm::FunctionType::get(CGM.Int32Ty, llvm::None, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_warp_active_thread_mask");
+ RTLFn = CGM.CreateConvergentRuntimeFunction(FnTy, "__kmpc_warp_active_thread_mask");
break;
}
case OMPRTL_NVPTX__kmpc_syncwarp: {
// Build void __kmpc_syncwarp(kmp_int32 Mask);
auto *FnTy =
llvm::FunctionType::get(CGM.VoidTy, CGM.Int32Ty, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_syncwarp");
+ RTLFn = CGM.CreateConvergentRuntimeFunction(FnTy, "__kmpc_syncwarp");
break;
}
}
@@ -1927,7 +1935,7 @@ CGOpenMPRuntimeNVPTX::CGOpenMPRuntimeNVPTX(CodeGenModule &CGM)
}
void CGOpenMPRuntimeNVPTX::emitProcBindClause(CodeGenFunction &CGF,
- OpenMPProcBindClauseKind ProcBind,
+ ProcBindKind ProcBind,
SourceLocation Loc) {
// Do nothing in case of SPMD mode and L0 parallel.
if (getExecutionMode() == CGOpenMPRuntimeNVPTX::EM_SPMD)
@@ -2317,7 +2325,7 @@ void CGOpenMPRuntimeNVPTX::emitGenericVarsProlog(CodeGenFunction &CGF,
VarTy = Rec.second.FD->getType();
} else {
llvm::Value *Ptr = CGF.Builder.CreateInBoundsGEP(
- VarAddr.getAddress().getPointer(),
+ VarAddr.getAddress(CGF).getPointer(),
{Bld.getInt32(0), getNVPTXLaneID(CGF)});
VarTy =
Rec.second.FD->getType()->castAsArrayTypeUnsafe()->getElementType();
@@ -2325,7 +2333,7 @@ void CGOpenMPRuntimeNVPTX::emitGenericVarsProlog(CodeGenFunction &CGF,
Address(Ptr, CGM.getContext().getDeclAlign(Rec.first)), VarTy,
AlignmentSource::Decl);
}
- Rec.second.PrivateAddr = VarAddr.getAddress();
+ Rec.second.PrivateAddr = VarAddr.getAddress(CGF);
if (!IsInTTDRegion &&
(WithSPMDCheck ||
getExecutionMode() == CGOpenMPRuntimeNVPTX::EM_Unknown)) {
@@ -2336,10 +2344,10 @@ void CGOpenMPRuntimeNVPTX::emitGenericVarsProlog(CodeGenFunction &CGF,
"Secondary glob data must be one per team.");
LValue SecVarAddr = CGF.EmitLValueForField(SecBase, SecIt->second.FD);
VarAddr.setAddress(
- Address(Bld.CreateSelect(IsTTD, SecVarAddr.getPointer(),
- VarAddr.getPointer()),
+ Address(Bld.CreateSelect(IsTTD, SecVarAddr.getPointer(CGF),
+ VarAddr.getPointer(CGF)),
VarAddr.getAlignment()));
- Rec.second.PrivateAddr = VarAddr.getAddress();
+ Rec.second.PrivateAddr = VarAddr.getAddress(CGF);
}
Address GlobalPtr = Rec.second.PrivateAddr;
Address LocalAddr = CGF.CreateMemTemp(VarTy, Rec.second.FD->getName());
@@ -2351,7 +2359,8 @@ void CGOpenMPRuntimeNVPTX::emitGenericVarsProlog(CodeGenFunction &CGF,
if (EscapedParam) {
const auto *VD = cast<VarDecl>(Rec.first);
CGF.EmitStoreOfScalar(ParValue, VarAddr);
- I->getSecond().MappedParams->setVarAddr(CGF, VD, VarAddr.getAddress());
+ I->getSecond().MappedParams->setVarAddr(CGF, VD,
+ VarAddr.getAddress(CGF));
}
if (IsTTD)
++SecIt;
@@ -2385,7 +2394,7 @@ void CGOpenMPRuntimeNVPTX::emitGenericVarsProlog(CodeGenFunction &CGF,
CGM.getContext().getDeclAlign(VD),
AlignmentSource::Decl);
I->getSecond().MappedParams->setVarAddr(CGF, cast<VarDecl>(VD),
- Base.getAddress());
+ Base.getAddress(CGF));
I->getSecond().EscapedVariableLengthDeclsAddrs.emplace_back(GlobalRecValue);
}
I->getSecond().MappedParams->apply(CGF);
@@ -2646,7 +2655,7 @@ void CGOpenMPRuntimeNVPTX::emitNonSPMDParallelCall(
};
if (IfCond) {
- emitOMPIfClause(CGF, IfCond, LNParallelGen, SeqGen);
+ emitIfClause(CGF, IfCond, LNParallelGen, SeqGen);
} else {
CodeGenFunction::RunCleanupsScope Scope(CGF);
RegionCodeGenTy ThenRCG(LNParallelGen);
@@ -3689,7 +3698,8 @@ static llvm::Value *emitListToGlobalCopyFunction(
const FieldDecl *FD = VarFieldMap.lookup(VD);
LValue GlobLVal = CGF.EmitLValueForField(
CGF.MakeNaturalAlignAddrLValue(BufferArrPtr, StaticTy), FD);
- llvm::Value *BufferPtr = Bld.CreateInBoundsGEP(GlobLVal.getPointer(), Idxs);
+ llvm::Value *BufferPtr =
+ Bld.CreateInBoundsGEP(GlobLVal.getPointer(CGF), Idxs);
GlobLVal.setAddress(Address(BufferPtr, GlobLVal.getAlignment()));
switch (CGF.getEvaluationKind(Private->getType())) {
case TEK_Scalar: {
@@ -3786,7 +3796,8 @@ static llvm::Value *emitListToGlobalReduceFunction(
const FieldDecl *FD = VarFieldMap.lookup(VD);
LValue GlobLVal = CGF.EmitLValueForField(
CGF.MakeNaturalAlignAddrLValue(BufferArrPtr, StaticTy), FD);
- llvm::Value *BufferPtr = Bld.CreateInBoundsGEP(GlobLVal.getPointer(), Idxs);
+ llvm::Value *BufferPtr =
+ Bld.CreateInBoundsGEP(GlobLVal.getPointer(CGF), Idxs);
llvm::Value *Ptr = CGF.EmitCastToVoidPtr(BufferPtr);
CGF.EmitStoreOfScalar(Ptr, Elem, /*Volatile=*/false, C.VoidPtrTy);
if ((*IPriv)->getType()->isVariablyModifiedType()) {
@@ -3890,7 +3901,8 @@ static llvm::Value *emitGlobalToListCopyFunction(
const FieldDecl *FD = VarFieldMap.lookup(VD);
LValue GlobLVal = CGF.EmitLValueForField(
CGF.MakeNaturalAlignAddrLValue(BufferArrPtr, StaticTy), FD);
- llvm::Value *BufferPtr = Bld.CreateInBoundsGEP(GlobLVal.getPointer(), Idxs);
+ llvm::Value *BufferPtr =
+ Bld.CreateInBoundsGEP(GlobLVal.getPointer(CGF), Idxs);
GlobLVal.setAddress(Address(BufferPtr, GlobLVal.getAlignment()));
switch (CGF.getEvaluationKind(Private->getType())) {
case TEK_Scalar: {
@@ -3986,7 +3998,8 @@ static llvm::Value *emitGlobalToListReduceFunction(
const FieldDecl *FD = VarFieldMap.lookup(VD);
LValue GlobLVal = CGF.EmitLValueForField(
CGF.MakeNaturalAlignAddrLValue(BufferArrPtr, StaticTy), FD);
- llvm::Value *BufferPtr = Bld.CreateInBoundsGEP(GlobLVal.getPointer(), Idxs);
+ llvm::Value *BufferPtr =
+ Bld.CreateInBoundsGEP(GlobLVal.getPointer(CGF), Idxs);
llvm::Value *Ptr = CGF.EmitCastToVoidPtr(BufferPtr);
CGF.EmitStoreOfScalar(Ptr, Elem, /*Volatile=*/false, C.VoidPtrTy);
if ((*IPriv)->getType()->isVariablyModifiedType()) {
@@ -4309,7 +4322,7 @@ void CGOpenMPRuntimeNVPTX::emitReduction(
Address Elem = CGF.Builder.CreateConstArrayGEP(ReductionList, Idx);
CGF.Builder.CreateStore(
CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- CGF.EmitLValue(RHSExprs[I]).getPointer(), CGF.VoidPtrTy),
+ CGF.EmitLValue(RHSExprs[I]).getPointer(CGF), CGF.VoidPtrTy),
Elem);
if ((*IPriv)->getType()->isVariablyModifiedType()) {
// Store array size.
@@ -4891,7 +4904,7 @@ void CGOpenMPRuntimeNVPTX::adjustTargetSpecificDataForLambdas(
if (VD->getType().getCanonicalType()->isReferenceType())
VDAddr = CGF.EmitLoadOfReferenceLValue(VDAddr,
VD->getType().getCanonicalType())
- .getAddress();
+ .getAddress(CGF);
CGF.EmitStoreOfScalar(VDAddr.getPointer(), VarLVal);
}
}
@@ -4953,7 +4966,8 @@ void CGOpenMPRuntimeNVPTX::checkArchForUnifiedAddressing(
const OMPRequiresDecl *D) {
for (const OMPClause *Clause : D->clauselists()) {
if (Clause->getClauseKind() == OMPC_unified_shared_memory) {
- switch (getCudaArch(CGM)) {
+ CudaArch Arch = getCudaArch(CGM);
+ switch (Arch) {
case CudaArch::SM_20:
case CudaArch::SM_21:
case CudaArch::SM_30:
@@ -4965,10 +4979,14 @@ void CGOpenMPRuntimeNVPTX::checkArchForUnifiedAddressing(
case CudaArch::SM_53:
case CudaArch::SM_60:
case CudaArch::SM_61:
- case CudaArch::SM_62:
- CGM.Error(Clause->getBeginLoc(),
- "Target architecture does not support unified addressing");
+ case CudaArch::SM_62: {
+ SmallString<256> Buffer;
+ llvm::raw_svector_ostream Out(Buffer);
+ Out << "Target architecture " << CudaArchToString(Arch)
+ << " does not support unified addressing";
+ CGM.Error(Clause->getBeginLoc(), Out.str());
return;
+ }
case CudaArch::SM_70:
case CudaArch::SM_72:
case CudaArch::SM_75:
diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h b/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h
index 0f78627c95e6..4159af0a622f 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h
+++ b/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h
@@ -212,7 +212,7 @@ public:
/// Emit call to void __kmpc_push_proc_bind(ident_t *loc, kmp_int32
/// global_tid, int proc_bind) to generate code for 'proc_bind' clause.
virtual void emitProcBindClause(CodeGenFunction &CGF,
- OpenMPProcBindClauseKind ProcBind,
+ llvm::omp::ProcBindKind ProcBind,
SourceLocation Loc) override;
/// Emits call to void __kmpc_push_num_threads(ident_t *loc, kmp_int32
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index bb2629f89d3d..138459c68dbf 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -10,10 +10,11 @@
//
//===----------------------------------------------------------------------===//
-#include "CodeGenFunction.h"
#include "CGDebugInfo.h"
+#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "TargetInfo.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/PrettyStackTrace.h"
@@ -221,6 +222,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
case Stmt::OMPParallelForSimdDirectiveClass:
EmitOMPParallelForSimdDirective(cast<OMPParallelForSimdDirective>(*S));
break;
+ case Stmt::OMPParallelMasterDirectiveClass:
+ EmitOMPParallelMasterDirective(cast<OMPParallelMasterDirective>(*S));
+ break;
case Stmt::OMPParallelSectionsDirectiveClass:
EmitOMPParallelSectionsDirective(cast<OMPParallelSectionsDirective>(*S));
break;
@@ -292,6 +296,10 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
EmitOMPParallelMasterTaskLoopDirective(
cast<OMPParallelMasterTaskLoopDirective>(*S));
break;
+ case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:
+ EmitOMPParallelMasterTaskLoopSimdDirective(
+ cast<OMPParallelMasterTaskLoopSimdDirective>(*S));
+ break;
case Stmt::OMPDistributeDirectiveClass:
EmitOMPDistributeDirective(cast<OMPDistributeDirective>(*S));
break;
@@ -554,8 +562,7 @@ void CodeGenFunction::EmitLabel(const LabelDecl *D) {
// Emit debug info for labels.
if (CGDebugInfo *DI = getDebugInfo()) {
- if (CGM.getCodeGenOpts().getDebugInfo() >=
- codegenoptions::LimitedDebugInfo) {
+ if (CGM.getCodeGenOpts().hasReducedDebugInfo()) {
DI->setLocation(D->getLocation());
DI->EmitLabel(D, Builder);
}
@@ -1830,15 +1837,15 @@ CodeGenFunction::EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info,
Ty = llvm::IntegerType::get(getLLVMContext(), Size);
Ty = llvm::PointerType::getUnqual(Ty);
- Arg = Builder.CreateLoad(Builder.CreateBitCast(InputValue.getAddress(),
- Ty));
+ Arg = Builder.CreateLoad(
+ Builder.CreateBitCast(InputValue.getAddress(*this), Ty));
} else {
- Arg = InputValue.getPointer();
+ Arg = InputValue.getPointer(*this);
ConstraintStr += '*';
}
}
} else {
- Arg = InputValue.getPointer();
+ Arg = InputValue.getPointer(*this);
ConstraintStr += '*';
}
@@ -2087,8 +2094,8 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
LargestVectorWidth = std::max((uint64_t)LargestVectorWidth,
VT->getPrimitiveSizeInBits().getFixedSize());
} else {
- ArgTypes.push_back(Dest.getAddress().getType());
- Args.push_back(Dest.getPointer());
+ ArgTypes.push_back(Dest.getAddress(*this).getType());
+ Args.push_back(Dest.getPointer(*this));
Constraints += "=*";
Constraints += OutputConstraint;
ReadOnly = ReadNone = false;
@@ -2330,7 +2337,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// ResultTypeRequiresCast.size() elements of RegResults.
if ((i < ResultTypeRequiresCast.size()) && ResultTypeRequiresCast[i]) {
unsigned Size = getContext().getTypeSize(ResultRegQualTys[i]);
- Address A = Builder.CreateBitCast(Dest.getAddress(),
+ Address A = Builder.CreateBitCast(Dest.getAddress(*this),
ResultRegTypes[i]->getPointerTo());
QualType Ty = getContext().getIntTypeForBitwidth(Size, /*Signed*/ false);
if (Ty.isNull()) {
@@ -2383,14 +2390,14 @@ CodeGenFunction::EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K) {
delete CGF.CapturedStmtInfo;
// Emit call to the helper function.
- EmitCallOrInvoke(F, CapStruct.getPointer());
+ EmitCallOrInvoke(F, CapStruct.getPointer(*this));
return F;
}
Address CodeGenFunction::GenerateCapturedStmtArgument(const CapturedStmt &S) {
LValue CapStruct = InitCapturedStruct(S);
- return CapStruct.getAddress();
+ return CapStruct.getAddress(*this);
}
/// Creates the outlined function for a CapturedStmt.
diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index 6ece69d51daf..dc3899f0e4ea 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -15,11 +15,16 @@
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "TargetInfo.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtOpenMP.h"
-#include "clang/AST/DeclOpenMP.h"
+#include "clang/Basic/PrettyStackTrace.h"
+#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
using namespace clang;
using namespace CodeGen;
+using namespace llvm::omp;
namespace {
/// Lexical scope for OpenMP executable constructs, that handles correct codegen
@@ -76,7 +81,7 @@ public:
InlinedShareds.isGlobalVarCaptured(VD)),
VD->getType().getNonReferenceType(), VK_LValue, C.getLocation());
InlinedShareds.addPrivate(VD, [&CGF, &DRE]() -> Address {
- return CGF.EmitLValue(&DRE).getAddress();
+ return CGF.EmitLValue(&DRE).getAddress(CGF);
});
}
}
@@ -146,7 +151,8 @@ class OMPLoopScope : public CodeGenFunction::RunCleanupsScope {
const Stmt *Body =
S.getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers();
for (unsigned Cnt = 0; Cnt < S.getCollapsedNumber(); ++Cnt) {
- Body = Body->IgnoreContainers();
+ Body = OMPLoopDirective::tryToFindNextInnerLoop(
+ Body, /*TryImperfectlyNestedLoops=*/true);
if (auto *For = dyn_cast<ForStmt>(Body)) {
Body = For->getBody();
} else {
@@ -230,7 +236,7 @@ public:
VD->getType().getNonReferenceType(), VK_LValue,
C.getLocation());
InlinedShareds.addPrivate(VD, [&CGF, &DRE]() -> Address {
- return CGF.EmitLValue(&DRE).getAddress();
+ return CGF.EmitLValue(&DRE).getAddress(CGF);
});
}
}
@@ -323,7 +329,7 @@ void CodeGenFunction::GenerateOpenMPCapturedVars(
CapturedVars.push_back(CV);
} else {
assert(CurCap->capturesVariable() && "Expected capture by reference.");
- CapturedVars.push_back(EmitLValue(*I).getAddress().getPointer());
+ CapturedVars.push_back(EmitLValue(*I).getAddress(*this).getPointer());
}
}
}
@@ -334,11 +340,11 @@ static Address castValueFromUintptr(CodeGenFunction &CGF, SourceLocation Loc,
ASTContext &Ctx = CGF.getContext();
llvm::Value *CastedPtr = CGF.EmitScalarConversion(
- AddrLV.getAddress().getPointer(), Ctx.getUIntPtrType(),
+ AddrLV.getAddress(CGF).getPointer(), Ctx.getUIntPtrType(),
Ctx.getPointerType(DstType), Loc);
Address TmpAddr =
CGF.MakeNaturalAlignAddrLValue(CastedPtr, Ctx.getPointerType(DstType))
- .getAddress();
+ .getAddress(CGF);
return TmpAddr;
}
@@ -517,7 +523,7 @@ static llvm::Function *emitOutlinedFunctionPrologue(
} else if (I->capturesVariable()) {
const VarDecl *Var = I->getCapturedVar();
QualType VarTy = Var->getType();
- Address ArgAddr = ArgLVal.getAddress();
+ Address ArgAddr = ArgLVal.getAddress(CGF);
if (ArgLVal.getType()->isLValueReferenceType()) {
ArgAddr = CGF.EmitLoadOfReference(ArgLVal);
} else if (!VarTy->isVariablyModifiedType() || !VarTy->isPointerType()) {
@@ -539,12 +545,12 @@ static llvm::Function *emitOutlinedFunctionPrologue(
? castValueFromUintptr(
CGF, I->getLocation(), FD->getType(),
Args[Cnt]->getName(), ArgLVal)
- : ArgLVal.getAddress()}});
+ : ArgLVal.getAddress(CGF)}});
} else {
// If 'this' is captured, load it into CXXThisValue.
assert(I->capturesThis());
CXXThisValue = CGF.EmitLoadOfScalar(ArgLVal, I->getLocation());
- LocalAddrs.insert({Args[Cnt], {nullptr, ArgLVal.getAddress()}});
+ LocalAddrs.insert({Args[Cnt], {nullptr, ArgLVal.getAddress(CGF)}});
}
++Cnt;
++I;
@@ -561,8 +567,7 @@ CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S) {
const CapturedDecl *CD = S.getCapturedDecl();
// Build the argument list.
bool NeedWrapperFunction =
- getDebugInfo() &&
- CGM.getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo;
+ getDebugInfo() && CGM.getCodeGenOpts().hasReducedDebugInfo();
FunctionArgList Args;
llvm::MapVector<const Decl *, std::pair<const VarDecl *, Address>> LocalAddrs;
llvm::DenseMap<const Decl *, std::pair<const Expr *, llvm::Value *>> VLASizes;
@@ -828,8 +833,8 @@ bool CodeGenFunction::EmitOMPFirstprivateClause(const OMPExecutableDirective &D,
EmitAggregateAssign(Dest, OriginalLVal, Type);
} else {
EmitOMPAggregateAssign(
- Emission.getAllocatedAddress(), OriginalLVal.getAddress(),
- Type,
+ Emission.getAllocatedAddress(),
+ OriginalLVal.getAddress(*this), Type,
[this, VDInit, Init](Address DestElement,
Address SrcElement) {
// Clean up any temporaries needed by the
@@ -847,7 +852,7 @@ bool CodeGenFunction::EmitOMPFirstprivateClause(const OMPExecutableDirective &D,
return Emission.getAllocatedAddress();
});
} else {
- Address OriginalAddr = OriginalLVal.getAddress();
+ Address OriginalAddr = OriginalLVal.getAddress(*this);
IsRegistered = PrivateScope.addPrivate(
OrigVD, [this, VDInit, OriginalAddr, VD]() {
// Emit private VarDecl with copy init.
@@ -924,7 +929,7 @@ bool CodeGenFunction::EmitOMPCopyinClause(const OMPExecutableDirective &D) {
"Copyin threadprivates should have been captured!");
DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(VD), true,
(*IRef)->getType(), VK_LValue, (*IRef)->getExprLoc());
- MasterAddr = EmitLValue(&DRE).getAddress();
+ MasterAddr = EmitLValue(&DRE).getAddress(*this);
LocalDeclMap.erase(VD);
} else {
MasterAddr =
@@ -933,7 +938,7 @@ bool CodeGenFunction::EmitOMPCopyinClause(const OMPExecutableDirective &D) {
getContext().getDeclAlign(VD));
}
// Get the address of the threadprivate variable.
- Address PrivateAddr = EmitLValue(*IRef).getAddress();
+ Address PrivateAddr = EmitLValue(*IRef).getAddress(*this);
if (CopiedVars.size() == 1) {
// At first check if current thread is a master thread. If it is, no
// need to copy data.
@@ -1001,7 +1006,7 @@ bool CodeGenFunction::EmitOMPLastprivateClauseInit(
/*RefersToEnclosingVariableOrCapture=*/
CapturedStmtInfo->lookup(OrigVD) != nullptr,
(*IRef)->getType(), VK_LValue, (*IRef)->getExprLoc());
- return EmitLValue(&DRE).getAddress();
+ return EmitLValue(&DRE).getAddress(*this);
});
// Check if the variable is also a firstprivate: in this case IInit is
// not generated. Initialization of this variable will happen in codegen
@@ -1039,6 +1044,18 @@ void CodeGenFunction::EmitOMPLastprivateClauseFinal(
llvm::BasicBlock *ThenBB = nullptr;
llvm::BasicBlock *DoneBB = nullptr;
if (IsLastIterCond) {
+ // Emit implicit barrier if at least one lastprivate conditional is found
+ // and this is not a simd mode.
+ if (!getLangOpts().OpenMPSimd &&
+ llvm::any_of(D.getClausesOfKind<OMPLastprivateClause>(),
+ [](const OMPLastprivateClause *C) {
+ return C->getKind() == OMPC_LASTPRIVATE_conditional;
+ })) {
+ CGM.getOpenMPRuntime().emitBarrierCall(*this, D.getBeginLoc(),
+ OMPD_unknown,
+ /*EmitChecks=*/false,
+ /*ForceSimpleCall=*/true);
+ }
ThenBB = createBasicBlock(".omp.lastprivate.then");
DoneBB = createBasicBlock(".omp.lastprivate.done");
Builder.CreateCondBr(IsLastIterCond, ThenBB, DoneBB);
@@ -1077,14 +1094,19 @@ void CodeGenFunction::EmitOMPLastprivateClauseFinal(
cast<VarDecl>(cast<DeclRefExpr>(*ISrcRef)->getDecl());
const auto *DestVD =
cast<VarDecl>(cast<DeclRefExpr>(*IDestRef)->getDecl());
- // Get the address of the original variable.
- Address OriginalAddr = GetAddrOfLocalVar(DestVD);
// Get the address of the private variable.
Address PrivateAddr = GetAddrOfLocalVar(PrivateVD);
if (const auto *RefTy = PrivateVD->getType()->getAs<ReferenceType>())
PrivateAddr =
Address(Builder.CreateLoad(PrivateAddr),
getNaturalTypeAlignment(RefTy->getPointeeType()));
+ // Store the last value to the private copy in the last iteration.
+ if (C->getKind() == OMPC_LASTPRIVATE_conditional)
+ CGM.getOpenMPRuntime().emitLastprivateConditionalFinalUpdate(
+ *this, MakeAddrLValue(PrivateAddr, (*IRef)->getType()), PrivateVD,
+ (*IRef)->getExprLoc());
+ // Get the address of the original variable.
+ Address OriginalAddr = GetAddrOfLocalVar(DestVD);
EmitOMPCopy(Type, OriginalAddr, PrivateAddr, DestVD, SrcVD, AssignOp);
}
++IRef;
@@ -1158,8 +1180,8 @@ void CodeGenFunction::EmitOMPReductionClauseInit(
if (isaOMPArraySectionExpr && Type->isVariablyModifiedType()) {
// Store the address of the original variable associated with the LHS
// implicit variable.
- PrivateScope.addPrivate(LHSVD, [&RedCG, Count]() {
- return RedCG.getSharedLValue(Count).getAddress();
+ PrivateScope.addPrivate(LHSVD, [&RedCG, Count, this]() {
+ return RedCG.getSharedLValue(Count).getAddress(*this);
});
PrivateScope.addPrivate(
RHSVD, [this, PrivateVD]() { return GetAddrOfLocalVar(PrivateVD); });
@@ -1167,8 +1189,8 @@ void CodeGenFunction::EmitOMPReductionClauseInit(
isa<ArraySubscriptExpr>(IRef)) {
// Store the address of the original variable associated with the LHS
// implicit variable.
- PrivateScope.addPrivate(LHSVD, [&RedCG, Count]() {
- return RedCG.getSharedLValue(Count).getAddress();
+ PrivateScope.addPrivate(LHSVD, [&RedCG, Count, this]() {
+ return RedCG.getSharedLValue(Count).getAddress(*this);
});
PrivateScope.addPrivate(RHSVD, [this, PrivateVD, RHSVD]() {
return Builder.CreateElementBitCast(GetAddrOfLocalVar(PrivateVD),
@@ -1178,7 +1200,7 @@ void CodeGenFunction::EmitOMPReductionClauseInit(
} else {
QualType Type = PrivateVD->getType();
bool IsArray = getContext().getAsArrayType(Type) != nullptr;
- Address OriginalAddr = RedCG.getSharedLValue(Count).getAddress();
+ Address OriginalAddr = RedCG.getSharedLValue(Count).getAddress(*this);
// Store the address of the original variable associated with the LHS
// implicit variable.
if (IsArray) {
@@ -1313,6 +1335,87 @@ static void emitEmptyBoundParameters(CodeGenFunction &,
llvm::SmallVectorImpl<llvm::Value *> &) {}
void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
+
+ if (llvm::OpenMPIRBuilder *OMPBuilder = CGM.getOpenMPIRBuilder()) {
+ // Check if we have any if clause associated with the directive.
+ llvm::Value *IfCond = nullptr;
+ if (const auto *C = S.getSingleClause<OMPIfClause>())
+ IfCond = EmitScalarExpr(C->getCondition(),
+ /*IgnoreResultAssign=*/true);
+
+ llvm::Value *NumThreads = nullptr;
+ if (const auto *NumThreadsClause = S.getSingleClause<OMPNumThreadsClause>())
+ NumThreads = EmitScalarExpr(NumThreadsClause->getNumThreads(),
+ /*IgnoreResultAssign=*/true);
+
+ ProcBindKind ProcBind = OMP_PROC_BIND_default;
+ if (const auto *ProcBindClause = S.getSingleClause<OMPProcBindClause>())
+ ProcBind = ProcBindClause->getProcBindKind();
+
+ using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
+
+ // The cleanup callback that finalizes all variabels at the given location,
+ // thus calls destructors etc.
+ auto FiniCB = [this](InsertPointTy IP) {
+ CGBuilderTy::InsertPointGuard IPG(Builder);
+ assert(IP.getBlock()->end() != IP.getPoint() &&
+ "OpenMP IR Builder should cause terminated block!");
+ llvm::BasicBlock *IPBB = IP.getBlock();
+ llvm::BasicBlock *DestBB = IPBB->splitBasicBlock(IP.getPoint());
+ IPBB->getTerminator()->eraseFromParent();
+ Builder.SetInsertPoint(IPBB);
+ CodeGenFunction::JumpDest Dest = getJumpDestInCurrentScope(DestBB);
+ EmitBranchThroughCleanup(Dest);
+ };
+
+ // Privatization callback that performs appropriate action for
+ // shared/private/firstprivate/lastprivate/copyin/... variables.
+ //
+ // TODO: This defaults to shared right now.
+ auto PrivCB = [](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
+ llvm::Value &Val, llvm::Value *&ReplVal) {
+ // The next line is appropriate only for variables (Val) with the
+ // data-sharing attribute "shared".
+ ReplVal = &Val;
+
+ return CodeGenIP;
+ };
+
+ const CapturedStmt *CS = S.getCapturedStmt(OMPD_parallel);
+ const Stmt *ParallelRegionBodyStmt = CS->getCapturedStmt();
+
+ auto BodyGenCB = [ParallelRegionBodyStmt,
+ this](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
+ llvm::BasicBlock &ContinuationBB) {
+ auto OldAllocaIP = AllocaInsertPt;
+ AllocaInsertPt = &*AllocaIP.getPoint();
+
+ auto OldReturnBlock = ReturnBlock;
+ ReturnBlock = getJumpDestInCurrentScope(&ContinuationBB);
+
+ llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock();
+ CodeGenIPBB->splitBasicBlock(CodeGenIP.getPoint());
+ llvm::Instruction *CodeGenIPBBTI = CodeGenIPBB->getTerminator();
+ CodeGenIPBBTI->removeFromParent();
+
+ Builder.SetInsertPoint(CodeGenIPBB);
+
+ EmitStmt(ParallelRegionBodyStmt);
+
+ Builder.Insert(CodeGenIPBBTI);
+
+ AllocaInsertPt = OldAllocaIP;
+ ReturnBlock = OldReturnBlock;
+ };
+
+ CGCapturedStmtInfo CGSI(*CS, CR_OpenMP);
+ CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(*this, &CGSI);
+ Builder.restoreIP(OMPBuilder->CreateParallel(Builder, BodyGenCB, PrivCB,
+ FiniCB, IfCond, NumThreads,
+ ProcBind, S.hasCancel()));
+ return;
+ }
+
// Emit parallel region as a standalone region.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
Action.Enter(CGF);
@@ -1339,6 +1442,41 @@ void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
[](CodeGenFunction &) { return nullptr; });
}
+static void emitBody(CodeGenFunction &CGF, const Stmt *S, const Stmt *NextLoop,
+ int MaxLevel, int Level = 0) {
+ assert(Level < MaxLevel && "Too deep lookup during loop body codegen.");
+ const Stmt *SimplifiedS = S->IgnoreContainers();
+ if (const auto *CS = dyn_cast<CompoundStmt>(SimplifiedS)) {
+ PrettyStackTraceLoc CrashInfo(
+ CGF.getContext().getSourceManager(), CS->getLBracLoc(),
+ "LLVM IR generation of compound statement ('{}')");
+
+ // Keep track of the current cleanup stack depth, including debug scopes.
+ CodeGenFunction::LexicalScope Scope(CGF, S->getSourceRange());
+ for (const Stmt *CurStmt : CS->body())
+ emitBody(CGF, CurStmt, NextLoop, MaxLevel, Level);
+ return;
+ }
+ if (SimplifiedS == NextLoop) {
+ if (const auto *For = dyn_cast<ForStmt>(SimplifiedS)) {
+ S = For->getBody();
+ } else {
+ assert(isa<CXXForRangeStmt>(SimplifiedS) &&
+ "Expected canonical for loop or range-based for loop.");
+ const auto *CXXFor = cast<CXXForRangeStmt>(SimplifiedS);
+ CGF.EmitStmt(CXXFor->getLoopVarStmt());
+ S = CXXFor->getBody();
+ }
+ if (Level + 1 < MaxLevel) {
+ NextLoop = OMPLoopDirective::tryToFindNextInnerLoop(
+ S, /*TryImperfectlyNestedLoops=*/true);
+ emitBody(CGF, S, NextLoop, MaxLevel, Level + 1);
+ return;
+ }
+ }
+ CGF.EmitStmt(S);
+}
+
void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &D,
JumpDest LoopExit) {
RunCleanupsScope BodyScope(*this);
@@ -1371,20 +1509,12 @@ void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &D,
// Emit loop variables for C++ range loops.
const Stmt *Body =
D.getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers();
- for (unsigned Cnt = 0; Cnt < D.getCollapsedNumber(); ++Cnt) {
- Body = Body->IgnoreContainers();
- if (auto *For = dyn_cast<ForStmt>(Body)) {
- Body = For->getBody();
- } else {
- assert(isa<CXXForRangeStmt>(Body) &&
- "Expected canonical for loop or range-based for loop.");
- auto *CXXFor = cast<CXXForRangeStmt>(Body);
- EmitStmt(CXXFor->getLoopVarStmt());
- Body = CXXFor->getBody();
- }
- }
// Emit loop body.
- EmitStmt(D.getBody());
+ emitBody(*this, Body,
+ OMPLoopDirective::tryToFindNextInnerLoop(
+ Body, /*TryImperfectlyNestedLoops=*/true),
+ D.getCollapsedNumber());
+
// The end (updates/cleanups).
EmitBlock(Continue.getBlock());
BreakContinueStack.pop_back();
@@ -1500,7 +1630,7 @@ void CodeGenFunction::EmitOMPLinearClauseFinal(
DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(OrigVD),
CapturedStmtInfo->lookup(OrigVD) != nullptr,
(*IC)->getType(), VK_LValue, (*IC)->getExprLoc());
- Address OrigAddr = EmitLValue(&DRE).getAddress();
+ Address OrigAddr = EmitLValue(&DRE).getAddress(*this);
CodeGenFunction::OMPPrivateScope VarScope(*this);
VarScope.addPrivate(OrigVD, [OrigAddr]() { return OrigAddr; });
(void)VarScope.Privatize();
@@ -1570,7 +1700,7 @@ void CodeGenFunction::EmitOMPPrivateLoopCounters(
DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(VD),
LocalDeclMap.count(VD) || CapturedStmtInfo->lookup(VD),
E->getType(), VK_LValue, E->getExprLoc());
- return EmitLValue(&DRE).getAddress();
+ return EmitLValue(&DRE).getAddress(*this);
});
} else {
(void)LoopScope.addPrivate(PrivateVD, [&VarEmission]() {
@@ -1733,12 +1863,13 @@ void CodeGenFunction::EmitOMPSimdFinal(
}
Address OrigAddr = Address::invalid();
if (CED) {
- OrigAddr = EmitLValue(CED->getInit()->IgnoreImpCasts()).getAddress();
+ OrigAddr =
+ EmitLValue(CED->getInit()->IgnoreImpCasts()).getAddress(*this);
} else {
DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(PrivateVD),
/*RefersToEnclosingVariableOrCapture=*/false,
(*IPC)->getType(), VK_LValue, (*IPC)->getExprLoc());
- OrigAddr = EmitLValue(&DRE).getAddress();
+ OrigAddr = EmitLValue(&DRE).getAddress(*this);
}
OMPPrivateScope VarScope(*this);
VarScope.addPrivate(OrigVD, [OrigAddr]() { return OrigAddr; });
@@ -1755,6 +1886,7 @@ void CodeGenFunction::EmitOMPSimdFinal(
static void emitOMPLoopBodyWithStopPoint(CodeGenFunction &CGF,
const OMPLoopDirective &S,
CodeGenFunction::JumpDest LoopExit) {
+ CGF.CGM.getOpenMPRuntime().initLastprivateConditionalCounter(CGF, S);
CGF.EmitOMPLoopBody(S, LoopExit);
CGF.EmitStopPoint(&S);
}
@@ -1767,6 +1899,40 @@ static LValue EmitOMPHelperVar(CodeGenFunction &CGF,
return CGF.EmitLValue(Helper);
}
+static void emitCommonSimdLoop(CodeGenFunction &CGF, const OMPLoopDirective &S,
+ const RegionCodeGenTy &SimdInitGen,
+ const RegionCodeGenTy &BodyCodeGen) {
+ auto &&ThenGen = [&S, &SimdInitGen, &BodyCodeGen](CodeGenFunction &CGF,
+ PrePostActionTy &) {
+ CGOpenMPRuntime::NontemporalDeclsRAII NontemporalsRegion(CGF.CGM, S);
+ CodeGenFunction::OMPLocalDeclMapRAII Scope(CGF);
+ SimdInitGen(CGF);
+
+ BodyCodeGen(CGF);
+ };
+ auto &&ElseGen = [&BodyCodeGen](CodeGenFunction &CGF, PrePostActionTy &) {
+ CodeGenFunction::OMPLocalDeclMapRAII Scope(CGF);
+ CGF.LoopStack.setVectorizeEnable(/*Enable=*/false);
+
+ BodyCodeGen(CGF);
+ };
+ const Expr *IfCond = nullptr;
+ for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
+ if (CGF.getLangOpts().OpenMP >= 50 &&
+ (C->getNameModifier() == OMPD_unknown ||
+ C->getNameModifier() == OMPD_simd)) {
+ IfCond = C->getCondition();
+ break;
+ }
+ }
+ if (IfCond) {
+ CGF.CGM.getOpenMPRuntime().emitIfClause(CGF, IfCond, ThenGen, ElseGen);
+ } else {
+ RegionCodeGenTy ThenRCG(ThenGen);
+ ThenRCG(CGF);
+ }
+}
+
static void emitOMPSimdRegion(CodeGenFunction &CGF, const OMPLoopDirective &S,
PrePostActionTy &Action) {
Action.Enter(CGF);
@@ -1817,8 +1983,6 @@ static void emitOMPSimdRegion(CodeGenFunction &CGF, const OMPLoopDirective &S,
CGF.EmitIgnoredExpr(S.getCalcLastIteration());
}
- CGF.EmitOMPSimdInit(S);
-
emitAlignedClause(CGF, S);
(void)CGF.EmitOMPLinearClauseInit(S);
{
@@ -1827,17 +1991,29 @@ static void emitOMPSimdRegion(CodeGenFunction &CGF, const OMPLoopDirective &S,
CGF.EmitOMPLinearClause(S, LoopScope);
CGF.EmitOMPPrivateClause(S, LoopScope);
CGF.EmitOMPReductionClauseInit(S, LoopScope);
+ CGOpenMPRuntime::LastprivateConditionalRAII LPCRegion(
+ CGF, S, CGF.EmitLValue(S.getIterationVariable()));
bool HasLastprivateClause = CGF.EmitOMPLastprivateClauseInit(S, LoopScope);
(void)LoopScope.Privatize();
if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
CGF.CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(CGF, S);
- CGF.EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(),
- S.getInc(),
- [&S](CodeGenFunction &CGF) {
- CGF.EmitOMPLoopBody(S, CodeGenFunction::JumpDest());
- CGF.EmitStopPoint(&S);
- },
- [](CodeGenFunction &) {});
+
+ emitCommonSimdLoop(
+ CGF, S,
+ [&S](CodeGenFunction &CGF, PrePostActionTy &) {
+ CGF.EmitOMPSimdInit(S);
+ },
+ [&S, &LoopScope](CodeGenFunction &CGF, PrePostActionTy &) {
+ CGF.EmitOMPInnerLoop(
+ S, LoopScope.requiresCleanups(), S.getCond(), S.getInc(),
+ [&S](CodeGenFunction &CGF) {
+ CGF.CGM.getOpenMPRuntime().initLastprivateConditionalCounter(
+ CGF, S);
+ CGF.EmitOMPLoopBody(S, CodeGenFunction::JumpDest());
+ CGF.EmitStopPoint(&S);
+ },
+ [](CodeGenFunction &) {});
+ });
CGF.EmitOMPSimdFinal(S, [](CodeGenFunction &) { return nullptr; });
// Emit final copy of the lastprivate variables at the end of loops.
if (HasLastprivateClause)
@@ -1922,27 +2098,32 @@ void CodeGenFunction::EmitOMPOuterLoop(
JumpDest Continue = getJumpDestInCurrentScope("omp.dispatch.inc");
BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
- // Generate !llvm.loop.parallel metadata for loads and stores for loops
- // with dynamic/guided scheduling and without ordered clause.
- if (!isOpenMPSimdDirective(S.getDirectiveKind()))
- LoopStack.setParallel(!IsMonotonic);
- else
- EmitOMPSimdInit(S, IsMonotonic);
-
- SourceLocation Loc = S.getBeginLoc();
-
- // when 'distribute' is not combined with a 'for':
- // while (idx <= UB) { BODY; ++idx; }
- // when 'distribute' is combined with a 'for'
- // (e.g. 'distribute parallel for')
- // while (idx <= UB) { <CodeGen rest of pragma>; idx += ST; }
- EmitOMPInnerLoop(
- S, LoopScope.requiresCleanups(), LoopArgs.Cond, LoopArgs.IncExpr,
- [&S, LoopExit, &CodeGenLoop](CodeGenFunction &CGF) {
- CodeGenLoop(CGF, S, LoopExit);
+ emitCommonSimdLoop(
+ *this, S,
+ [&S, IsMonotonic](CodeGenFunction &CGF, PrePostActionTy &) {
+ // Generate !llvm.loop.parallel metadata for loads and stores for loops
+ // with dynamic/guided scheduling and without ordered clause.
+ if (!isOpenMPSimdDirective(S.getDirectiveKind()))
+ CGF.LoopStack.setParallel(!IsMonotonic);
+ else
+ CGF.EmitOMPSimdInit(S, IsMonotonic);
},
- [IVSize, IVSigned, Loc, &CodeGenOrdered](CodeGenFunction &CGF) {
- CodeGenOrdered(CGF, Loc, IVSize, IVSigned);
+ [&S, &LoopArgs, LoopExit, &CodeGenLoop, IVSize, IVSigned, &CodeGenOrdered,
+ &LoopScope](CodeGenFunction &CGF, PrePostActionTy &) {
+ SourceLocation Loc = S.getBeginLoc();
+ // when 'distribute' is not combined with a 'for':
+ // while (idx <= UB) { BODY; ++idx; }
+ // when 'distribute' is combined with a 'for'
+ // (e.g. 'distribute parallel for')
+ // while (idx <= UB) { <CodeGen rest of pragma>; idx += ST; }
+ CGF.EmitOMPInnerLoop(
+ S, LoopScope.requiresCleanups(), LoopArgs.Cond, LoopArgs.IncExpr,
+ [&S, LoopExit, &CodeGenLoop](CodeGenFunction &CGF) {
+ CodeGenLoop(CGF, S, LoopExit);
+ },
+ [IVSize, IVSigned, Loc, &CodeGenOrdered](CodeGenFunction &CGF) {
+ CodeGenOrdered(CGF, Loc, IVSize, IVSigned);
+ });
});
EmitBlock(Continue.getBlock());
@@ -2204,14 +2385,16 @@ static void emitDistributeParallelForDistributeInnerBoundParams(
const auto &Dir = cast<OMPLoopDirective>(S);
LValue LB =
CGF.EmitLValue(cast<DeclRefExpr>(Dir.getCombinedLowerBoundVariable()));
- llvm::Value *LBCast = CGF.Builder.CreateIntCast(
- CGF.Builder.CreateLoad(LB.getAddress()), CGF.SizeTy, /*isSigned=*/false);
+ llvm::Value *LBCast =
+ CGF.Builder.CreateIntCast(CGF.Builder.CreateLoad(LB.getAddress(CGF)),
+ CGF.SizeTy, /*isSigned=*/false);
CapturedVars.push_back(LBCast);
LValue UB =
CGF.EmitLValue(cast<DeclRefExpr>(Dir.getCombinedUpperBoundVariable()));
- llvm::Value *UBCast = CGF.Builder.CreateIntCast(
- CGF.Builder.CreateLoad(UB.getAddress()), CGF.SizeTy, /*isSigned=*/false);
+ llvm::Value *UBCast =
+ CGF.Builder.CreateIntCast(CGF.Builder.CreateLoad(UB.getAddress(CGF)),
+ CGF.SizeTy, /*isSigned=*/false);
CapturedVars.push_back(UBCast);
}
@@ -2384,6 +2567,8 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(
/*ForceSimpleCall=*/true);
}
EmitOMPPrivateClause(S, LoopScope);
+ CGOpenMPRuntime::LastprivateConditionalRAII LPCRegion(
+ *this, S, EmitLValue(S.getIterationVariable()));
HasLastprivateClause = EmitOMPLastprivateClauseInit(S, LoopScope);
EmitOMPReductionClauseInit(S, LoopScope);
EmitOMPPrivateLoopCounters(S, LoopScope);
@@ -2431,47 +2616,60 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(
/* Chunked */ Chunk != nullptr) ||
StaticChunkedOne) &&
!Ordered) {
- if (isOpenMPSimdDirective(S.getDirectiveKind()))
- EmitOMPSimdInit(S, /*IsMonotonic=*/true);
- // OpenMP [2.7.1, Loop Construct, Description, table 2-1]
- // When no chunk_size is specified, the iteration space is divided into
- // chunks that are approximately equal in size, and at most one chunk is
- // distributed to each thread. Note that the size of the chunks is
- // unspecified in this case.
- CGOpenMPRuntime::StaticRTInput StaticInit(
- IVSize, IVSigned, Ordered, IL.getAddress(), LB.getAddress(),
- UB.getAddress(), ST.getAddress(),
- StaticChunkedOne ? Chunk : nullptr);
- RT.emitForStaticInit(*this, S.getBeginLoc(), S.getDirectiveKind(),
- ScheduleKind, StaticInit);
JumpDest LoopExit =
getJumpDestInCurrentScope(createBasicBlock("omp.loop.exit"));
- // UB = min(UB, GlobalUB);
- if (!StaticChunkedOne)
- EmitIgnoredExpr(S.getEnsureUpperBound());
- // IV = LB;
- EmitIgnoredExpr(S.getInit());
- // For unchunked static schedule generate:
- //
- // while (idx <= UB) {
- // BODY;
- // ++idx;
- // }
- //
- // For static schedule with chunk one:
- //
- // while (IV <= PrevUB) {
- // BODY;
- // IV += ST;
- // }
- EmitOMPInnerLoop(S, LoopScope.requiresCleanups(),
- StaticChunkedOne ? S.getCombinedParForInDistCond() : S.getCond(),
- StaticChunkedOne ? S.getDistInc() : S.getInc(),
- [&S, LoopExit](CodeGenFunction &CGF) {
- CGF.EmitOMPLoopBody(S, LoopExit);
- CGF.EmitStopPoint(&S);
+ emitCommonSimdLoop(
+ *this, S,
+ [&S](CodeGenFunction &CGF, PrePostActionTy &) {
+ if (isOpenMPSimdDirective(S.getDirectiveKind()))
+ CGF.EmitOMPSimdInit(S, /*IsMonotonic=*/true);
},
- [](CodeGenFunction &) {});
+ [IVSize, IVSigned, Ordered, IL, LB, UB, ST, StaticChunkedOne, Chunk,
+ &S, ScheduleKind, LoopExit,
+ &LoopScope](CodeGenFunction &CGF, PrePostActionTy &) {
+ // OpenMP [2.7.1, Loop Construct, Description, table 2-1]
+ // When no chunk_size is specified, the iteration space is divided
+ // into chunks that are approximately equal in size, and at most
+ // one chunk is distributed to each thread. Note that the size of
+ // the chunks is unspecified in this case.
+ CGOpenMPRuntime::StaticRTInput StaticInit(
+ IVSize, IVSigned, Ordered, IL.getAddress(CGF),
+ LB.getAddress(CGF), UB.getAddress(CGF), ST.getAddress(CGF),
+ StaticChunkedOne ? Chunk : nullptr);
+ CGF.CGM.getOpenMPRuntime().emitForStaticInit(
+ CGF, S.getBeginLoc(), S.getDirectiveKind(), ScheduleKind,
+ StaticInit);
+ // UB = min(UB, GlobalUB);
+ if (!StaticChunkedOne)
+ CGF.EmitIgnoredExpr(S.getEnsureUpperBound());
+ // IV = LB;
+ CGF.EmitIgnoredExpr(S.getInit());
+ // For unchunked static schedule generate:
+ //
+ // while (idx <= UB) {
+ // BODY;
+ // ++idx;
+ // }
+ //
+ // For static schedule with chunk one:
+ //
+ // while (IV <= PrevUB) {
+ // BODY;
+ // IV += ST;
+ // }
+ CGF.EmitOMPInnerLoop(
+ S, LoopScope.requiresCleanups(),
+ StaticChunkedOne ? S.getCombinedParForInDistCond()
+ : S.getCond(),
+ StaticChunkedOne ? S.getDistInc() : S.getInc(),
+ [&S, LoopExit](CodeGenFunction &CGF) {
+ CGF.CGM.getOpenMPRuntime()
+ .initLastprivateConditionalCounter(CGF, S);
+ CGF.EmitOMPLoopBody(S, LoopExit);
+ CGF.EmitStopPoint(&S);
+ },
+ [](CodeGenFunction &) {});
+ });
EmitBlock(LoopExit.getBlock());
// Tell the runtime we are done.
auto &&CodeGen = [&S](CodeGenFunction &CGF) {
@@ -2487,9 +2685,9 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(
ScheduleKind.M2 == OMPC_SCHEDULE_MODIFIER_monotonic;
// Emit the outer loop, which requests its work chunk [LB..UB] from
// runtime and runs the inner loop to process it.
- const OMPLoopArguments LoopArguments(LB.getAddress(), UB.getAddress(),
- ST.getAddress(), IL.getAddress(),
- Chunk, EUB);
+ const OMPLoopArguments LoopArguments(
+ LB.getAddress(*this), UB.getAddress(*this), ST.getAddress(*this),
+ IL.getAddress(*this), Chunk, EUB);
EmitOMPForOuterLoop(ScheduleKind, IsMonotonic, S, LoopScope, Ordered,
LoopArguments, CGDispatchBounds);
}
@@ -2649,6 +2847,7 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) {
// break;
// }
// .omp.sections.exit:
+ CGF.CGM.getOpenMPRuntime().initLastprivateConditionalCounter(CGF, S);
llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".omp.sections.exit");
llvm::SwitchInst *SwitchStmt =
CGF.Builder.CreateSwitch(CGF.EmitLoadOfScalar(IV, S.getBeginLoc()),
@@ -2683,6 +2882,7 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) {
/*ForceSimpleCall=*/true);
}
CGF.EmitOMPPrivateClause(S, LoopScope);
+ CGOpenMPRuntime::LastprivateConditionalRAII LPCRegion(CGF, S, IV);
HasLastprivates = CGF.EmitOMPLastprivateClauseInit(S, LoopScope);
CGF.EmitOMPReductionClauseInit(S, LoopScope);
(void)LoopScope.Privatize();
@@ -2693,8 +2893,8 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) {
OpenMPScheduleTy ScheduleKind;
ScheduleKind.Schedule = OMPC_SCHEDULE_static;
CGOpenMPRuntime::StaticRTInput StaticInit(
- /*IVSize=*/32, /*IVSigned=*/true, /*Ordered=*/false, IL.getAddress(),
- LB.getAddress(), UB.getAddress(), ST.getAddress());
+ /*IVSize=*/32, /*IVSigned=*/true, /*Ordered=*/false, IL.getAddress(CGF),
+ LB.getAddress(CGF), UB.getAddress(CGF), ST.getAddress(CGF));
CGF.CGM.getOpenMPRuntime().emitForStaticInit(
CGF, S.getBeginLoc(), S.getDirectiveKind(), ScheduleKind, StaticInit);
// UB = min(UB, GlobalUB);
@@ -2809,13 +3009,17 @@ void CodeGenFunction::EmitOMPSingleDirective(const OMPSingleDirective &S) {
}
}
-void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &S) {
+static void emitMaster(CodeGenFunction &CGF, const OMPExecutableDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
Action.Enter(CGF);
CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
};
+ CGF.CGM.getOpenMPRuntime().emitMasterRegion(CGF, CodeGen, S.getBeginLoc());
+}
+
+void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &S) {
OMPLexicalScope Scope(*this, S, OMPD_unknown);
- CGM.getOpenMPRuntime().emitMasterRegion(*this, CodeGen, S.getBeginLoc());
+ emitMaster(*this, S);
}
void CodeGenFunction::EmitOMPCriticalDirective(const OMPCriticalDirective &S) {
@@ -2859,6 +3063,35 @@ void CodeGenFunction::EmitOMPParallelForSimdDirective(
emitEmptyBoundParameters);
}
+void CodeGenFunction::EmitOMPParallelMasterDirective(
+ const OMPParallelMasterDirective &S) {
+ // Emit directive as a combined directive that consists of two implicit
+ // directives: 'parallel' with 'master' directive.
+ auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
+ Action.Enter(CGF);
+ OMPPrivateScope PrivateScope(CGF);
+ bool Copyins = CGF.EmitOMPCopyinClause(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();
+ emitMaster(CGF, S);
+ CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel);
+ };
+ emitCommonOMPParallelDirective(*this, S, OMPD_master, CodeGen,
+ emitEmptyBoundParameters);
+ emitPostUpdateForReductionClause(*this, S,
+ [](CodeGenFunction &) { return nullptr; });
+}
+
void CodeGenFunction::EmitOMPParallelSectionsDirective(
const OMPParallelSectionsDirective &S) {
// Emit directive as a combined directive that consists of two implicit
@@ -3028,7 +3261,7 @@ void CodeGenFunction::EmitOMPTaskBasedDirective(
Pair.second->getType(), VK_LValue,
Pair.second->getExprLoc());
Scope.addPrivate(Pair.first, [&CGF, &DRE]() {
- return CGF.EmitLValue(&DRE).getAddress();
+ return CGF.EmitLValue(&DRE).getAddress(CGF);
});
}
for (const auto &Pair : PrivatePtrs) {
@@ -3125,7 +3358,8 @@ void CodeGenFunction::EmitOMPTaskBasedDirective(
S, *I, *PartId, *TaskT, S.getDirectiveKind(), CodeGen, Data.Tied,
Data.NumberOfParts);
OMPLexicalScope Scope(*this, S, llvm::None,
- !isOpenMPParallelDirective(S.getDirectiveKind()));
+ !isOpenMPParallelDirective(S.getDirectiveKind()) &&
+ !isOpenMPSimdDirective(S.getDirectiveKind()));
TaskGen(*this, OutlinedFn, Data);
}
@@ -3483,11 +3717,9 @@ void CodeGenFunction::EmitOMPDistributeLoop(const OMPLoopDirective &S,
if (RT.isStaticNonchunked(ScheduleKind,
/* Chunked */ Chunk != nullptr) ||
StaticChunked) {
- if (isOpenMPSimdDirective(S.getDirectiveKind()))
- EmitOMPSimdInit(S, /*IsMonotonic=*/true);
CGOpenMPRuntime::StaticRTInput StaticInit(
- IVSize, IVSigned, /* Ordered = */ false, IL.getAddress(),
- LB.getAddress(), UB.getAddress(), ST.getAddress(),
+ IVSize, IVSigned, /* Ordered = */ false, IL.getAddress(*this),
+ LB.getAddress(*this), UB.getAddress(*this), ST.getAddress(*this),
StaticChunked ? Chunk : nullptr);
RT.emitDistributeStaticInit(*this, S.getBeginLoc(), ScheduleKind,
StaticInit);
@@ -3534,18 +3766,28 @@ void CodeGenFunction::EmitOMPDistributeLoop(const OMPLoopDirective &S,
// IV = LB;
// }
//
- EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), Cond, IncExpr,
- [&S, LoopExit, &CodeGenLoop](CodeGenFunction &CGF) {
- CodeGenLoop(CGF, S, LoopExit);
- },
- [&S, StaticChunked](CodeGenFunction &CGF) {
- if (StaticChunked) {
- CGF.EmitIgnoredExpr(S.getCombinedNextLowerBound());
- CGF.EmitIgnoredExpr(S.getCombinedNextUpperBound());
- CGF.EmitIgnoredExpr(S.getCombinedEnsureUpperBound());
- CGF.EmitIgnoredExpr(S.getCombinedInit());
- }
- });
+ emitCommonSimdLoop(
+ *this, S,
+ [&S](CodeGenFunction &CGF, PrePostActionTy &) {
+ if (isOpenMPSimdDirective(S.getDirectiveKind()))
+ CGF.EmitOMPSimdInit(S, /*IsMonotonic=*/true);
+ },
+ [&S, &LoopScope, Cond, IncExpr, LoopExit, &CodeGenLoop,
+ StaticChunked](CodeGenFunction &CGF, PrePostActionTy &) {
+ CGF.EmitOMPInnerLoop(
+ S, LoopScope.requiresCleanups(), Cond, IncExpr,
+ [&S, LoopExit, &CodeGenLoop](CodeGenFunction &CGF) {
+ CodeGenLoop(CGF, S, LoopExit);
+ },
+ [&S, StaticChunked](CodeGenFunction &CGF) {
+ if (StaticChunked) {
+ CGF.EmitIgnoredExpr(S.getCombinedNextLowerBound());
+ CGF.EmitIgnoredExpr(S.getCombinedNextUpperBound());
+ CGF.EmitIgnoredExpr(S.getCombinedEnsureUpperBound());
+ CGF.EmitIgnoredExpr(S.getCombinedInit());
+ }
+ });
+ });
EmitBlock(LoopExit.getBlock());
// Tell the runtime we are done.
RT.emitForStaticFinish(*this, S.getBeginLoc(), S.getDirectiveKind());
@@ -3553,8 +3795,8 @@ void CodeGenFunction::EmitOMPDistributeLoop(const OMPLoopDirective &S,
// Emit the outer loop, which requests its work chunk [LB..UB] from
// runtime and runs the inner loop to process it.
const OMPLoopArguments LoopArguments = {
- LB.getAddress(), UB.getAddress(), ST.getAddress(), IL.getAddress(),
- Chunk};
+ LB.getAddress(*this), UB.getAddress(*this), ST.getAddress(*this),
+ IL.getAddress(*this), Chunk};
EmitOMPDistributeOuterLoop(ScheduleKind, S, LoopScope, LoopArguments,
CodeGenLoop);
}
@@ -3754,11 +3996,11 @@ static std::pair<bool, RValue> emitOMPAtomicRMW(CodeGenFunction &CGF, LValue X,
// expression is simple and atomic is allowed for the given type for the
// target platform.
if (BO == BO_Comma || !Update.isScalar() ||
- !Update.getScalarVal()->getType()->isIntegerTy() ||
- !X.isSimple() || (!isa<llvm::ConstantInt>(Update.getScalarVal()) &&
- (Update.getScalarVal()->getType() !=
- X.getAddress().getElementType())) ||
- !X.getAddress().getElementType()->isIntegerTy() ||
+ !Update.getScalarVal()->getType()->isIntegerTy() || !X.isSimple() ||
+ (!isa<llvm::ConstantInt>(Update.getScalarVal()) &&
+ (Update.getScalarVal()->getType() !=
+ X.getAddress(CGF).getElementType())) ||
+ !X.getAddress(CGF).getElementType()->isIntegerTy() ||
!Context.getTargetInfo().hasBuiltinAtomic(
Context.getTypeSize(X.getType()), Context.toBits(X.getAlignment())))
return std::make_pair(false, RValue::get(nullptr));
@@ -3830,11 +4072,11 @@ static std::pair<bool, RValue> emitOMPAtomicRMW(CodeGenFunction &CGF, LValue X,
llvm::Value *UpdateVal = Update.getScalarVal();
if (auto *IC = dyn_cast<llvm::ConstantInt>(UpdateVal)) {
UpdateVal = CGF.Builder.CreateIntCast(
- IC, X.getAddress().getElementType(),
+ IC, X.getAddress(CGF).getElementType(),
X.getType()->hasSignedIntegerRepresentation());
}
llvm::Value *Res =
- CGF.Builder.CreateAtomicRMW(RMWOp, X.getPointer(), UpdateVal, AO);
+ CGF.Builder.CreateAtomicRMW(RMWOp, X.getPointer(CGF), UpdateVal, AO);
return std::make_pair(true, RValue::get(Res));
}
@@ -4074,6 +4316,7 @@ static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
case OMPC_atomic_default_mem_order:
case OMPC_device_type:
case OMPC_match:
+ case OMPC_nontemporal:
llvm_unreachable("Clause is not allowed in 'omp atomic'.");
}
}
@@ -4489,7 +4732,8 @@ void CodeGenFunction::EmitOMPTeamsDistributeParallelForSimdDirective(
CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false);
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
};
- emitCommonOMPTeamsDirective(*this, S, OMPD_distribute_parallel_for, CodeGen);
+ emitCommonOMPTeamsDirective(*this, S, OMPD_distribute_parallel_for_simd,
+ CodeGen);
emitPostUpdateForReductionClause(*this, S,
[](CodeGenFunction &) { return nullptr; });
}
@@ -4612,6 +4856,19 @@ void CodeGenFunction::EmitOMPCancelDirective(const OMPCancelDirective &S) {
break;
}
}
+ if (llvm::OpenMPIRBuilder *OMPBuilder = CGM.getOpenMPIRBuilder()) {
+ // TODO: This check is necessary as we only generate `omp parallel` through
+ // the OpenMPIRBuilder for now.
+ if (S.getCancelRegion() == OMPD_parallel) {
+ llvm::Value *IfCondition = nullptr;
+ if (IfCond)
+ IfCondition = EmitScalarExpr(IfCond,
+ /*IgnoreResultAssign=*/true);
+ return Builder.restoreIP(
+ OMPBuilder->CreateCancel(Builder, IfCondition, S.getCancelRegion()));
+ }
+ }
+
CGM.getOpenMPRuntime().emitCancelCall(*this, S.getBeginLoc(), IfCond,
S.getCancelRegion());
}
@@ -5017,8 +5274,7 @@ void CodeGenFunction::EmitOMPTaskLoopBasedDirective(const OMPLoopDirective &S) {
CGF.incrementProfileCounter(&S);
}
- if (isOpenMPSimdDirective(S.getDirectiveKind()))
- CGF.EmitOMPSimdInit(S);
+ (void)CGF.EmitOMPLinearClauseInit(S);
OMPPrivateScope LoopScope(CGF);
// Emit helper vars inits.
@@ -5036,6 +5292,7 @@ void CodeGenFunction::EmitOMPTaskLoopBasedDirective(const OMPLoopDirective &S) {
mapParam(CGF, cast<DeclRefExpr>(S.getIsLastIterVariable()), *LIP,
LoopScope);
CGF.EmitOMPPrivateLoopCounters(S, LoopScope);
+ CGF.EmitOMPLinearClause(S, LoopScope);
bool HasLastprivateClause = CGF.EmitOMPLastprivateClauseInit(S, LoopScope);
(void)LoopScope.Privatize();
// Emit the loop iteration variable.
@@ -5053,13 +5310,24 @@ void CodeGenFunction::EmitOMPTaskLoopBasedDirective(const OMPLoopDirective &S) {
CGF.EmitIgnoredExpr(S.getCalcLastIteration());
}
- CGF.EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(),
- S.getInc(),
- [&S](CodeGenFunction &CGF) {
- CGF.EmitOMPLoopBody(S, JumpDest());
- CGF.EmitStopPoint(&S);
- },
- [](CodeGenFunction &) {});
+ {
+ OMPLexicalScope Scope(CGF, S, OMPD_taskloop, /*EmitPreInitStmt=*/false);
+ emitCommonSimdLoop(
+ CGF, S,
+ [&S](CodeGenFunction &CGF, PrePostActionTy &) {
+ if (isOpenMPSimdDirective(S.getDirectiveKind()))
+ CGF.EmitOMPSimdInit(S);
+ },
+ [&S, &LoopScope](CodeGenFunction &CGF, PrePostActionTy &) {
+ CGF.EmitOMPInnerLoop(
+ S, LoopScope.requiresCleanups(), S.getCond(), S.getInc(),
+ [&S](CodeGenFunction &CGF) {
+ CGF.EmitOMPLoopBody(S, CodeGenFunction::JumpDest());
+ CGF.EmitStopPoint(&S);
+ },
+ [](CodeGenFunction &) {});
+ });
+ }
// Emit: if (PreCond) - end.
if (ContBlock) {
CGF.EmitBranch(ContBlock);
@@ -5073,6 +5341,11 @@ void CodeGenFunction::EmitOMPTaskLoopBasedDirective(const OMPLoopDirective &S) {
CGF.GetAddrOfLocalVar(*LIP), /*Volatile=*/false,
(*LIP)->getType(), S.getBeginLoc())));
}
+ CGF.EmitOMPLinearClauseFinal(S, [LIP, &S](CodeGenFunction &CGF) {
+ return CGF.Builder.CreateIsNotNull(
+ CGF.EmitLoadOfScalar(CGF.GetAddrOfLocalVar(*LIP), /*Volatile=*/false,
+ (*LIP)->getType(), S.getBeginLoc()));
+ });
};
auto &&TaskGen = [&S, SharedsTy, CapturedStruct,
IfCond](CodeGenFunction &CGF, llvm::Function *OutlinedFn,
@@ -5108,6 +5381,7 @@ void CodeGenFunction::EmitOMPTaskLoopDirective(const OMPTaskLoopDirective &S) {
void CodeGenFunction::EmitOMPTaskLoopSimdDirective(
const OMPTaskLoopSimdDirective &S) {
+ OMPLexicalScope Scope(*this, S);
EmitOMPTaskLoopBasedDirective(S);
}
@@ -5127,7 +5401,7 @@ void CodeGenFunction::EmitOMPMasterTaskLoopSimdDirective(
Action.Enter(CGF);
EmitOMPTaskLoopBasedDirective(S);
};
- OMPLexicalScope Scope(*this, S, llvm::None, /*EmitPreInitStmt=*/false);
+ OMPLexicalScope Scope(*this, S);
CGM.getOpenMPRuntime().emitMasterRegion(*this, CodeGen, S.getBeginLoc());
}
@@ -5147,6 +5421,22 @@ void CodeGenFunction::EmitOMPParallelMasterTaskLoopDirective(
emitEmptyBoundParameters);
}
+void CodeGenFunction::EmitOMPParallelMasterTaskLoopSimdDirective(
+ const OMPParallelMasterTaskLoopSimdDirective &S) {
+ auto &&CodeGen = [this, &S](CodeGenFunction &CGF, PrePostActionTy &Action) {
+ auto &&TaskLoopCodeGen = [&S](CodeGenFunction &CGF,
+ PrePostActionTy &Action) {
+ Action.Enter(CGF);
+ CGF.EmitOMPTaskLoopBasedDirective(S);
+ };
+ OMPLexicalScope Scope(CGF, S, OMPD_parallel, /*EmitPreInitStmt=*/false);
+ CGM.getOpenMPRuntime().emitMasterRegion(CGF, TaskLoopCodeGen,
+ S.getBeginLoc());
+ };
+ emitCommonOMPParallelDirective(*this, S, OMPD_master_taskloop_simd, CodeGen,
+ emitEmptyBoundParameters);
+}
+
// Generate the instructions for '#pragma omp target update' directive.
void CodeGenFunction::EmitOMPTargetUpdateDirective(
const OMPTargetUpdateDirective &S) {
@@ -5180,11 +5470,11 @@ void CodeGenFunction::EmitSimpleOMPExecutableDirective(
OMPPrivateScope LoopGlobals(CGF);
if (const auto *LD = dyn_cast<OMPLoopDirective>(&D)) {
for (const Expr *E : LD->counters()) {
- const auto *VD = dyn_cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
+ const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
if (!VD->hasLocalStorage() && !CGF.LocalDeclMap.count(VD)) {
LValue GlobLVal = CGF.EmitLValue(E);
LoopGlobals.addPrivate(
- VD, [&GlobLVal]() { return GlobLVal.getAddress(); });
+ VD, [&GlobLVal, &CGF]() { return GlobLVal.getAddress(CGF); });
}
if (isa<OMPCapturedExprDecl>(VD)) {
// Emit only those that were not explicitly referenced in clauses.
diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp
index f9f25e7e57ad..59631e802373 100644
--- a/clang/lib/CodeGen/CGVTables.cpp
+++ b/clang/lib/CodeGen/CGVTables.cpp
@@ -13,6 +13,7 @@
#include "CGCXXABI.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/CodeGenOptions.h"
@@ -335,7 +336,7 @@ void CodeGenFunction::EmitCallAndReturnForThunk(llvm::FunctionCallee Callee,
for (const ParmVarDecl *PD : MD->parameters())
EmitDelegateCallArg(CallArgs, PD, SourceLocation());
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
#ifndef NDEBUG
const CGFunctionInfo &CallFnInfo = CGM.getTypes().arrangeCXXMethodCall(
@@ -675,7 +676,12 @@ void CodeGenVTables::addVTableComponent(
// Method is acceptable, continue processing as usual.
}
- auto getSpecialVirtualFn = [&](StringRef name) {
+ auto getSpecialVirtualFn = [&](StringRef name) -> llvm::Constant * {
+ // For NVPTX devices in OpenMP emit special functon as null pointers,
+ // otherwise linking ends up with unresolved references.
+ if (CGM.getLangOpts().OpenMP && CGM.getLangOpts().OpenMPIsDevice &&
+ CGM.getTriple().isNVPTX())
+ return llvm::ConstantPointerNull::get(CGM.Int8PtrTy);
llvm::FunctionType *fnTy =
llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
llvm::Constant *fn = cast<llvm::Constant>(
diff --git a/clang/lib/CodeGen/CGValue.h b/clang/lib/CodeGen/CGValue.h
index 71f95abe488a..9fd07bdb187d 100644
--- a/clang/lib/CodeGen/CGValue.h
+++ b/clang/lib/CodeGen/CGValue.h
@@ -29,6 +29,7 @@ namespace llvm {
namespace clang {
namespace CodeGen {
class AggValueSlot;
+ class CodeGenFunction;
struct CGBitFieldInfo;
/// RValue - This trivial value class is used to represent the result of an
@@ -319,11 +320,13 @@ public:
void setBaseInfo(LValueBaseInfo Info) { BaseInfo = Info; }
// simple lvalue
- llvm::Value *getPointer() const {
+ llvm::Value *getPointer(CodeGenFunction &CGF) const {
assert(isSimple());
return V;
}
- Address getAddress() const { return Address(getPointer(), getAlignment()); }
+ Address getAddress(CodeGenFunction &CGF) const {
+ return Address(getPointer(CGF), getAlignment());
+ }
void setAddress(Address address) {
assert(isSimple());
V = address.getPointer();
@@ -427,8 +430,8 @@ public:
return R;
}
- RValue asAggregateRValue() const {
- return RValue::getAggregate(getAddress(), isVolatileQualified());
+ RValue asAggregateRValue(CodeGenFunction &CGF) const {
+ return RValue::getAggregate(getAddress(CGF), isVolatileQualified());
}
};
@@ -536,14 +539,12 @@ public:
return AV;
}
- static AggValueSlot forLValue(const LValue &LV,
- IsDestructed_t isDestructed,
- NeedsGCBarriers_t needsGC,
- IsAliased_t isAliased,
- Overlap_t mayOverlap,
- IsZeroed_t isZeroed = IsNotZeroed,
- IsSanitizerChecked_t isChecked = IsNotSanitizerChecked) {
- return forAddr(LV.getAddress(), LV.getQuals(), isDestructed, needsGC,
+ static AggValueSlot
+ forLValue(const LValue &LV, CodeGenFunction &CGF, IsDestructed_t isDestructed,
+ NeedsGCBarriers_t needsGC, IsAliased_t isAliased,
+ Overlap_t mayOverlap, IsZeroed_t isZeroed = IsNotZeroed,
+ IsSanitizerChecked_t isChecked = IsNotSanitizerChecked) {
+ return forAddr(LV.getAddress(CGF), LV.getQuals(), isDestructed, needsGC,
isAliased, mayOverlap, isZeroed, isChecked);
}
diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp
index 87bda4a0fc2c..7065e78f19a2 100644
--- a/clang/lib/CodeGen/CodeGenAction.cpp
+++ b/clang/lib/CodeGen/CodeGenAction.cpp
@@ -82,6 +82,24 @@ namespace clang {
BackendConsumer *BackendCon;
};
+ static void reportOptRecordError(Error E, DiagnosticsEngine &Diags,
+ const CodeGenOptions CodeGenOpts) {
+ handleAllErrors(
+ std::move(E),
+ [&](const RemarkSetupFileError &E) {
+ Diags.Report(diag::err_cannot_open_file)
+ << CodeGenOpts.OptRecordFile << E.message();
+ },
+ [&](const RemarkSetupPatternError &E) {
+ Diags.Report(diag::err_drv_optimization_remark_pattern)
+ << E.message() << CodeGenOpts.OptRecordPasses;
+ },
+ [&](const RemarkSetupFormatError &E) {
+ Diags.Report(diag::err_drv_optimization_remark_format)
+ << CodeGenOpts.OptRecordFormat;
+ });
+ }
+
class BackendConsumer : public ASTConsumer {
using LinkModule = CodeGenAction::LinkModule;
@@ -133,6 +151,29 @@ namespace clang {
FrontendTimesIsEnabled = TimePasses;
llvm::TimePassesIsEnabled = TimePasses;
}
+
+ // This constructor is used in installing an empty BackendConsumer
+ // to use the clang diagnostic handler for IR input files. It avoids
+ // initializing the OS field.
+ BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags,
+ const HeaderSearchOptions &HeaderSearchOpts,
+ const PreprocessorOptions &PPOpts,
+ const CodeGenOptions &CodeGenOpts,
+ const TargetOptions &TargetOpts,
+ const LangOptions &LangOpts, bool TimePasses,
+ SmallVector<LinkModule, 4> LinkModules, LLVMContext &C,
+ CoverageSourceInfo *CoverageInfo = nullptr)
+ : Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts),
+ CodeGenOpts(CodeGenOpts), TargetOpts(TargetOpts), LangOpts(LangOpts),
+ Context(nullptr),
+ LLVMIRGeneration("irgen", "LLVM IR Generation Time"),
+ LLVMIRGenerationRefCount(0),
+ Gen(CreateLLVMCodeGen(Diags, "", HeaderSearchOpts, PPOpts,
+ CodeGenOpts, C, CoverageInfo)),
+ LinkModules(std::move(LinkModules)) {
+ FrontendTimesIsEnabled = TimePasses;
+ llvm::TimePassesIsEnabled = TimePasses;
+ }
llvm::Module *getModule() const { return Gen->GetModule(); }
std::unique_ptr<llvm::Module> takeModule() {
return std::unique_ptr<llvm::Module>(Gen->ReleaseModule());
@@ -231,7 +272,7 @@ namespace clang {
void HandleTranslationUnit(ASTContext &C) override {
{
- llvm::TimeTraceScope TimeScope("Frontend", StringRef(""));
+ llvm::TimeTraceScope TimeScope("Frontend");
PrettyStackTraceString CrashInfo("Per-file LLVM IR generation");
if (FrontendTimesIsEnabled) {
LLVMIRGenerationRefCount += 1;
@@ -268,29 +309,16 @@ namespace clang {
CodeGenOpts, this));
Expected<std::unique_ptr<llvm::ToolOutputFile>> OptRecordFileOrErr =
- setupOptimizationRemarks(Ctx, CodeGenOpts.OptRecordFile,
- CodeGenOpts.OptRecordPasses,
- CodeGenOpts.OptRecordFormat,
- CodeGenOpts.DiagnosticsWithHotness,
- CodeGenOpts.DiagnosticsHotnessThreshold);
+ setupOptimizationRemarks(
+ Ctx, CodeGenOpts.OptRecordFile, CodeGenOpts.OptRecordPasses,
+ CodeGenOpts.OptRecordFormat, CodeGenOpts.DiagnosticsWithHotness,
+ CodeGenOpts.DiagnosticsHotnessThreshold);
if (Error E = OptRecordFileOrErr.takeError()) {
- handleAllErrors(
- std::move(E),
- [&](const RemarkSetupFileError &E) {
- Diags.Report(diag::err_cannot_open_file)
- << CodeGenOpts.OptRecordFile << E.message();
- },
- [&](const RemarkSetupPatternError &E) {
- Diags.Report(diag::err_drv_optimization_remark_pattern)
- << E.message() << CodeGenOpts.OptRecordPasses;
- },
- [&](const RemarkSetupFormatError &E) {
- Diags.Report(diag::err_drv_optimization_remark_format)
- << CodeGenOpts.OptRecordFormat;
- });
+ reportOptRecordError(std::move(E), Diags, CodeGenOpts);
return;
}
+
std::unique_ptr<llvm::ToolOutputFile> OptRecordFile =
std::move(*OptRecordFileOrErr);
@@ -331,6 +359,10 @@ namespace clang {
Gen->CompleteTentativeDefinition(D);
}
+ void CompleteExternalDeclaration(VarDecl *D) override {
+ Gen->CompleteExternalDeclaration(D);
+ }
+
void AssignInheritanceModel(CXXRecordDecl *RD) override {
Gen->AssignInheritanceModel(RD);
}
@@ -607,10 +639,20 @@ void BackendConsumer::UnsupportedDiagHandler(
StringRef Filename;
unsigned Line, Column;
bool BadDebugInfo = false;
- FullSourceLoc Loc =
- getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column);
+ FullSourceLoc Loc;
+ std::string Msg;
+ raw_string_ostream MsgStream(Msg);
- Diags.Report(Loc, diag::err_fe_backend_unsupported) << D.getMessage().str();
+ // Context will be nullptr for IR input files, we will construct the diag
+ // message from llvm::DiagnosticInfoUnsupported.
+ if (Context != nullptr) {
+ Loc = getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column);
+ MsgStream << D.getMessage();
+ } else {
+ DiagnosticPrinterRawOStream DP(MsgStream);
+ D.print(DP);
+ }
+ Diags.Report(Loc, diag::err_fe_backend_unsupported) << MsgStream.str();
if (BadDebugInfo)
// If we were not able to translate the file:line:col information
@@ -626,10 +668,21 @@ void BackendConsumer::MisExpectDiagHandler(
StringRef Filename;
unsigned Line, Column;
bool BadDebugInfo = false;
- FullSourceLoc Loc =
- getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column);
+ FullSourceLoc Loc;
+ std::string Msg;
+ raw_string_ostream MsgStream(Msg);
+ DiagnosticPrinterRawOStream DP(MsgStream);
- Diags.Report(Loc, diag::warn_profile_data_misexpect) << D.getMsg().str();
+ // Context will be nullptr for IR input files, we will construct the diag
+ // message from llvm::DiagnosticInfoMisExpect.
+ if (Context != nullptr) {
+ Loc = getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column);
+ MsgStream << D.getMsg();
+ } else {
+ DiagnosticPrinterRawOStream DP(MsgStream);
+ D.print(DP);
+ }
+ Diags.Report(Loc, diag::warn_profile_data_misexpect) << MsgStream.str();
if (BadDebugInfo)
// If we were not able to translate the file:line:col information
@@ -649,12 +702,19 @@ void BackendConsumer::EmitOptimizationMessage(
StringRef Filename;
unsigned Line, Column;
bool BadDebugInfo = false;
- FullSourceLoc Loc =
- getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column);
-
+ FullSourceLoc Loc;
std::string Msg;
raw_string_ostream MsgStream(Msg);
- MsgStream << D.getMsg();
+
+ // Context will be nullptr for IR input files, we will construct the remark
+ // message from llvm::DiagnosticInfoOptimizationBase.
+ if (Context != nullptr) {
+ Loc = getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column);
+ MsgStream << D.getMsg();
+ } else {
+ DiagnosticPrinterRawOStream DP(MsgStream);
+ D.print(DP);
+ }
if (D.getHotness())
MsgStream << " (hotness: " << *D.getHotness() << ")";
@@ -1046,6 +1106,8 @@ void CodeGenAction::ExecuteAction() {
if (getCurrentFileKind().getLanguage() == Language::LLVM_IR) {
BackendAction BA = static_cast<BackendAction>(Act);
CompilerInstance &CI = getCompilerInstance();
+ auto &CodeGenOpts = CI.getCodeGenOpts();
+ auto &Diagnostics = CI.getDiagnostics();
std::unique_ptr<raw_pwrite_stream> OS =
GetOutputStream(CI, getCurrentFile(), BA);
if (BA != Backend_EmitNothing && !OS)
@@ -1064,23 +1126,49 @@ void CodeGenAction::ExecuteAction() {
const TargetOptions &TargetOpts = CI.getTargetOpts();
if (TheModule->getTargetTriple() != TargetOpts.Triple) {
- CI.getDiagnostics().Report(SourceLocation(),
- diag::warn_fe_override_module)
+ Diagnostics.Report(SourceLocation(),
+ diag::warn_fe_override_module)
<< TargetOpts.Triple;
TheModule->setTargetTriple(TargetOpts.Triple);
}
- EmbedBitcode(TheModule.get(), CI.getCodeGenOpts(),
+ EmbedBitcode(TheModule.get(), CodeGenOpts,
MainFile->getMemBufferRef());
LLVMContext &Ctx = TheModule->getContext();
Ctx.setInlineAsmDiagnosticHandler(BitcodeInlineAsmDiagHandler,
- &CI.getDiagnostics());
+ &Diagnostics);
+
+ // Set clang diagnostic handler. To do this we need to create a fake
+ // BackendConsumer.
+ BackendConsumer Result(BA, CI.getDiagnostics(), CI.getHeaderSearchOpts(),
+ CI.getPreprocessorOpts(), CI.getCodeGenOpts(),
+ CI.getTargetOpts(), CI.getLangOpts(),
+ CI.getFrontendOpts().ShowTimers,
+ std::move(LinkModules), *VMContext, nullptr);
+ Ctx.setDiagnosticHandler(
+ std::make_unique<ClangDiagnosticHandler>(CodeGenOpts, &Result));
- EmitBackendOutput(CI.getDiagnostics(), CI.getHeaderSearchOpts(),
- CI.getCodeGenOpts(), TargetOpts, CI.getLangOpts(),
+ Expected<std::unique_ptr<llvm::ToolOutputFile>> OptRecordFileOrErr =
+ setupOptimizationRemarks(
+ Ctx, CodeGenOpts.OptRecordFile, CodeGenOpts.OptRecordPasses,
+ CodeGenOpts.OptRecordFormat, CodeGenOpts.DiagnosticsWithHotness,
+ CodeGenOpts.DiagnosticsHotnessThreshold);
+
+ if (Error E = OptRecordFileOrErr.takeError()) {
+ reportOptRecordError(std::move(E), Diagnostics, CodeGenOpts);
+ return;
+ }
+ std::unique_ptr<llvm::ToolOutputFile> OptRecordFile =
+ std::move(*OptRecordFileOrErr);
+
+ EmitBackendOutput(Diagnostics, CI.getHeaderSearchOpts(), CodeGenOpts,
+ TargetOpts, CI.getLangOpts(),
CI.getTarget().getDataLayout(), TheModule.get(), BA,
std::move(OS));
+
+ if (OptRecordFile)
+ OptRecordFile->keep();
return;
}
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 3f9a52ab7638..2bf94f697e01 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -12,9 +12,9 @@
#include "CodeGenFunction.h"
#include "CGBlocks.h"
-#include "CGCleanup.h"
#include "CGCUDARuntime.h"
#include "CGCXXABI.h"
+#include "CGCleanup.h"
#include "CGDebugInfo.h"
#include "CGOpenMPRuntime.h"
#include "CodeGenModule.h"
@@ -22,6 +22,7 @@
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTLambda.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtCXX.h"
@@ -33,6 +34,8 @@
#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Dominators.h"
+#include "llvm/IR/FPEnv.h"
+#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Operator.h"
@@ -87,6 +90,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
FMF.setAllowReassoc();
}
Builder.setFastMathFlags(FMF);
+ SetFPModel();
}
CodeGenFunction::~CodeGenFunction() {
@@ -102,6 +106,51 @@ CodeGenFunction::~CodeGenFunction() {
CGM.getOpenMPRuntime().functionFinished(*this);
}
+// Map the LangOption for rounding mode into
+// the corresponding enum in the IR.
+static llvm::fp::RoundingMode ToConstrainedRoundingMD(
+ LangOptions::FPRoundingModeKind Kind) {
+
+ switch (Kind) {
+ case LangOptions::FPR_ToNearest: return llvm::fp::rmToNearest;
+ case LangOptions::FPR_Downward: return llvm::fp::rmDownward;
+ case LangOptions::FPR_Upward: return llvm::fp::rmUpward;
+ case LangOptions::FPR_TowardZero: return llvm::fp::rmTowardZero;
+ case LangOptions::FPR_Dynamic: return llvm::fp::rmDynamic;
+ }
+ llvm_unreachable("Unsupported FP RoundingMode");
+}
+
+// Map the LangOption for exception behavior into
+// the corresponding enum in the IR.
+static llvm::fp::ExceptionBehavior ToConstrainedExceptMD(
+ LangOptions::FPExceptionModeKind Kind) {
+
+ switch (Kind) {
+ case LangOptions::FPE_Ignore: return llvm::fp::ebIgnore;
+ case LangOptions::FPE_MayTrap: return llvm::fp::ebMayTrap;
+ case LangOptions::FPE_Strict: return llvm::fp::ebStrict;
+ }
+ llvm_unreachable("Unsupported FP Exception Behavior");
+}
+
+void CodeGenFunction::SetFPModel() {
+ auto fpRoundingMode = ToConstrainedRoundingMD(
+ getLangOpts().getFPRoundingMode());
+ auto fpExceptionBehavior = ToConstrainedExceptMD(
+ getLangOpts().getFPExceptionMode());
+
+ if (fpExceptionBehavior == llvm::fp::ebIgnore &&
+ fpRoundingMode == llvm::fp::rmToNearest)
+ // Constrained intrinsics are not used.
+ ;
+ else {
+ Builder.setIsFPConstrained(true);
+ Builder.setDefaultConstrainedRounding(fpRoundingMode);
+ Builder.setDefaultConstrainedExcept(fpExceptionBehavior);
+ }
+}
+
CharUnits CodeGenFunction::getNaturalPointeeTypeAlignment(QualType T,
LValueBaseInfo *BaseInfo,
TBAAAccessInfo *TBAAInfo) {
@@ -329,9 +378,15 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
if (HasCleanups) {
// Make sure the line table doesn't jump back into the body for
// the ret after it's been at EndLoc.
- if (CGDebugInfo *DI = getDebugInfo())
+ 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);
+ }
PopCleanupBlocks(PrologueCleanupDepth);
}
@@ -606,6 +661,13 @@ void CodeGenFunction::markAsIgnoreThreadCheckingAtRuntime(llvm::Function *Fn) {
}
}
+/// Check if the return value of this function requires sanitization.
+bool CodeGenFunction::requiresReturnValueCheck() const {
+ return requiresReturnValueNullabilityCheck() ||
+ (SanOpts.has(SanitizerKind::ReturnsNonnullAttribute) && CurCodeDecl &&
+ CurCodeDecl->getAttr<ReturnsNonNullAttr>());
+}
+
static bool matchesStlAllocatorFn(const Decl *D, const ASTContext &Ctx) {
auto *MD = dyn_cast_or_null<CXXMethodDecl>(D);
if (!MD || !MD->getDeclName().getAsIdentifierInfo() ||
@@ -635,8 +697,7 @@ static llvm::Constant *getPrologueSignature(CodeGenModule &CGM,
return CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM);
}
-void CodeGenFunction::StartFunction(GlobalDecl GD,
- QualType RetTy,
+void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
llvm::Function *Fn,
const CGFunctionInfo &FnInfo,
const FunctionArgList &Args,
@@ -738,8 +799,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
FD->getBody()->getStmtClass() == Stmt::CoroutineBodyStmtClass)
SanOpts.Mask &= ~SanitizerKind::Null;
- // Apply xray attributes to the function (as a string, for now)
if (D) {
+ // Apply xray attributes to the function (as a string, for now)
if (const auto *XRayAttr = D->getAttr<XRayInstrumentAttr>()) {
if (CGM.getCodeGenOpts().XRayInstrumentationBundle.has(
XRayInstrKind::Function)) {
@@ -758,12 +819,25 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
"xray-instruction-threshold",
llvm::itostr(CGM.getCodeGenOpts().XRayInstructionThreshold));
}
+
+ if (const auto *Attr = D->getAttr<PatchableFunctionEntryAttr>()) {
+ // Attr->getStart is currently ignored.
+ Fn->addFnAttr("patchable-function-entry",
+ std::to_string(Attr->getCount()));
+ } else if (unsigned Count = CGM.getCodeGenOpts().PatchableFunctionEntryCount) {
+ Fn->addFnAttr("patchable-function-entry",
+ std::to_string(Count));
+ }
}
// Add no-jump-tables value.
Fn->addFnAttr("no-jump-tables",
llvm::toStringRef(CGM.getCodeGenOpts().NoUseJumpTables));
+ // Add no-inline-line-tables value.
+ if (CGM.getCodeGenOpts().NoInlineLineTables)
+ Fn->addFnAttr("no-inline-line-tables");
+
// Add profile-sample-accurate value.
if (CGM.getCodeGenOpts().ProfileSampleAccurate)
Fn->addFnAttr("profile-sample-accurate");
@@ -820,6 +894,10 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
if (FD->isMain())
Fn->addFnAttr(llvm::Attribute::NoRecurse);
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
+ if (FD->usesFPIntrin())
+ Fn->addFnAttr(llvm::Attribute::StrictFP);
+
// If a custom alignment is used, force realigning to this alignment on
// any main function which certainly will need it.
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
@@ -889,9 +967,30 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
Fn->addFnAttr("instrument-function-entry-inlined",
getTarget().getMCountName());
}
+ if (CGM.getCodeGenOpts().MNopMCount) {
+ if (!CGM.getCodeGenOpts().CallFEntry)
+ CGM.getDiags().Report(diag::err_opt_not_valid_without_opt)
+ << "-mnop-mcount" << "-mfentry";
+ Fn->addFnAttr("mnop-mcount");
+ }
+
+ if (CGM.getCodeGenOpts().RecordMCount) {
+ if (!CGM.getCodeGenOpts().CallFEntry)
+ CGM.getDiags().Report(diag::err_opt_not_valid_without_opt)
+ << "-mrecord-mcount" << "-mfentry";
+ Fn->addFnAttr("mrecord-mcount");
+ }
}
}
+ if (CGM.getCodeGenOpts().PackedStack) {
+ if (getContext().getTargetInfo().getTriple().getArch() !=
+ llvm::Triple::systemz)
+ CGM.getDiags().Report(diag::err_opt_not_valid_on_target)
+ << "-mpacked-stack";
+ Fn->addFnAttr("packed-stack");
+ }
+
if (RetTy->isVoidType()) {
// Void type; nothing to return.
ReturnValue = Address::invalid();
@@ -963,7 +1062,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
LValue ThisFieldLValue = EmitLValueForLambdaField(LambdaThisCaptureField);
if (!LambdaThisCaptureField->getType()->isPointerType()) {
// If the enclosing object was captured by value, just use its address.
- CXXThisValue = ThisFieldLValue.getAddress().getPointer();
+ CXXThisValue = ThisFieldLValue.getAddress(*this).getPointer();
} else {
// Load the lvalue pointed to by the field, since '*this' was captured
// by reference.
@@ -2000,18 +2099,18 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
Address CodeGenFunction::EmitVAListRef(const Expr* E) {
if (getContext().getBuiltinVaListType()->isArrayType())
return EmitPointerWithAlignment(E);
- return EmitLValue(E).getAddress();
+ return EmitLValue(E).getAddress(*this);
}
Address CodeGenFunction::EmitMSVAListRef(const Expr *E) {
- return EmitLValue(E).getAddress();
+ return EmitLValue(E).getAddress(*this);
}
void CodeGenFunction::EmitDeclRefExprDbgValue(const DeclRefExpr *E,
const APValue &Init) {
assert(Init.hasValue() && "Invalid DeclRefExpr initializer!");
if (CGDebugInfo *Dbg = getDebugInfo())
- if (CGM.getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo)
+ if (CGM.getCodeGenOpts().hasReducedDebugInfo())
Dbg->EmitGlobalVariable(E->getDecl(), Init);
}
@@ -2153,7 +2252,7 @@ static bool hasRequiredFeatures(const SmallVectorImpl<StringRef> &ReqFeatures,
// Now build up the set of caller features and verify that all the required
// features are there.
llvm::StringMap<bool> CallerFeatureMap;
- CGM.getFunctionFeatureMap(CallerFeatureMap, GlobalDecl().getWithDecl(FD));
+ CGM.getContext().getFunctionFeatureMap(CallerFeatureMap, FD);
// If we have at least one of the features in the feature list return
// true, otherwise return false.
@@ -2210,16 +2309,18 @@ void CodeGenFunction::checkTargetFeatures(SourceLocation Loc,
<< TargetDecl->getDeclName()
<< CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID);
- } else if (TargetDecl->hasAttr<TargetAttr>() ||
- TargetDecl->hasAttr<CPUSpecificAttr>()) {
+ } else if (!TargetDecl->isMultiVersion() &&
+ TargetDecl->hasAttr<TargetAttr>()) {
// Get the required features for the callee.
const TargetAttr *TD = TargetDecl->getAttr<TargetAttr>();
- TargetAttr::ParsedTargetAttr ParsedAttr = CGM.filterFunctionTargetAttrs(TD);
+ ParsedTargetAttr ParsedAttr =
+ CGM.getContext().filterFunctionTargetAttrs(TD);
SmallVector<StringRef, 1> ReqFeatures;
llvm::StringMap<bool> CalleeFeatureMap;
- CGM.getFunctionFeatureMap(CalleeFeatureMap, TargetDecl);
+ CGM.getContext().getFunctionFeatureMap(CalleeFeatureMap,
+ GlobalDecl(TargetDecl));
for (const auto &F : ParsedAttr.Features) {
if (F[0] == '+' && CalleeFeatureMap.lookup(F.substr(1)))
@@ -2286,10 +2387,7 @@ static void CreateMultiVersionResolverReturn(CodeGenModule &CGM,
void CodeGenFunction::EmitMultiVersionResolver(
llvm::Function *Resolver, ArrayRef<MultiVersionResolverOption> Options) {
- assert((getContext().getTargetInfo().getTriple().getArch() ==
- llvm::Triple::x86 ||
- getContext().getTargetInfo().getTriple().getArch() ==
- llvm::Triple::x86_64) &&
+ assert(getContext().getTargetInfo().getTriple().isX86() &&
"Only implemented for x86 targets");
bool SupportsIFunc = getContext().getTargetInfo().supportsIFunc();
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 99bc85ba3773..3d8bc93eb965 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -75,6 +75,7 @@ class ObjCAtTryStmt;
class ObjCAtThrowStmt;
class ObjCAtSynchronizedStmt;
class ObjCAutoreleasePoolStmt;
+class ReturnsNonNullAttr;
namespace analyze_os_log {
class OSLogBufferLayout;
@@ -947,6 +948,19 @@ public:
}
};
+ /// Save/restore original map of previously emitted local vars in case when we
+ /// need to duplicate emission of the same code several times in the same
+ /// function for OpenMP code.
+ class OMPLocalDeclMapRAII {
+ CodeGenFunction &CGF;
+ DeclMapTy SavedMap;
+
+ public:
+ OMPLocalDeclMapRAII(CodeGenFunction &CGF)
+ : CGF(CGF), SavedMap(CGF.LocalDeclMap) {}
+ ~OMPLocalDeclMapRAII() { SavedMap.swap(CGF.LocalDeclMap); }
+ };
+
/// Takes the old cleanup stack size and emits the cleanup blocks
/// that have been added.
void
@@ -1262,7 +1276,7 @@ private:
CancelExit(OpenMPDirectiveKind Kind, JumpDest ExitBlock,
JumpDest ContBlock)
: Kind(Kind), ExitBlock(ExitBlock), ContBlock(ContBlock) {}
- OpenMPDirectiveKind Kind = OMPD_unknown;
+ OpenMPDirectiveKind Kind = llvm::omp::OMPD_unknown;
/// true if the exit block has been emitted already by the special
/// emitExit() call, false if the default codegen is used.
bool HasBeenEmitted = false;
@@ -1584,11 +1598,7 @@ private:
Address ReturnLocation = Address::invalid();
/// Check if the return value of this function requires sanitization.
- bool requiresReturnValueCheck() const {
- return requiresReturnValueNullabilityCheck() ||
- (SanOpts.has(SanitizerKind::ReturnsNonnullAttribute) &&
- CurCodeDecl && CurCodeDecl->getAttr<ReturnsNonNullAttr>());
- }
+ bool requiresReturnValueCheck() const;
llvm::BasicBlock *TerminateLandingPad = nullptr;
llvm::BasicBlock *TerminateHandler = nullptr;
@@ -3132,6 +3142,7 @@ public:
void EmitOMPParallelForDirective(const OMPParallelForDirective &S);
void EmitOMPParallelForSimdDirective(const OMPParallelForSimdDirective &S);
void EmitOMPParallelSectionsDirective(const OMPParallelSectionsDirective &S);
+ void EmitOMPParallelMasterDirective(const OMPParallelMasterDirective &S);
void EmitOMPTaskDirective(const OMPTaskDirective &S);
void EmitOMPTaskyieldDirective(const OMPTaskyieldDirective &S);
void EmitOMPBarrierDirective(const OMPBarrierDirective &S);
@@ -3160,6 +3171,8 @@ public:
EmitOMPMasterTaskLoopSimdDirective(const OMPMasterTaskLoopSimdDirective &S);
void EmitOMPParallelMasterTaskLoopDirective(
const OMPParallelMasterTaskLoopDirective &S);
+ void EmitOMPParallelMasterTaskLoopSimdDirective(
+ const OMPParallelMasterTaskLoopSimdDirective &S);
void EmitOMPDistributeDirective(const OMPDistributeDirective &S);
void EmitOMPDistributeParallelForDirective(
const OMPDistributeParallelForDirective &S);
@@ -3718,6 +3731,11 @@ public:
/// Emit IR for __builtin_os_log_format.
RValue emitBuiltinOSLogFormat(const CallExpr &E);
+ /// Emit IR for __builtin_is_aligned.
+ RValue EmitBuiltinIsAligned(const CallExpr *E);
+ /// Emit IR for __builtin_align_up/__builtin_align_down.
+ RValue EmitBuiltinAlignTo(const CallExpr *E, bool AlignUp);
+
llvm::Function *generateBuiltinOSLogHelperFunction(
const analyze_os_log::OSLogBufferLayout &Layout,
CharUnits BufferAlignment);
@@ -3726,14 +3744,19 @@ public:
/// EmitTargetBuiltinExpr - Emit the given builtin call. Returns 0 if the call
/// is unhandled by the current target.
- llvm::Value *EmitTargetBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
+ llvm::Value *EmitTargetBuiltinExpr(unsigned BuiltinID, const CallExpr *E,
+ ReturnValueSlot ReturnValue);
llvm::Value *EmitAArch64CompareBuiltinExpr(llvm::Value *Op, llvm::Type *Ty,
const llvm::CmpInst::Predicate Fp,
const llvm::CmpInst::Predicate Ip,
const llvm::Twine &Name = "");
llvm::Value *EmitARMBuiltinExpr(unsigned BuiltinID, const CallExpr *E,
+ ReturnValueSlot ReturnValue,
llvm::Triple::ArchType Arch);
+ llvm::Value *EmitARMMVEBuiltinExpr(unsigned BuiltinID, const CallExpr *E,
+ ReturnValueSlot ReturnValue,
+ llvm::Triple::ArchType Arch);
llvm::Value *EmitCommonNeonBuiltinExpr(unsigned BuiltinID,
unsigned LLVMIntrinsic,
@@ -4149,6 +4172,9 @@ public:
/// point operation, expressed as the maximum relative error in ulp.
void SetFPAccuracy(llvm::Value *Val, float Accuracy);
+ /// SetFPModel - Control floating point behavior via fp-model settings.
+ void SetFPModel();
+
private:
llvm::MDNode *getRangeForLoadFromType(QualType Ty);
void EmitReturnOfRValue(RValue RV, QualType Ty);
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index b05a58848e82..57beda26677c 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -47,6 +47,7 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Intrinsics.h"
@@ -55,6 +56,7 @@
#include "llvm/IR/ProfileSummary.h"
#include "llvm/ProfileData/InstrProfReader.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"
@@ -72,6 +74,7 @@ static const char AnnotationSection[] = "llvm.metadata";
static CGCXXABI *createCXXABI(CodeGenModule &CGM) {
switch (CGM.getTarget().getCXXABI().getKind()) {
+ case TargetCXXABI::Fuchsia:
case TargetCXXABI::GenericAArch64:
case TargetCXXABI::GenericARM:
case TargetCXXABI::iOS:
@@ -216,6 +219,14 @@ void CodeGenModule::createOpenMPRuntime() {
OpenMPRuntime.reset(new CGOpenMPRuntime(*this));
break;
}
+
+ // The OpenMP-IR-Builder should eventually replace the above runtime codegens
+ // but we are not there yet so they both reside in CGModule for now and the
+ // OpenMP-IR-Builder is opt-in only.
+ if (LangOpts.OpenMPIRBuilder) {
+ OMPBuilder.reset(new llvm::OpenMPIRBuilder(TheModule));
+ OMPBuilder->initialize();
+ }
}
void CodeGenModule::createCUDARuntime() {
@@ -469,9 +480,7 @@ void CodeGenModule::Release() {
CodeGenOpts.NumRegisterParameters);
if (CodeGenOpts.DwarfVersion) {
- // We actually want the latest version when there are conflicts.
- // We can change from Warning to Latest if such mode is supported.
- getModule().addModuleFlag(llvm::Module::Warning, "Dwarf Version",
+ getModule().addModuleFlag(llvm::Module::Max, "Dwarf Version",
CodeGenOpts.DwarfVersion);
}
if (CodeGenOpts.EmitCodeView) {
@@ -482,8 +491,11 @@ void CodeGenModule::Release() {
getModule().addModuleFlag(llvm::Module::Warning, "CodeViewGHash", 1);
}
if (CodeGenOpts.ControlFlowGuard) {
- // We want function ID tables for Control Flow Guard.
- getModule().addModuleFlag(llvm::Module::Warning, "cfguardtable", 1);
+ // Function ID tables and checks for Control Flow Guard (cfguard=2).
+ getModule().addModuleFlag(llvm::Module::Warning, "cfguard", 2);
+ } else if (CodeGenOpts.ControlFlowGuardNoChecks) {
+ // Function ID tables for Control Flow Guard (cfguard=1).
+ getModule().addModuleFlag(llvm::Module::Warning, "cfguard", 1);
}
if (CodeGenOpts.OptimizationLevel > 0 && CodeGenOpts.StrictVTablePointers) {
// We don't support LTO with 2 with different StrictVTablePointers
@@ -813,7 +825,7 @@ static bool shouldAssumeDSOLocal(const CodeGenModule &CGM,
const auto &CGOpts = CGM.getCodeGenOpts();
llvm::Reloc::Model RM = CGOpts.RelocationModel;
const auto &LOpts = CGM.getLangOpts();
- if (RM != llvm::Reloc::Static && !LOpts.PIE && !LOpts.OpenMPIsDevice)
+ if (RM != llvm::Reloc::Static && !LOpts.PIE)
return false;
// A definition cannot be preempted from an executable.
@@ -954,7 +966,7 @@ static void AppendTargetMangling(const CodeGenModule &CGM,
Out << '.';
const TargetInfo &Target = CGM.getTarget();
- TargetAttr::ParsedTargetAttr Info =
+ ParsedTargetAttr Info =
Attr->parse([&Target](StringRef LHS, StringRef RHS) {
// Multiversioning doesn't allow "no-${feature}", so we can
// only have "+" prefixes here.
@@ -1511,16 +1523,15 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
!CodeGenOpts.DisableO0ImplyOptNone && CodeGenOpts.OptimizationLevel == 0;
// We can't add optnone in the following cases, it won't pass the verifier.
ShouldAddOptNone &= !D->hasAttr<MinSizeAttr>();
- ShouldAddOptNone &= !F->hasFnAttribute(llvm::Attribute::AlwaysInline);
ShouldAddOptNone &= !D->hasAttr<AlwaysInlineAttr>();
- if (ShouldAddOptNone || D->hasAttr<OptimizeNoneAttr>()) {
+ // Add optnone, but do so only if the function isn't always_inline.
+ if ((ShouldAddOptNone || D->hasAttr<OptimizeNoneAttr>()) &&
+ !F->hasFnAttribute(llvm::Attribute::AlwaysInline)) {
B.addAttribute(llvm::Attribute::OptimizeNone);
// OptimizeNone implies noinline; we should not be inlining such functions.
B.addAttribute(llvm::Attribute::NoInline);
- assert(!F->hasFnAttribute(llvm::Attribute::AlwaysInline) &&
- "OptimizeNone and AlwaysInline on same function!");
// We still need to handle naked functions even though optnone subsumes
// much of their semantics.
@@ -1536,7 +1547,8 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
B.addAttribute(llvm::Attribute::NoInline);
} else if (D->hasAttr<NoDuplicateAttr>()) {
B.addAttribute(llvm::Attribute::NoDuplicate);
- } else if (D->hasAttr<NoInlineAttr>()) {
+ } else if (D->hasAttr<NoInlineAttr>() && !F->hasFnAttribute(llvm::Attribute::AlwaysInline)) {
+ // Add noinline if the function isn't always_inline.
B.addAttribute(llvm::Attribute::NoInline);
} else if (D->hasAttr<AlwaysInlineAttr>() &&
!F->hasFnAttribute(llvm::Attribute::NoInline)) {
@@ -1664,7 +1676,7 @@ bool CodeGenModule::GetCPUAndFeaturesAttributes(GlobalDecl GD,
bool AddedAttr = false;
if (TD || SD) {
llvm::StringMap<bool> FeatureMap;
- getFunctionFeatureMap(FeatureMap, GD);
+ getContext().getFunctionFeatureMap(FeatureMap, GD);
// Produce the canonical string for this set of features.
for (const llvm::StringMap<bool>::value_type &Entry : FeatureMap)
@@ -1675,7 +1687,7 @@ bool CodeGenModule::GetCPUAndFeaturesAttributes(GlobalDecl GD,
// get and parse the target attribute so we can get the cpu for
// the function.
if (TD) {
- TargetAttr::ParsedTargetAttr ParsedAttr = TD->parse();
+ ParsedTargetAttr ParsedAttr = TD->parse();
if (ParsedAttr.Architecture != "" &&
getTarget().isValidCPUName(ParsedAttr.Architecture))
TargetCPU = ParsedAttr.Architecture;
@@ -1828,6 +1840,11 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
else if (const auto *SA = FD->getAttr<SectionAttr>())
F->setSection(SA->getName());
+ if (FD->isInlineBuiltinDeclaration()) {
+ F->addAttribute(llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::NoBuiltin);
+ }
+
if (FD->isReplaceableGlobalAllocationFunction()) {
// A replaceable global allocation function does not act like a builtin by
// default, only if it is invoked by a new-expression or delete-expression.
@@ -1930,6 +1947,8 @@ void CodeGenModule::AppendLinkerOptions(StringRef Opts) {
void CodeGenModule::AddDetectMismatch(StringRef Name, StringRef Value) {
llvm::SmallString<32> Opt;
getTargetCodeGenInfo().getDetectMismatchOption(Name, Value, Opt);
+ if (Opt.empty())
+ return;
auto *MDOpts = llvm::MDString::get(getLLVMContext(), Opt);
LinkerOptionsMetadata.push_back(llvm::MDNode::get(getLLVMContext(), MDOpts));
}
@@ -2207,9 +2226,15 @@ llvm::Constant *CodeGenModule::EmitAnnotateAttr(llvm::GlobalValue *GV,
*UnitGV = EmitAnnotationUnit(L),
*LineNoCst = EmitAnnotationLineNo(L);
+ llvm::Constant *ASZeroGV = GV;
+ if (GV->getAddressSpace() != 0) {
+ ASZeroGV = llvm::ConstantExpr::getAddrSpaceCast(
+ GV, GV->getValueType()->getPointerTo(0));
+ }
+
// Create the ConstantStruct for the global annotation.
llvm::Constant *Fields[4] = {
- llvm::ConstantExpr::getBitCast(GV, Int8PtrTy),
+ llvm::ConstantExpr::getBitCast(ASZeroGV, Int8PtrTy),
llvm::ConstantExpr::getBitCast(AnnoGV, Int8PtrTy),
llvm::ConstantExpr::getBitCast(UnitGV, Int8PtrTy),
LineNoCst
@@ -3332,8 +3357,14 @@ GetRuntimeFunctionDecl(ASTContext &C, StringRef Name) {
/// type and name.
llvm::FunctionCallee
CodeGenModule::CreateRuntimeFunction(llvm::FunctionType *FTy, StringRef Name,
- llvm::AttributeList ExtraAttrs,
- bool Local) {
+ llvm::AttributeList ExtraAttrs, bool Local,
+ bool AssumeConvergent) {
+ if (AssumeConvergent) {
+ ExtraAttrs =
+ ExtraAttrs.addAttribute(VMContext, llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::Convergent);
+ }
+
llvm::Constant *C =
GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false,
/*DontDefer=*/false, /*IsThunk=*/false,
@@ -3564,6 +3595,9 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
}
}
+ if (GV->isDeclaration())
+ getTargetCodeGenInfo().setTargetAttributes(D, GV, *this);
+
LangAS ExpectedAS =
D ? D->getType().getAddressSpace()
: (LangOpts.OpenCL ? LangAS::opencl_global : LangAS::Default);
@@ -3573,9 +3607,6 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
return getTargetCodeGenInfo().performAddrSpaceCast(*this, GV, AddrSpace,
ExpectedAS, Ty);
- if (GV->isDeclaration())
- getTargetCodeGenInfo().setTargetAttributes(D, GV, *this);
-
return GV;
}
@@ -3704,6 +3735,10 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
EmitGlobalVarDefinition(D);
}
+void CodeGenModule::EmitExternalDeclaration(const VarDecl *D) {
+ EmitExternalVarDeclaration(D);
+}
+
CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const {
return Context.toCharUnitsFromBits(
getDataLayout().getTypeStoreSizeInBits(Ty));
@@ -4083,10 +4118,23 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
// Emit global variable debug information.
if (CGDebugInfo *DI = getModuleDebugInfo())
- if (getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo)
+ if (getCodeGenOpts().hasReducedDebugInfo())
DI->EmitGlobalVariable(GV, D);
}
+void CodeGenModule::EmitExternalVarDeclaration(const VarDecl *D) {
+ if (CGDebugInfo *DI = getModuleDebugInfo())
+ if (getCodeGenOpts().hasReducedDebugInfo()) {
+ QualType ASTTy = D->getType();
+ llvm::Type *Ty = getTypes().ConvertTypeForMem(D->getType());
+ llvm::PointerType *PTy =
+ llvm::PointerType::get(Ty, getContext().getTargetAddressSpace(ASTTy));
+ llvm::Constant *GV = GetOrCreateLLVMGlobal(D->getName(), PTy, D);
+ DI->EmitExternalVariable(
+ cast<llvm::GlobalVariable>(GV->stripPointerCasts()), D);
+ }
+}
+
static bool isVarDeclStrongDefinition(const ASTContext &Context,
CodeGenModule &CGM, const VarDecl *D,
bool NoCommon) {
@@ -4999,7 +5047,7 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary(
// If we're not materializing a subobject of the temporary, keep the
// cv-qualifiers from the type of the MaterializeTemporaryExpr.
QualType MaterializedType = Init->getType();
- if (Init == E->GetTemporaryExpr())
+ if (Init == E->getSubExpr())
MaterializedType = E->getType();
CharUnits Align = getContext().getTypeAlignInChars(MaterializedType);
@@ -5022,7 +5070,7 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary(
// temporary. Note that this might have a different value from the value
// computed by evaluating the initializer if the surrounding constant
// expression modifies the temporary.
- Value = getContext().getMaterializedTemporaryValue(E, false);
+ Value = E->getOrCreateValue(false);
}
// Try evaluating it now, it might have a constant initializer.
@@ -5102,11 +5150,12 @@ void CodeGenModule::EmitObjCPropertyImplementations(const
// we want, that just indicates if the decl came from a
// property. What we want to know is if the method is defined in
// this implementation.
- if (!D->getInstanceMethod(PD->getGetterName()))
+ auto *Getter = PID->getGetterMethodDecl();
+ if (!Getter || Getter->isSynthesizedAccessorStub())
CodeGenFunction(*this).GenerateObjCGetter(
- const_cast<ObjCImplementationDecl *>(D), PID);
- if (!PD->isReadOnly() &&
- !D->getInstanceMethod(PD->getSetterName()))
+ const_cast<ObjCImplementationDecl *>(D), PID);
+ auto *Setter = PID->getSetterMethodDecl();
+ if (!PD->isReadOnly() && (!Setter || Setter->isSynthesizedAccessorStub()))
CodeGenFunction(*this).GenerateObjCSetter(
const_cast<ObjCImplementationDecl *>(D), PID);
}
@@ -5143,12 +5192,13 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
if (needsDestructMethod(D)) {
IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct");
Selector cxxSelector = getContext().Selectors.getSelector(0, &II);
- ObjCMethodDecl *DTORMethod =
- ObjCMethodDecl::Create(getContext(), D->getLocation(), D->getLocation(),
- cxxSelector, getContext().VoidTy, nullptr, D,
- /*isInstance=*/true, /*isVariadic=*/false,
- /*isPropertyAccessor=*/true, /*isImplicitlyDeclared=*/true,
- /*isDefined=*/false, ObjCMethodDecl::Required);
+ ObjCMethodDecl *DTORMethod = ObjCMethodDecl::Create(
+ getContext(), D->getLocation(), D->getLocation(), cxxSelector,
+ getContext().VoidTy, nullptr, D,
+ /*isInstance=*/true, /*isVariadic=*/false,
+ /*isPropertyAccessor=*/true, /*isSynthesizedAccessorStub=*/false,
+ /*isImplicitlyDeclared=*/true,
+ /*isDefined=*/false, ObjCMethodDecl::Required);
D->addInstanceMethod(DTORMethod);
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false);
D->setHasDestructors(true);
@@ -5163,17 +5213,13 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
IdentifierInfo *II = &getContext().Idents.get(".cxx_construct");
Selector cxxSelector = getContext().Selectors.getSelector(0, &II);
// The constructor returns 'self'.
- ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(getContext(),
- D->getLocation(),
- D->getLocation(),
- cxxSelector,
- getContext().getObjCIdType(),
- nullptr, D, /*isInstance=*/true,
- /*isVariadic=*/false,
- /*isPropertyAccessor=*/true,
- /*isImplicitlyDeclared=*/true,
- /*isDefined=*/false,
- ObjCMethodDecl::Required);
+ ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(
+ getContext(), D->getLocation(), D->getLocation(), cxxSelector,
+ getContext().getObjCIdType(), nullptr, D, /*isInstance=*/true,
+ /*isVariadic=*/false,
+ /*isPropertyAccessor=*/true, /*isSynthesizedAccessorStub=*/false,
+ /*isImplicitlyDeclared=*/true,
+ /*isDefined=*/false, ObjCMethodDecl::Required);
D->addInstanceMethod(CTORMethod);
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true);
D->setHasNonZeroConstructors(true);
@@ -5182,9 +5228,7 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
// EmitLinkageSpec - Emit all declarations in a linkage spec.
void CodeGenModule::EmitLinkageSpec(const LinkageSpecDecl *LSD) {
if (LSD->getLanguage() != LinkageSpecDecl::lang_c &&
- LSD->getLanguage() != LinkageSpecDecl::lang_cxx &&
- LSD->getLanguage() != LinkageSpecDecl::lang_cxx_11 &&
- LSD->getLanguage() != LinkageSpecDecl::lang_cxx_14) {
+ LSD->getLanguage() != LinkageSpecDecl::lang_cxx) {
ErrorUnsupported(LSD, "linkage spec");
return;
}
@@ -5327,7 +5371,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
ObjCRuntime->GenerateClass(OMD);
// Emit global variable debug information.
if (CGDebugInfo *DI = getModuleDebugInfo())
- if (getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo)
+ if (getCodeGenOpts().hasReducedDebugInfo())
DI->getOrCreateInterfaceType(getContext().getObjCInterfaceType(
OMD->getClassInterface()), OMD->getLocation());
break;
@@ -5851,58 +5895,6 @@ void CodeGenModule::AddVTableTypeMetadata(llvm::GlobalVariable *VTable,
}
}
-TargetAttr::ParsedTargetAttr CodeGenModule::filterFunctionTargetAttrs(const TargetAttr *TD) {
- assert(TD != nullptr);
- TargetAttr::ParsedTargetAttr ParsedAttr = TD->parse();
-
- ParsedAttr.Features.erase(
- llvm::remove_if(ParsedAttr.Features,
- [&](const std::string &Feat) {
- return !Target.isValidFeatureName(
- StringRef{Feat}.substr(1));
- }),
- ParsedAttr.Features.end());
- return ParsedAttr;
-}
-
-
-// Fills in the supplied string map with the set of target features for the
-// passed in function.
-void CodeGenModule::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
- GlobalDecl GD) {
- StringRef TargetCPU = Target.getTargetOpts().CPU;
- const FunctionDecl *FD = GD.getDecl()->getAsFunction();
- if (const auto *TD = FD->getAttr<TargetAttr>()) {
- TargetAttr::ParsedTargetAttr ParsedAttr = filterFunctionTargetAttrs(TD);
-
- // Make a copy of the features as passed on the command line into the
- // beginning of the additional features from the function to override.
- ParsedAttr.Features.insert(ParsedAttr.Features.begin(),
- Target.getTargetOpts().FeaturesAsWritten.begin(),
- Target.getTargetOpts().FeaturesAsWritten.end());
-
- if (ParsedAttr.Architecture != "" &&
- Target.isValidCPUName(ParsedAttr.Architecture))
- TargetCPU = ParsedAttr.Architecture;
-
- // 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
- // the passed in features (FeaturesAsWritten) along with the new ones from
- // the attribute.
- Target.initFeatureMap(FeatureMap, getDiags(), TargetCPU,
- ParsedAttr.Features);
- } else if (const auto *SD = FD->getAttr<CPUSpecificAttr>()) {
- llvm::SmallVector<StringRef, 32> FeaturesTmp;
- Target.getCPUSpecificCPUDispatchFeatures(
- SD->getCPUName(GD.getMultiVersionIndex())->getName(), FeaturesTmp);
- std::vector<std::string> Features(FeaturesTmp.begin(), FeaturesTmp.end());
- Target.initFeatureMap(FeatureMap, getDiags(), TargetCPU, Features);
- } else {
- Target.initFeatureMap(FeatureMap, getDiags(), TargetCPU,
- Target.getTargetOpts().Features);
- }
-}
-
llvm::SanitizerStatReport &CodeGenModule::getSanStats() {
if (!SanStats)
SanStats = std::make_unique<llvm::SanitizerStatReport>(&getModule());
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 73f81adae35f..115e754bb392 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -17,7 +17,6 @@
#include "CodeGenTypeCache.h"
#include "CodeGenTypes.h"
#include "SanitizerMetadata.h"
-#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclOpenMP.h"
@@ -45,6 +44,7 @@ class GlobalValue;
class DataLayout;
class FunctionType;
class LLVMContext;
+class OpenMPIRBuilder;
class IndexedInstrProfReader;
}
@@ -77,6 +77,9 @@ class AnnotateAttr;
class CXXDestructorDecl;
class Module;
class CoverageSourceInfo;
+class TargetAttr;
+class InitSegAttr;
+struct ParsedTargetAttr;
namespace CodeGen {
@@ -319,6 +322,7 @@ private:
std::unique_ptr<CGObjCRuntime> ObjCRuntime;
std::unique_ptr<CGOpenCLRuntime> OpenCLRuntime;
std::unique_ptr<CGOpenMPRuntime> OpenMPRuntime;
+ std::unique_ptr<llvm::OpenMPIRBuilder> OMPBuilder;
std::unique_ptr<CGCUDARuntime> CUDARuntime;
std::unique_ptr<CGDebugInfo> DebugInfo;
std::unique_ptr<ObjCEntrypoints> ObjCData;
@@ -523,18 +527,18 @@ private:
int GlobalUniqueCount;
} Block;
+ GlobalDecl initializedGlobalDecl;
+
+ /// @}
+
/// void @llvm.lifetime.start(i64 %size, i8* nocapture <ptr>)
llvm::Function *LifetimeStartFn = nullptr;
/// void @llvm.lifetime.end(i64 %size, i8* nocapture <ptr>)
llvm::Function *LifetimeEndFn = nullptr;
- GlobalDecl initializedGlobalDecl;
-
std::unique_ptr<SanitizerMetadata> SanitizerMD;
- /// @}
-
llvm::MapVector<const Decl *, bool> DeferredEmptyCoverageMappingDecls;
std::unique_ptr<CoverageMappingModuleGen> CoverageMapping;
@@ -585,6 +589,9 @@ public:
return *OpenMPRuntime;
}
+ /// Return a pointer to the configured OpenMPIRBuilder, if any.
+ llvm::OpenMPIRBuilder *getOpenMPIRBuilder() { return OMPBuilder.get(); }
+
/// Return a reference to the configured CUDA runtime.
CGCUDARuntime &getCUDARuntime() {
assert(CUDARuntime != nullptr);
@@ -1027,11 +1034,22 @@ public:
}
/// Create or return a runtime function declaration with the specified type
- /// and name.
+ /// and name. If \p AssumeConvergent is true, the call will have the
+ /// convergent attribute added.
llvm::FunctionCallee
CreateRuntimeFunction(llvm::FunctionType *Ty, StringRef Name,
llvm::AttributeList ExtraAttrs = llvm::AttributeList(),
- bool Local = false);
+ bool Local = false, bool AssumeConvergent = false);
+
+ /// Create or return a runtime function declaration with the specified type
+ /// and name. This will automatically add the convergent attribute to the
+ /// function declaration.
+ llvm::FunctionCallee CreateConvergentRuntimeFunction(
+ llvm::FunctionType *Ty, StringRef Name,
+ llvm::AttributeList ExtraAttrs = llvm::AttributeList(),
+ bool Local = false) {
+ return CreateRuntimeFunction(Ty, Name, ExtraAttrs, Local, true);
+ }
/// Create a new runtime global variable with the specified type and name.
llvm::Constant *CreateRuntimeVariable(llvm::Type *Ty,
@@ -1139,19 +1157,13 @@ public:
/// It's up to you to ensure that this is safe.
void AddDefaultFnAttrs(llvm::Function &F);
- /// Parses the target attributes passed in, and returns only the ones that are
- /// valid feature names.
- TargetAttr::ParsedTargetAttr filterFunctionTargetAttrs(const TargetAttr *TD);
-
- // Fills in the supplied string map with the set of target features for the
- // passed in function.
- void getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap, GlobalDecl GD);
-
StringRef getMangledName(GlobalDecl GD);
StringRef getBlockMangledName(GlobalDecl GD, const BlockDecl *BD);
void EmitTentativeDefinition(const VarDecl *D);
+ void EmitExternalDeclaration(const VarDecl *D);
+
void EmitVTable(CXXRecordDecl *Class);
void RefreshTypeCacheForClass(const CXXRecordDecl *Class);
@@ -1387,6 +1399,7 @@ private:
void EmitMultiVersionFunctionDefinition(GlobalDecl GD, llvm::GlobalValue *GV);
void EmitGlobalVarDefinition(const VarDecl *D, bool IsTentative = false);
+ void EmitExternalVarDeclaration(const VarDecl *D);
void EmitAliasDefinition(GlobalDecl GD);
void emitIFuncDefinition(GlobalDecl GD);
void emitCPUDispatchDefinition(GlobalDecl GD);
diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp
index e525abe979e3..bad796bf92dc 100644
--- a/clang/lib/CodeGen/CodeGenPGO.cpp
+++ b/clang/lib/CodeGen/CodeGenPGO.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/StmtVisitor.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/MDBuilder.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MD5.h"
@@ -166,7 +167,7 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
bool TraverseBlockExpr(BlockExpr *BE) { return true; }
bool TraverseLambdaExpr(LambdaExpr *LE) {
// Traverse the captures, but not the body.
- for (const auto &C : zip(LE->captures(), LE->capture_inits()))
+ for (auto C : zip(LE->captures(), LE->capture_inits()))
TraverseLambdaCapture(LE, &std::get<0>(C), std::get<1>(C));
return true;
}
diff --git a/clang/lib/CodeGen/CodeGenTBAA.cpp b/clang/lib/CodeGen/CodeGenTBAA.cpp
index 09de9591de7e..7d730cb1ed15 100644
--- a/clang/lib/CodeGen/CodeGenTBAA.cpp
+++ b/clang/lib/CodeGen/CodeGenTBAA.cpp
@@ -78,17 +78,18 @@ llvm::MDNode *CodeGenTBAA::getChar() {
static bool TypeHasMayAlias(QualType QTy) {
// Tagged types have declarations, and therefore may have attributes.
- if (const TagType *TTy = dyn_cast<TagType>(QTy))
- return TTy->getDecl()->hasAttr<MayAliasAttr>();
+ if (auto *TD = QTy->getAsTagDecl())
+ if (TD->hasAttr<MayAliasAttr>())
+ return true;
- // Typedef types have declarations, and therefore may have attributes.
- if (const TypedefType *TTy = dyn_cast<TypedefType>(QTy)) {
- if (TTy->getDecl()->hasAttr<MayAliasAttr>())
+ // Also look for may_alias as a declaration attribute on a typedef.
+ // FIXME: We should follow GCC and model may_alias as a type attribute
+ // rather than as a declaration attribute.
+ while (auto *TT = QTy->getAs<TypedefType>()) {
+ if (TT->getDecl()->hasAttr<MayAliasAttr>())
return true;
- // Also, their underlying types may have relevant attributes.
- return TypeHasMayAlias(TTy->desugar());
+ QTy = TT->desugar();
}
-
return false;
}
diff --git a/clang/lib/CodeGen/ConstantEmitter.h b/clang/lib/CodeGen/ConstantEmitter.h
index 59a19730f4eb..121acbac4fa9 100644
--- a/clang/lib/CodeGen/ConstantEmitter.h
+++ b/clang/lib/CodeGen/ConstantEmitter.h
@@ -23,7 +23,7 @@ namespace CodeGen {
class ConstantEmitter {
public:
CodeGenModule &CGM;
- CodeGenFunction *CGF;
+ CodeGenFunction *const CGF;
private:
bool Abstract = false;
diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index a6f6e38d5f14..bdecff39c88f 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -1114,8 +1114,8 @@ struct CounterCoverageMappingBuilder
// Make a region for the body of the switch. If the body starts with
// a case, that case will reuse this region; otherwise, this covers
// the unreachable code at the beginning of the switch body.
- size_t Index =
- pushRegion(Counter::getZero(), getStart(CS->body_front()));
+ size_t Index = pushRegion(Counter::getZero(), getStart(CS));
+ getRegion().setGap(true);
for (const auto *Child : CS->children())
Visit(Child);
@@ -1278,6 +1278,13 @@ std::string getCoverageSection(const CodeGenModule &CGM) {
CGM.getContext().getTargetInfo().getTriple().getObjectFormat());
}
+std::string normalizeFilename(StringRef Filename) {
+ llvm::SmallString<256> Path(Filename);
+ llvm::sys::fs::make_absolute(Path);
+ llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
+ return Path.str().str();
+}
+
} // end anonymous namespace
static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
@@ -1310,24 +1317,6 @@ static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
}
}
-CoverageMappingModuleGen::CoverageMappingModuleGen(
- CodeGenModule &CGM, CoverageSourceInfo &SourceInfo)
- : CGM(CGM), SourceInfo(SourceInfo), FunctionRecordTy(nullptr) {
- // Honor -fdebug-compilation-dir in paths in coverage data. Otherwise, use the
- // regular working directory when normalizing paths.
- if (!CGM.getCodeGenOpts().DebugCompilationDir.empty())
- CWD = CGM.getCodeGenOpts().DebugCompilationDir;
- else
- llvm::sys::fs::current_path(CWD);
-}
-
-std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) {
- llvm::SmallString<256> Path(Filename);
- llvm::sys::fs::make_absolute(CWD, Path);
- llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
- return Path.str().str();
-}
-
void CoverageMappingModuleGen::addFunctionMappingRecord(
llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash,
const std::string &CoverageMapping, bool IsUsed) {
diff --git a/clang/lib/CodeGen/CoverageMappingGen.h b/clang/lib/CodeGen/CoverageMappingGen.h
index 2bdc00e25668..3bf51f590479 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.h
+++ b/clang/lib/CodeGen/CoverageMappingGen.h
@@ -54,14 +54,10 @@ class CoverageMappingModuleGen {
std::vector<llvm::Constant *> FunctionNames;
llvm::StructType *FunctionRecordTy;
std::vector<std::string> CoverageMappings;
- SmallString<256> CWD;
-
- /// Make the filename absolute, remove dots, and normalize slashes to local
- /// path style.
- std::string normalizeFilename(StringRef Filename);
public:
- CoverageMappingModuleGen(CodeGenModule &CGM, CoverageSourceInfo &SourceInfo);
+ CoverageMappingModuleGen(CodeGenModule &CGM, CoverageSourceInfo &SourceInfo)
+ : CGM(CGM), SourceInfo(SourceInfo), FunctionRecordTy(nullptr) {}
CoverageSourceInfo &getSourceInfo() const {
return SourceInfo;
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 8f9b16470b64..b5b8702c551e 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -24,10 +24,11 @@
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "TargetInfo.h"
-#include "clang/CodeGen/ConstantInitBuilder.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Mangle.h"
-#include "clang/AST/Type.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/AST/Type.h"
+#include "clang/CodeGen/ConstantInitBuilder.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/Instructions.h"
@@ -487,6 +488,19 @@ public:
bool shouldRTTIBeUnique() const override { return false; }
};
+class FuchsiaCXXABI final : public ItaniumCXXABI {
+public:
+ explicit FuchsiaCXXABI(CodeGen::CodeGenModule &CGM)
+ : ItaniumCXXABI(CGM) {}
+
+private:
+ bool HasThisReturn(GlobalDecl GD) const override {
+ return isa<CXXConstructorDecl>(GD.getDecl()) ||
+ (isa<CXXDestructorDecl>(GD.getDecl()) &&
+ GD.getDtorType() != Dtor_Deleting);
+ }
+};
+
class WebAssemblyCXXABI final : public ItaniumCXXABI {
public:
explicit WebAssemblyCXXABI(CodeGen::CodeGenModule &CGM)
@@ -516,6 +530,9 @@ CodeGen::CGCXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) {
case TargetCXXABI::iOS64:
return new iOS64CXXABI(CGM);
+ case TargetCXXABI::Fuchsia:
+ return new FuchsiaCXXABI(CGM);
+
// Note that AArch64 uses the generic ItaniumCXXABI class since it doesn't
// include the other 32-bit ARM oddities: constructor/destructor return values
// and array cookies.
@@ -2406,7 +2423,7 @@ static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF,
}
void CodeGenModule::registerGlobalDtorsWithAtExit() {
- for (const auto I : DtorsUsingAtExit) {
+ for (const auto &I : DtorsUsingAtExit) {
int Priority = I.first;
const llvm::TinyPtrVector<llvm::Function *> &Dtors = I.second;
@@ -2529,6 +2546,9 @@ ItaniumCXXABI::getOrCreateThreadLocalWrapper(const VarDecl *VD,
llvm::Function::Create(FnTy, getThreadLocalWrapperLinkage(VD, CGM),
WrapperName.str(), &CGM.getModule());
+ if (CGM.supportsCOMDAT() && Wrapper->isWeakForLinker())
+ Wrapper->setComdat(CGM.getModule().getOrInsertComdat(Wrapper->getName()));
+
CGM.SetLLVMFunctionAttributes(GlobalDecl(), FI, Wrapper);
// Always resolve references to the wrapper at link time.
@@ -2667,7 +2687,9 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs(
if (Init) {
Init->setVisibility(Var->getVisibility());
- Init->setDSOLocal(Var->isDSOLocal());
+ // Don't mark an extern_weak function DSO local on windows.
+ if (!CGM.getTriple().isOSWindows() || !Init->hasExternalWeakLinkage())
+ Init->setDSOLocal(Var->isDSOLocal());
}
llvm::LLVMContext &Context = CGM.getModule().getContext();
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index 2d8b538bc2ee..aff46135705a 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -19,11 +19,13 @@
#include "CodeGenModule.h"
#include "CodeGenTypes.h"
#include "TargetInfo.h"
-#include "clang/CodeGen/ConstantInitBuilder.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/VTableBuilder.h"
+#include "clang/CodeGen/ConstantInitBuilder.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/IR/Intrinsics.h"
@@ -619,6 +621,9 @@ private:
llvm::Function *EmitVirtualMemPtrThunk(const CXXMethodDecl *MD,
const MethodVFTableLocation &ML);
+ llvm::Constant *EmitMemberDataPointer(const CXXRecordDecl *RD,
+ CharUnits offset);
+
public:
llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT) override;
@@ -1339,6 +1344,13 @@ void MicrosoftCXXABI::EmitCXXDestructors(const CXXDestructorDecl *D) {
// The TU defining a dtor is only guaranteed to emit a base destructor. All
// other destructor variants are delegating thunks.
CGM.EmitGlobal(GlobalDecl(D, Dtor_Base));
+
+ // If the class is dllexported, emit the complete (vbase) destructor wherever
+ // the base dtor is emitted.
+ // FIXME: To match MSVC, this should only be done when the class is exported
+ // with -fdllexport-inlines enabled.
+ if (D->getParent()->getNumVBases() > 0 && D->hasAttr<DLLExportAttr>())
+ CGM.EmitGlobal(GlobalDecl(D, Dtor_Complete));
}
CharUnits
@@ -2601,27 +2613,27 @@ bool MicrosoftCXXABI::isZeroInitializable(const MemberPointerType *MPT) {
// we can't zero initialize. The field offset is sometimes also -1 if 0 is a
// valid field offset.
const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
- MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
- return (!MSInheritanceAttr::hasVBTableOffsetField(Inheritance) &&
+ MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
+ return (!inheritanceModelHasVBTableOffsetField(Inheritance) &&
RD->nullFieldOffsetIsZero());
}
llvm::Type *
MicrosoftCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) {
const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
- MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
+ MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
llvm::SmallVector<llvm::Type *, 4> fields;
if (MPT->isMemberFunctionPointer())
fields.push_back(CGM.VoidPtrTy); // FunctionPointerOrVirtualThunk
else
fields.push_back(CGM.IntTy); // FieldOffset
- if (MSInheritanceAttr::hasNVOffsetField(MPT->isMemberFunctionPointer(),
- Inheritance))
+ if (inheritanceModelHasNVOffsetField(MPT->isMemberFunctionPointer(),
+ Inheritance))
fields.push_back(CGM.IntTy);
- if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance))
+ if (inheritanceModelHasVBPtrOffsetField(Inheritance))
fields.push_back(CGM.IntTy);
- if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
+ if (inheritanceModelHasVBTableOffsetField(Inheritance))
fields.push_back(CGM.IntTy); // VirtualBaseAdjustmentOffset
if (fields.size() == 1)
@@ -2634,7 +2646,7 @@ GetNullMemberPointerFields(const MemberPointerType *MPT,
llvm::SmallVectorImpl<llvm::Constant *> &fields) {
assert(fields.empty());
const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
- MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
+ MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
if (MPT->isMemberFunctionPointer()) {
// FunctionPointerOrVirtualThunk
fields.push_back(llvm::Constant::getNullValue(CGM.VoidPtrTy));
@@ -2645,12 +2657,12 @@ GetNullMemberPointerFields(const MemberPointerType *MPT,
fields.push_back(getAllOnesInt()); // FieldOffset
}
- if (MSInheritanceAttr::hasNVOffsetField(MPT->isMemberFunctionPointer(),
- Inheritance))
+ if (inheritanceModelHasNVOffsetField(MPT->isMemberFunctionPointer(),
+ Inheritance))
fields.push_back(getZeroInt());
- if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance))
+ if (inheritanceModelHasVBPtrOffsetField(Inheritance))
fields.push_back(getZeroInt());
- if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
+ if (inheritanceModelHasVBTableOffsetField(Inheritance))
fields.push_back(getAllOnesInt());
}
@@ -2671,21 +2683,21 @@ MicrosoftCXXABI::EmitFullMemberPointer(llvm::Constant *FirstField,
const CXXRecordDecl *RD,
CharUnits NonVirtualBaseAdjustment,
unsigned VBTableIndex) {
- MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
+ MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
// Single inheritance class member pointer are represented as scalars instead
// of aggregates.
- if (MSInheritanceAttr::hasOnlyOneField(IsMemberFunction, Inheritance))
+ if (inheritanceModelHasOnlyOneField(IsMemberFunction, Inheritance))
return FirstField;
llvm::SmallVector<llvm::Constant *, 4> fields;
fields.push_back(FirstField);
- if (MSInheritanceAttr::hasNVOffsetField(IsMemberFunction, Inheritance))
+ if (inheritanceModelHasNVOffsetField(IsMemberFunction, Inheritance))
fields.push_back(llvm::ConstantInt::get(
CGM.IntTy, NonVirtualBaseAdjustment.getQuantity()));
- if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance)) {
+ if (inheritanceModelHasVBPtrOffsetField(Inheritance)) {
CharUnits Offs = CharUnits::Zero();
if (VBTableIndex)
Offs = getContext().getASTRecordLayout(RD).getVBPtrOffset();
@@ -2693,7 +2705,7 @@ MicrosoftCXXABI::EmitFullMemberPointer(llvm::Constant *FirstField,
}
// The rest of the fields are adjusted by conversions to a more derived class.
- if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
+ if (inheritanceModelHasVBTableOffsetField(Inheritance))
fields.push_back(llvm::ConstantInt::get(CGM.IntTy, VBTableIndex));
return llvm::ConstantStruct::getAnon(fields);
@@ -2702,9 +2714,13 @@ MicrosoftCXXABI::EmitFullMemberPointer(llvm::Constant *FirstField,
llvm::Constant *
MicrosoftCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
CharUnits offset) {
- const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
+ return EmitMemberDataPointer(MPT->getMostRecentCXXRecordDecl(), offset);
+}
+
+llvm::Constant *MicrosoftCXXABI::EmitMemberDataPointer(const CXXRecordDecl *RD,
+ CharUnits offset) {
if (RD->getMSInheritanceModel() ==
- MSInheritanceAttr::Keyword_virtual_inheritance)
+ MSInheritanceModel::Virtual)
offset -= getContext().getOffsetOfBaseWithVBPtr(RD);
llvm::Constant *FirstField =
llvm::ConstantInt::get(CGM.IntTy, offset.getQuantity());
@@ -2726,8 +2742,17 @@ llvm::Constant *MicrosoftCXXABI::EmitMemberPointer(const APValue &MP,
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MPD)) {
C = EmitMemberFunctionPointer(MD);
} else {
+ // For a pointer to data member, start off with the offset of the field in
+ // the class in which it was declared, and convert from there if necessary.
+ // For indirect field decls, get the outermost anonymous field and use the
+ // parent class.
CharUnits FieldOffset = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(MPD));
- C = EmitMemberDataPointer(DstTy, FieldOffset);
+ const FieldDecl *FD = dyn_cast<FieldDecl>(MPD);
+ if (!FD)
+ FD = cast<FieldDecl>(*cast<IndirectFieldDecl>(MPD)->chain_begin());
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(FD->getParent());
+ RD = RD->getMostRecentNonInjectedDecl();
+ C = EmitMemberDataPointer(RD, FieldOffset);
}
if (!MemberPointerPath.empty()) {
@@ -2801,7 +2826,7 @@ MicrosoftCXXABI::EmitMemberFunctionPointer(const CXXMethodDecl *MD) {
if (VBTableIndex == 0 &&
RD->getMSInheritanceModel() ==
- MSInheritanceAttr::Keyword_virtual_inheritance)
+ MSInheritanceModel::Virtual)
NonVirtualBaseAdjustment -= getContext().getOffsetOfBaseWithVBPtr(RD);
// The rest of the fields are common with data member pointers.
@@ -2837,9 +2862,9 @@ MicrosoftCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF,
// If this is a single field member pointer (single inheritance), this is a
// single icmp.
const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
- MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
- if (MSInheritanceAttr::hasOnlyOneField(MPT->isMemberFunctionPointer(),
- Inheritance))
+ MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
+ if (inheritanceModelHasOnlyOneField(MPT->isMemberFunctionPointer(),
+ Inheritance))
return Builder.CreateICmp(Eq, L, R);
// Compare the first field.
@@ -3039,7 +3064,7 @@ llvm::Value *MicrosoftCXXABI::EmitMemberDataPointerAddress(
CGF.ConvertTypeForMem(MPT->getPointeeType())->getPointerTo(AS);
CGBuilderTy &Builder = CGF.Builder;
const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
- MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
+ MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
// Extract the fields we need, regardless of model. We'll apply them if we
// have them.
@@ -3050,9 +3075,9 @@ llvm::Value *MicrosoftCXXABI::EmitMemberDataPointerAddress(
// We need to extract values.
unsigned I = 0;
FieldOffset = Builder.CreateExtractValue(MemPtr, I++);
- if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance))
+ if (inheritanceModelHasVBPtrOffsetField(Inheritance))
VBPtrOffset = Builder.CreateExtractValue(MemPtr, I++);
- if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
+ if (inheritanceModelHasVBTableOffsetField(Inheritance))
VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(MemPtr, I++);
}
@@ -3147,8 +3172,8 @@ llvm::Value *MicrosoftCXXABI::EmitNonNullMemberPointerConversion(
CGBuilderTy &Builder) {
const CXXRecordDecl *SrcRD = SrcTy->getMostRecentCXXRecordDecl();
const CXXRecordDecl *DstRD = DstTy->getMostRecentCXXRecordDecl();
- MSInheritanceAttr::Spelling SrcInheritance = SrcRD->getMSInheritanceModel();
- MSInheritanceAttr::Spelling DstInheritance = DstRD->getMSInheritanceModel();
+ MSInheritanceModel SrcInheritance = SrcRD->getMSInheritanceModel();
+ MSInheritanceModel DstInheritance = DstRD->getMSInheritanceModel();
bool IsFunc = SrcTy->isMemberFunctionPointer();
bool IsConstant = isa<llvm::Constant>(Src);
@@ -3157,15 +3182,15 @@ llvm::Value *MicrosoftCXXABI::EmitNonNullMemberPointerConversion(
llvm::Value *NonVirtualBaseAdjustment = getZeroInt();
llvm::Value *VirtualBaseAdjustmentOffset = getZeroInt();
llvm::Value *VBPtrOffset = getZeroInt();
- if (!MSInheritanceAttr::hasOnlyOneField(IsFunc, SrcInheritance)) {
+ if (!inheritanceModelHasOnlyOneField(IsFunc, SrcInheritance)) {
// We need to extract values.
unsigned I = 0;
FirstField = Builder.CreateExtractValue(Src, I++);
- if (MSInheritanceAttr::hasNVOffsetField(IsFunc, SrcInheritance))
+ if (inheritanceModelHasNVOffsetField(IsFunc, SrcInheritance))
NonVirtualBaseAdjustment = Builder.CreateExtractValue(Src, I++);
- if (MSInheritanceAttr::hasVBPtrOffsetField(SrcInheritance))
+ if (inheritanceModelHasVBPtrOffsetField(SrcInheritance))
VBPtrOffset = Builder.CreateExtractValue(Src, I++);
- if (MSInheritanceAttr::hasVBTableOffsetField(SrcInheritance))
+ if (inheritanceModelHasVBTableOffsetField(SrcInheritance))
VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(Src, I++);
}
@@ -3184,7 +3209,7 @@ llvm::Value *MicrosoftCXXABI::EmitNonNullMemberPointerConversion(
// adjustment to normalize the member pointer.
llvm::Value *SrcVBIndexEqZero =
Builder.CreateICmpEQ(VirtualBaseAdjustmentOffset, getZeroInt());
- if (SrcInheritance == MSInheritanceAttr::Keyword_virtual_inheritance) {
+ if (SrcInheritance == MSInheritanceModel::Virtual) {
if (int64_t SrcOffsetToFirstVBase =
getContext().getOffsetOfBaseWithVBPtr(SrcRD).getQuantity()) {
llvm::Value *UndoSrcAdjustment = Builder.CreateSelect(
@@ -3218,8 +3243,8 @@ llvm::Value *MicrosoftCXXABI::EmitNonNullMemberPointerConversion(
// Update the vbindex to an appropriate value in the destination because
// SrcRD's vbtable might not be a strict prefix of the one in DstRD.
llvm::Value *DstVBIndexEqZero = SrcVBIndexEqZero;
- if (MSInheritanceAttr::hasVBTableOffsetField(DstInheritance) &&
- MSInheritanceAttr::hasVBTableOffsetField(SrcInheritance)) {
+ if (inheritanceModelHasVBTableOffsetField(DstInheritance) &&
+ inheritanceModelHasVBTableOffsetField(SrcInheritance)) {
if (llvm::GlobalVariable *VDispMap =
getAddrOfVirtualDisplacementMap(SrcRD, DstRD)) {
llvm::Value *VBIndex = Builder.CreateExactUDiv(
@@ -3242,7 +3267,7 @@ llvm::Value *MicrosoftCXXABI::EmitNonNullMemberPointerConversion(
// Set the VBPtrOffset to zero if the vbindex is zero. Otherwise, initialize
// it to the offset of the vbptr.
- if (MSInheritanceAttr::hasVBPtrOffsetField(DstInheritance)) {
+ if (inheritanceModelHasVBPtrOffsetField(DstInheritance)) {
llvm::Value *DstVBPtrOffset = llvm::ConstantInt::get(
CGM.IntTy,
getContext().getASTRecordLayout(DstRD).getVBPtrOffset().getQuantity());
@@ -3253,7 +3278,7 @@ llvm::Value *MicrosoftCXXABI::EmitNonNullMemberPointerConversion(
// Likewise, apply a similar adjustment so that dereferencing the member
// pointer correctly accounts for the distance between the start of the first
// virtual base and the top of the MDC.
- if (DstInheritance == MSInheritanceAttr::Keyword_virtual_inheritance) {
+ if (DstInheritance == MSInheritanceModel::Virtual) {
if (int64_t DstOffsetToFirstVBase =
getContext().getOffsetOfBaseWithVBPtr(DstRD).getQuantity()) {
llvm::Value *DoDstAdjustment = Builder.CreateSelect(
@@ -3266,17 +3291,17 @@ llvm::Value *MicrosoftCXXABI::EmitNonNullMemberPointerConversion(
// Recompose dst from the null struct and the adjusted fields from src.
llvm::Value *Dst;
- if (MSInheritanceAttr::hasOnlyOneField(IsFunc, DstInheritance)) {
+ if (inheritanceModelHasOnlyOneField(IsFunc, DstInheritance)) {
Dst = FirstField;
} else {
Dst = llvm::UndefValue::get(ConvertMemberPointerType(DstTy));
unsigned Idx = 0;
Dst = Builder.CreateInsertValue(Dst, FirstField, Idx++);
- if (MSInheritanceAttr::hasNVOffsetField(IsFunc, DstInheritance))
+ if (inheritanceModelHasNVOffsetField(IsFunc, DstInheritance))
Dst = Builder.CreateInsertValue(Dst, NonVirtualBaseAdjustment, Idx++);
- if (MSInheritanceAttr::hasVBPtrOffsetField(DstInheritance))
+ if (inheritanceModelHasVBPtrOffsetField(DstInheritance))
Dst = Builder.CreateInsertValue(Dst, VBPtrOffset, Idx++);
- if (MSInheritanceAttr::hasVBTableOffsetField(DstInheritance))
+ if (inheritanceModelHasVBTableOffsetField(DstInheritance))
Dst = Builder.CreateInsertValue(Dst, VirtualBaseAdjustmentOffset, Idx++);
}
return Dst;
@@ -3332,7 +3357,7 @@ CGCallee MicrosoftCXXABI::EmitLoadOfMemberFunctionPointer(
CGM.getTypes().arrangeCXXMethodType(RD, FPT, /*FD=*/nullptr));
CGBuilderTy &Builder = CGF.Builder;
- MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
+ MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
// Extract the fields we need, regardless of model. We'll apply them if we
// have them.
@@ -3344,11 +3369,11 @@ CGCallee MicrosoftCXXABI::EmitLoadOfMemberFunctionPointer(
// We need to extract values.
unsigned I = 0;
FunctionPointer = Builder.CreateExtractValue(MemPtr, I++);
- if (MSInheritanceAttr::hasNVOffsetField(MPT, Inheritance))
+ if (inheritanceModelHasNVOffsetField(MPT, Inheritance))
NonVirtualBaseAdjustment = Builder.CreateExtractValue(MemPtr, I++);
- if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance))
+ if (inheritanceModelHasVBPtrOffsetField(Inheritance))
VBPtrOffset = Builder.CreateExtractValue(MemPtr, I++);
- if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
+ if (inheritanceModelHasVBTableOffsetField(Inheritance))
VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(MemPtr, I++);
}
diff --git a/clang/lib/CodeGen/ModuleBuilder.cpp b/clang/lib/CodeGen/ModuleBuilder.cpp
index 4154f6ebe736..01093cf20c18 100644
--- a/clang/lib/CodeGen/ModuleBuilder.cpp
+++ b/clang/lib/CodeGen/ModuleBuilder.cpp
@@ -290,6 +290,10 @@ namespace {
Builder->EmitTentativeDefinition(D);
}
+ void CompleteExternalDeclaration(VarDecl *D) override {
+ Builder->EmitExternalDeclaration(D);
+ }
+
void HandleVTable(CXXRecordDecl *RD) override {
if (Diags.hasErrorOccurred())
return;
diff --git a/clang/lib/CodeGen/SanitizerMetadata.cpp b/clang/lib/CodeGen/SanitizerMetadata.cpp
index ebc9cd5529bc..24ae6c6e362f 100644
--- a/clang/lib/CodeGen/SanitizerMetadata.cpp
+++ b/clang/lib/CodeGen/SanitizerMetadata.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "SanitizerMetadata.h"
#include "CodeGenModule.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/Constants.h"
diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp
index c2c7b8bf653b..682ef18da73b 100644
--- a/clang/lib/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CodeGen/TargetInfo.cpp
@@ -17,10 +17,12 @@
#include "CGCXXABI.h"
#include "CGValue.h"
#include "CodeGenFunction.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/CodeGenOptions.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"
#include "llvm/ADT/Triple.h"
@@ -28,7 +30,7 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/raw_ostream.h"
-#include <algorithm> // std::sort
+#include <algorithm> // std::sort
using namespace clang;
using namespace CodeGen;
@@ -778,6 +780,12 @@ public:
B.addAttribute("wasm-import-name", Attr->getImportName());
Fn->addAttributes(llvm::AttributeList::FunctionIndex, B);
}
+ if (const auto *Attr = FD->getAttr<WebAssemblyExportNameAttr>()) {
+ llvm::Function *Fn = cast<llvm::Function>(GV);
+ llvm::AttrBuilder B;
+ B.addAttribute("wasm-export-name", Attr->getExportName());
+ Fn->addAttributes(llvm::AttributeList::FunctionIndex, B);
+ }
}
if (auto *FD = dyn_cast_or_null<FunctionDecl>(D)) {
@@ -989,11 +997,13 @@ static ABIArgInfo getDirectX86Hva(llvm::Type* T = nullptr) {
/// Similar to llvm::CCState, but for Clang.
struct CCState {
- CCState(unsigned CC) : CC(CC), FreeRegs(0), FreeSSERegs(0) {}
+ CCState(CGFunctionInfo &FI)
+ : IsPreassigned(FI.arg_size()), CC(FI.getCallingConvention()) {}
- unsigned CC;
- unsigned FreeRegs;
- unsigned FreeSSERegs;
+ llvm::SmallBitVector IsPreassigned;
+ unsigned CC = CallingConv::CC_C;
+ unsigned FreeRegs = 0;
+ unsigned FreeSSERegs = 0;
};
enum {
@@ -1064,8 +1074,7 @@ class X86_32ABIInfo : public SwiftABIInfo {
void addFieldToArgStruct(SmallVector<llvm::Type *, 6> &FrameFields,
CharUnits &StackOffset, ABIArgInfo &Info,
QualType Type) const;
- void computeVectorCallArgs(CGFunctionInfo &FI, CCState &State,
- bool &UsedInAlloca) const;
+ void runVectorCallFirstPass(CGFunctionInfo &FI, CCState &State) const;
public:
@@ -1180,6 +1189,10 @@ static void rewriteInputConstraintReferences(unsigned FirstIn,
if (NumDollars % 2 != 0 && Pos < AsmString.size()) {
// We have an operand reference.
size_t DigitStart = Pos;
+ if (AsmString[DigitStart] == '{') {
+ OS << '{';
+ ++DigitStart;
+ }
size_t DigitEnd = AsmString.find_first_not_of("0123456789", DigitStart);
if (DigitEnd == std::string::npos)
DigitEnd = AsmString.size();
@@ -1225,7 +1238,7 @@ void X86_32TargetCodeGenInfo::addReturnRegisterOutputs(
ResultTruncRegTypes.push_back(CoerceTy);
// Coerce the integer by bitcasting the return slot pointer.
- ReturnSlot.setAddress(CGF.Builder.CreateBitCast(ReturnSlot.getAddress(),
+ ReturnSlot.setAddress(CGF.Builder.CreateBitCast(ReturnSlot.getAddress(CGF),
CoerceTy->getPointerTo()));
ResultRegDests.push_back(ReturnSlot);
@@ -1629,9 +1642,38 @@ bool X86_32ABIInfo::shouldPrimitiveUseInReg(QualType Ty, CCState &State) const {
return true;
}
+void X86_32ABIInfo::runVectorCallFirstPass(CGFunctionInfo &FI, CCState &State) const {
+ // Vectorcall x86 works subtly different than in x64, so the format is
+ // a bit different than the x64 version. First, all vector types (not HVAs)
+ // are assigned, with the first 6 ending up in the [XYZ]MM0-5 registers.
+ // This differs from the x64 implementation, where the first 6 by INDEX get
+ // registers.
+ // In the second pass over the arguments, HVAs are passed in the remaining
+ // vector registers if possible, or indirectly by address. The address will be
+ // passed in ECX/EDX if available. Any other arguments are passed according to
+ // the usual fastcall rules.
+ MutableArrayRef<CGFunctionInfoArgInfo> Args = FI.arguments();
+ for (int I = 0, E = Args.size(); I < E; ++I) {
+ const Type *Base = nullptr;
+ uint64_t NumElts = 0;
+ const QualType &Ty = Args[I].type;
+ if ((Ty->isVectorType() || Ty->isBuiltinType()) &&
+ isHomogeneousAggregate(Ty, Base, NumElts)) {
+ if (State.FreeSSERegs >= NumElts) {
+ State.FreeSSERegs -= NumElts;
+ Args[I].info = ABIArgInfo::getDirect();
+ State.IsPreassigned.set(I);
+ }
+ }
+ }
+}
+
ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
CCState &State) const {
// FIXME: Set alignment on indirect arguments.
+ bool IsFastCall = State.CC == llvm::CallingConv::X86_FastCall;
+ bool IsRegCall = State.CC == llvm::CallingConv::X86_RegCall;
+ bool IsVectorCall = State.CC == llvm::CallingConv::X86_VectorCall;
Ty = useFirstFieldIfTransparentUnion(Ty);
@@ -1651,11 +1693,16 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
// to other targets.
const Type *Base = nullptr;
uint64_t NumElts = 0;
- if (State.CC == llvm::CallingConv::X86_RegCall &&
+ if ((IsRegCall || IsVectorCall) &&
isHomogeneousAggregate(Ty, Base, NumElts)) {
-
if (State.FreeSSERegs >= NumElts) {
State.FreeSSERegs -= NumElts;
+
+ // Vectorcall passes HVAs directly and does not flatten them, but regcall
+ // does.
+ if (IsVectorCall)
+ return getDirectX86Hva();
+
if (Ty->isBuiltinType() || Ty->isVectorType())
return ABIArgInfo::getDirect();
return ABIArgInfo::getExpand();
@@ -1697,10 +1744,7 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
if (getContext().getTypeSize(Ty) <= 4 * 32 &&
(!IsMCUABI || State.FreeRegs == 0) && canExpandIndirectArgument(Ty))
return ABIArgInfo::getExpandWithPadding(
- State.CC == llvm::CallingConv::X86_FastCall ||
- State.CC == llvm::CallingConv::X86_VectorCall ||
- State.CC == llvm::CallingConv::X86_RegCall,
- PaddingType);
+ IsFastCall || IsVectorCall || IsRegCall, PaddingType);
return getIndirectResult(Ty, true, State);
}
@@ -1739,60 +1783,8 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
return ABIArgInfo::getDirect();
}
-void X86_32ABIInfo::computeVectorCallArgs(CGFunctionInfo &FI, CCState &State,
- bool &UsedInAlloca) const {
- // Vectorcall x86 works subtly different than in x64, so the format is
- // a bit different than the x64 version. First, all vector types (not HVAs)
- // are assigned, with the first 6 ending up in the YMM0-5 or XMM0-5 registers.
- // This differs from the x64 implementation, where the first 6 by INDEX get
- // registers.
- // After that, integers AND HVAs are assigned Left to Right in the same pass.
- // Integers are passed as ECX/EDX if one is available (in order). HVAs will
- // first take up the remaining YMM/XMM registers. If insufficient registers
- // remain but an integer register (ECX/EDX) is available, it will be passed
- // in that, else, on the stack.
- for (auto &I : FI.arguments()) {
- // First pass do all the vector types.
- const Type *Base = nullptr;
- uint64_t NumElts = 0;
- const QualType& Ty = I.type;
- if ((Ty->isVectorType() || Ty->isBuiltinType()) &&
- isHomogeneousAggregate(Ty, Base, NumElts)) {
- if (State.FreeSSERegs >= NumElts) {
- State.FreeSSERegs -= NumElts;
- I.info = ABIArgInfo::getDirect();
- } else {
- I.info = classifyArgumentType(Ty, State);
- }
- UsedInAlloca |= (I.info.getKind() == ABIArgInfo::InAlloca);
- }
- }
-
- for (auto &I : FI.arguments()) {
- // Second pass, do the rest!
- const Type *Base = nullptr;
- uint64_t NumElts = 0;
- const QualType& Ty = I.type;
- bool IsHva = isHomogeneousAggregate(Ty, Base, NumElts);
-
- if (IsHva && !Ty->isVectorType() && !Ty->isBuiltinType()) {
- // Assign true HVAs (non vector/native FP types).
- if (State.FreeSSERegs >= NumElts) {
- State.FreeSSERegs -= NumElts;
- I.info = getDirectX86Hva();
- } else {
- I.info = getIndirectResult(Ty, /*ByVal=*/false, State);
- }
- } else if (!IsHva) {
- // Assign all Non-HVAs, so this will exclude Vector/FP args.
- I.info = classifyArgumentType(Ty, State);
- UsedInAlloca |= (I.info.getKind() == ABIArgInfo::InAlloca);
- }
- }
-}
-
void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const {
- CCState State(FI.getCallingConvention());
+ CCState State(FI);
if (IsMCUABI)
State.FreeRegs = 3;
else if (State.CC == llvm::CallingConv::X86_FastCall)
@@ -1824,15 +1816,20 @@ void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const {
if (FI.isChainCall())
++State.FreeRegs;
+ // For vectorcall, do a first pass over the arguments, assigning FP and vector
+ // arguments to XMM registers as available.
+ if (State.CC == llvm::CallingConv::X86_VectorCall)
+ runVectorCallFirstPass(FI, State);
+
bool UsedInAlloca = false;
- if (State.CC == llvm::CallingConv::X86_VectorCall) {
- computeVectorCallArgs(FI, State, UsedInAlloca);
- } else {
- // If not vectorcall, revert to normal behavior.
- for (auto &I : FI.arguments()) {
- I.info = classifyArgumentType(I.type, State);
- UsedInAlloca |= (I.info.getKind() == ABIArgInfo::InAlloca);
- }
+ MutableArrayRef<CGFunctionInfoArgInfo> Args = FI.arguments();
+ for (int I = 0, E = Args.size(); I < E; ++I) {
+ // Skip arguments that have already been assigned.
+ if (State.IsPreassigned.test(I))
+ continue;
+
+ Args[I].info = classifyArgumentType(Args[I].type, State);
+ UsedInAlloca |= (Args[I].info.getKind() == ABIArgInfo::InAlloca);
}
// If we needed to use inalloca for any argument, do a second pass and rewrite
@@ -4991,7 +4988,7 @@ private:
ABIKind getABIKind() const { return Kind; }
bool isDarwinPCS() const { return Kind == DarwinPCS; }
- ABIArgInfo classifyReturnType(QualType RetTy) const;
+ ABIArgInfo classifyReturnType(QualType RetTy, bool IsVariadic) const;
ABIArgInfo classifyArgumentType(QualType RetTy) const;
bool isHomogeneousAggregateBaseType(QualType Ty) const override;
bool isHomogeneousAggregateSmallEnough(const Type *Ty,
@@ -5001,7 +4998,8 @@ private:
void computeInfo(CGFunctionInfo &FI) const override {
if (!::classifyReturnType(getCXXABI(), FI, *this))
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ FI.getReturnInfo() =
+ classifyReturnType(FI.getReturnType(), FI.isVariadic());
for (auto &it : FI.arguments())
it.info = classifyArgumentType(it.type);
@@ -5055,23 +5053,38 @@ public:
const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
if (!FD)
return;
- llvm::Function *Fn = cast<llvm::Function>(GV);
- auto Kind = CGM.getCodeGenOpts().getSignReturnAddress();
- if (Kind != CodeGenOptions::SignReturnAddressScope::None) {
+ CodeGenOptions::SignReturnAddressScope Scope = CGM.getCodeGenOpts().getSignReturnAddress();
+ CodeGenOptions::SignReturnAddressKeyValue Key = CGM.getCodeGenOpts().getSignReturnAddressKey();
+ bool BranchTargetEnforcement = CGM.getCodeGenOpts().BranchTargetEnforcement;
+ if (const auto *TA = FD->getAttr<TargetAttr>()) {
+ ParsedTargetAttr Attr = TA->parse();
+ if (!Attr.BranchProtection.empty()) {
+ TargetInfo::BranchProtectionInfo BPI;
+ StringRef Error;
+ (void)CGM.getTarget().validateBranchProtection(Attr.BranchProtection,
+ BPI, Error);
+ assert(Error.empty());
+ Scope = BPI.SignReturnAddr;
+ Key = BPI.SignKey;
+ BranchTargetEnforcement = BPI.BranchTargetEnforcement;
+ }
+ }
+
+ auto *Fn = cast<llvm::Function>(GV);
+ if (Scope != CodeGenOptions::SignReturnAddressScope::None) {
Fn->addFnAttr("sign-return-address",
- Kind == CodeGenOptions::SignReturnAddressScope::All
+ Scope == CodeGenOptions::SignReturnAddressScope::All
? "all"
: "non-leaf");
- auto Key = CGM.getCodeGenOpts().getSignReturnAddressKey();
Fn->addFnAttr("sign-return-address-key",
Key == CodeGenOptions::SignReturnAddressKeyValue::AKey
? "a_key"
: "b_key");
}
- if (CGM.getCodeGenOpts().BranchTargetEnforcement)
+ if (BranchTargetEnforcement)
Fn->addFnAttr("branch-target-enforcement");
}
};
@@ -5184,23 +5197,24 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty) const {
Alignment = getContext().getTypeUnadjustedAlign(Ty);
Alignment = Alignment < 128 ? 64 : 128;
} else {
- Alignment = getContext().getTypeAlign(Ty);
+ Alignment = std::max(getContext().getTypeAlign(Ty),
+ (unsigned)getTarget().getPointerWidth(0));
}
- Size = llvm::alignTo(Size, 64); // round up to multiple of 8 bytes
+ Size = llvm::alignTo(Size, Alignment);
// We use a pair of i64 for 16-byte aggregate with 8-byte alignment.
// For aggregates with 16-byte alignment, we use i128.
- if (Alignment < 128 && Size == 128) {
- llvm::Type *BaseTy = llvm::Type::getInt64Ty(getVMContext());
- return ABIArgInfo::getDirect(llvm::ArrayType::get(BaseTy, Size / 64));
- }
- return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size));
+ llvm::Type *BaseTy = llvm::Type::getIntNTy(getVMContext(), Alignment);
+ return ABIArgInfo::getDirect(
+ Size == Alignment ? BaseTy
+ : llvm::ArrayType::get(BaseTy, Size / Alignment));
}
return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
}
-ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy) const {
+ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy,
+ bool IsVariadic) const {
if (RetTy->isVoidType())
return ABIArgInfo::getIgnore();
@@ -5224,7 +5238,9 @@ ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy) const {
const Type *Base = nullptr;
uint64_t Members = 0;
- if (isHomogeneousAggregate(RetTy, Base, Members))
+ if (isHomogeneousAggregate(RetTy, Base, Members) &&
+ !(getTarget().getTriple().getArch() == llvm::Triple::aarch64_32 &&
+ IsVariadic))
// Homogeneous Floating-point Aggregates (HFAs) are returned directly.
return ABIArgInfo::getDirect();
@@ -5259,6 +5275,14 @@ bool AArch64ABIInfo::isIllegalVectorType(QualType Ty) const {
// NumElements should be power of 2.
if (!llvm::isPowerOf2_32(NumElements))
return true;
+
+ // arm64_32 has to be compatible with the ARM logic here, which allows huge
+ // vectors for some reason.
+ llvm::Triple Triple = getTarget().getTriple();
+ if (Triple.getArch() == llvm::Triple::aarch64_32 &&
+ Triple.isOSBinFormatMachO())
+ return Size <= 32;
+
return Size != 64 && (Size != 128 || NumElements == 1);
}
return false;
@@ -5550,7 +5574,8 @@ Address AArch64ABIInfo::EmitDarwinVAArg(Address VAListAddr, QualType Ty,
if (!isAggregateTypeForABI(Ty) && !isIllegalVectorType(Ty))
return EmitVAArgInstr(CGF, VAListAddr, Ty, ABIArgInfo::getDirect());
- CharUnits SlotSize = CharUnits::fromQuantity(8);
+ uint64_t PointerSize = getTarget().getPointerWidth(0) / 8;
+ CharUnits SlotSize = CharUnits::fromQuantity(PointerSize);
// Empty records are ignored for parameter passing purposes.
if (isEmptyRecord(getContext(), Ty, true)) {
@@ -7555,7 +7580,7 @@ public:
bool shouldUseInReg(QualType Ty, CCState &State) const;
void computeInfo(CGFunctionInfo &FI) const override {
- CCState State(FI.getCallingConvention());
+ CCState State(FI);
// Lanai uses 4 registers to pass arguments unless the function has the
// regparm attribute set.
if (FI.getHasRegParm()) {
@@ -7685,6 +7710,42 @@ private:
bool isHomogeneousAggregateSmallEnough(const Type *Base,
uint64_t Members) const override;
+ // Coerce HIP pointer arguments from generic pointers to global ones.
+ llvm::Type *coerceKernelArgumentType(llvm::Type *Ty, unsigned FromAS,
+ unsigned ToAS) const {
+ // Structure types.
+ if (auto STy = dyn_cast<llvm::StructType>(Ty)) {
+ SmallVector<llvm::Type *, 8> EltTys;
+ bool Changed = false;
+ for (auto T : STy->elements()) {
+ auto NT = coerceKernelArgumentType(T, FromAS, ToAS);
+ EltTys.push_back(NT);
+ Changed |= (NT != T);
+ }
+ // Skip if there is no change in element types.
+ if (!Changed)
+ return STy;
+ if (STy->hasName())
+ return llvm::StructType::create(
+ EltTys, (STy->getName() + ".coerce").str(), STy->isPacked());
+ return llvm::StructType::get(getVMContext(), EltTys, STy->isPacked());
+ }
+ // Arrary types.
+ if (auto ATy = dyn_cast<llvm::ArrayType>(Ty)) {
+ auto T = ATy->getElementType();
+ auto NT = coerceKernelArgumentType(T, FromAS, ToAS);
+ // Skip if there is no change in that element type.
+ if (NT == T)
+ return ATy;
+ return llvm::ArrayType::get(NT, ATy->getNumElements());
+ }
+ // Single value types.
+ if (Ty->isPointerTy() && Ty->getPointerAddressSpace() == FromAS)
+ return llvm::PointerType::get(
+ cast<llvm::PointerType>(Ty)->getElementType(), ToAS);
+ return Ty;
+ }
+
public:
explicit AMDGPUABIInfo(CodeGen::CodeGenTypes &CGT) :
DefaultABIInfo(CGT) {}
@@ -7694,6 +7755,8 @@ public:
ABIArgInfo classifyArgumentType(QualType Ty, unsigned &NumRegsLeft) const;
void computeInfo(CGFunctionInfo &FI) const override;
+ Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
+ QualType Ty) const override;
};
bool AMDGPUABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
@@ -7757,6 +7820,11 @@ void AMDGPUABIInfo::computeInfo(CGFunctionInfo &FI) const {
}
}
+Address AMDGPUABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
+ QualType Ty) const {
+ llvm_unreachable("AMDGPU does not support varargs");
+}
+
ABIArgInfo AMDGPUABIInfo::classifyReturnType(QualType RetTy) const {
if (isAggregateTypeForABI(RetTy)) {
// Records with non-trivial destructors/copy-constructors should not be
@@ -7805,14 +7873,22 @@ ABIArgInfo AMDGPUABIInfo::classifyKernelArgumentType(QualType Ty) const {
// TODO: Can we omit empty structs?
- // Coerce single element structs to its element.
+ llvm::Type *LTy = nullptr;
if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
- return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
+ LTy = CGT.ConvertType(QualType(SeltTy, 0));
+
+ if (getContext().getLangOpts().HIP) {
+ if (!LTy)
+ LTy = CGT.ConvertType(Ty);
+ LTy = coerceKernelArgumentType(
+ LTy, /*FromAS=*/getContext().getTargetAddressSpace(LangAS::Default),
+ /*ToAS=*/getContext().getTargetAddressSpace(LangAS::cuda_device));
+ }
// If we set CanBeFlattened to true, CodeGen will expand the struct to its
// individual elements, which confuses the Clover OpenCL backend; therefore we
// have to set it to false here. Other args of getDirect() are just defaults.
- return ABIArgInfo::getDirect(nullptr, 0, nullptr, false);
+ return ABIArgInfo::getDirect(LTy, 0, nullptr, false);
}
ABIArgInfo AMDGPUABIInfo::classifyArgumentType(QualType Ty,
@@ -7982,8 +8058,11 @@ void AMDGPUTargetCodeGenInfo::setTargetAttributes(
} else
assert(Max == 0 && "Max must be zero");
} else if (IsOpenCLKernel || IsHIPKernel) {
- // By default, restrict the maximum size to 256.
- F->addFnAttr("amdgpu-flat-work-group-size", "1,256");
+ // By default, restrict the maximum size to a value specified by
+ // --gpu-max-threads-per-block=n or its default value.
+ std::string AttrVal =
+ std::string("1,") + llvm::utostr(M.getLangOpts().GPUMaxThreadsPerBlock);
+ F->addFnAttr("amdgpu-flat-work-group-size", AttrVal);
}
if (const auto *Attr = FD->getAttr<AMDGPUWavesPerEUAttr>()) {
@@ -8477,7 +8556,7 @@ private:
}
void computeInfo(CGFunctionInfo &FI) const override {
- CCState State(FI.getCallingConvention());
+ CCState State(FI);
// ARC uses 8 registers to pass arguments.
State.FreeRegs = 8;
@@ -9284,11 +9363,21 @@ void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const {
FI.getReturnInfo() = classifyReturnType(RetTy);
// IsRetIndirect is true if classifyArgumentType indicated the value should
- // be passed indirect or if the type size is greater than 2*xlen. e.g. fp128
- // is passed direct in LLVM IR, relying on the backend lowering code to
- // rewrite the argument list and pass indirectly on RV32.
- bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect ||
- getContext().getTypeSize(RetTy) > (2 * XLen);
+ // be passed indirect, or if the type size is a scalar greater than 2*XLen
+ // and not a complex type with elements <= FLen. e.g. fp128 is passed direct
+ // in LLVM IR, relying on the backend lowering code to rewrite the argument
+ // list and pass indirectly on RV32.
+ bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect;
+ if (!IsRetIndirect && RetTy->isScalarType() &&
+ getContext().getTypeSize(RetTy) > (2 * XLen)) {
+ if (RetTy->isComplexType() && FLen) {
+ QualType EltTy = RetTy->getAs<ComplexType>()->getElementType();
+ IsRetIndirect = getContext().getTypeSize(EltTy) > FLen;
+ } else {
+ // This is a normal scalar > 2*XLen, such as fp128 on RV32.
+ IsRetIndirect = true;
+ }
+ }
// 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
@@ -9722,6 +9811,7 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
return SetCGInfo(new AVRTargetCodeGenInfo(Types));
case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_32:
case llvm::Triple::aarch64_be: {
AArch64ABIInfo::ABIKind Kind = AArch64ABIInfo::AAPCS;
if (getTarget().getABI() == "darwinpcs")
diff --git a/clang/lib/Driver/Distro.cpp b/clang/lib/Driver/Distro.cpp
index f2a3074d1e70..06707fefc9d0 100644
--- a/clang/lib/Driver/Distro.cpp
+++ b/clang/lib/Driver/Distro.cpp
@@ -13,11 +13,28 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/ADT/Triple.h"
using namespace clang::driver;
using namespace clang;
-static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) {
+static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS,
+ const llvm::Triple &TargetOrHost) {
+ // If we don't target Linux, no need to check the distro. This saves a few
+ // OS calls.
+ if (!TargetOrHost.isOSLinux())
+ return Distro::UnknownDistro;
+
+ // If the host is not running Linux, and we're backed by a real file system,
+ // no need to check the distro. This is the case where someone is
+ // cross-compiling from BSD or Windows to Linux, and it would be meaningless
+ // to try to figure out the "distro" of the non-Linux host.
+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> RealFS =
+ llvm::vfs::getRealFileSystem();
+ llvm::Triple HostTriple(llvm::sys::getProcessTriple());
+ if (!HostTriple.isOSLinux() && &VFS == RealFS.get())
+ return Distro::UnknownDistro;
+
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
VFS.getBufferForFile("/etc/lsb-release");
if (File) {
@@ -52,6 +69,7 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) {
.Case("cosmic", Distro::UbuntuCosmic)
.Case("disco", Distro::UbuntuDisco)
.Case("eoan", Distro::UbuntuEoan)
+ .Case("focal", Distro::UbuntuFocal)
.Default(Distro::UnknownDistro);
if (Version != Distro::UnknownDistro)
return Version;
@@ -148,4 +166,5 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) {
return Distro::UnknownDistro;
}
-Distro::Distro(llvm::vfs::FileSystem &VFS) : DistroVal(DetectDistro(VFS)) {}
+Distro::Distro(llvm::vfs::FileSystem &VFS, const llvm::Triple &TargetOrHost)
+ : DistroVal(DetectDistro(VFS, TargetOrHost)) {}
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index f6016b43b692..e718b8366df0 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -8,6 +8,7 @@
#include "clang/Driver/Driver.h"
#include "InputInfo.h"
+#include "ToolChains/AIX.h"
#include "ToolChains/AMDGPU.h"
#include "ToolChains/AVR.h"
#include "ToolChains/Ananas.h"
@@ -177,6 +178,7 @@ void Driver::setDriverModeFromOption(StringRef Opt) {
.Case("g++", GXXMode)
.Case("cpp", CPPMode)
.Case("cl", CLMode)
+ .Case("flang", FlangMode)
.Default(None))
Mode = *M;
else
@@ -290,10 +292,6 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL,
(PhaseArg = DAL.getLastArg(options::OPT_emit_ast))) {
FinalPhase = phases::Compile;
- // clang interface stubs
- } else if ((PhaseArg = DAL.getLastArg(options::OPT_emit_interface_stubs))) {
- FinalPhase = phases::IfsMerge;
-
// -S only runs up to the backend.
} else if ((PhaseArg = DAL.getLastArg(options::OPT_S))) {
FinalPhase = phases::Backend;
@@ -539,6 +537,17 @@ static llvm::Triple computeTargetTriple(const Driver &D,
}
}
+ // 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_lower("rv32"))
+ Target.setArch(llvm::Triple::riscv32);
+ else if (ArchName.startswith_lower("rv64"))
+ Target.setArch(llvm::Triple::riscv64);
+ }
+
return Target;
}
@@ -735,7 +744,7 @@ static bool searchForFile(SmallVectorImpl<char> &FilePath,
ArrayRef<std::string> Dirs,
StringRef FileName) {
SmallString<128> WPath;
- for (const StringRef &Dir : Dirs) {
+ for (const std::string &Dir : Dirs) {
if (Dir.empty())
continue;
WPath.clear();
@@ -1981,8 +1990,9 @@ void Driver::BuildUniversalActions(Compilation &C, const ToolChain &TC,
// Handle debug info queries.
Arg *A = Args.getLastArg(options::OPT_g_Group);
- if (A && !A->getOption().matches(options::OPT_g0) &&
- !A->getOption().matches(options::OPT_gstabs) &&
+ bool enablesDebugInfo = A && !A->getOption().matches(options::OPT_g0) &&
+ !A->getOption().matches(options::OPT_gstabs);
+ if ((enablesDebugInfo || willEmitRemarks(Args)) &&
ContainsCompileOrAssembleAction(Actions.back())) {
// Add a 'dsymutil' step if necessary, when debug info is enabled and we
@@ -3489,6 +3499,68 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
Actions.push_back(
C.MakeAction<IfsMergeJobAction>(MergerInputs, types::TY_Image));
+ if (Args.hasArg(options::OPT_emit_interface_stubs)) {
+ llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PhaseList;
+ if (Args.hasArg(options::OPT_c)) {
+ llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> CompilePhaseList;
+ types::getCompilationPhases(types::TY_IFS_CPP, CompilePhaseList);
+ llvm::copy_if(CompilePhaseList, std::back_inserter(PhaseList),
+ [&](phases::ID Phase) { return Phase <= phases::Compile; });
+ } else {
+ types::getCompilationPhases(types::TY_IFS_CPP, PhaseList);
+ }
+
+ ActionList MergerInputs;
+
+ for (auto &I : Inputs) {
+ types::ID InputType = I.first;
+ const Arg *InputArg = I.second;
+
+ // Currently clang and the llvm assembler do not support generating symbol
+ // stubs from assembly, so we skip the input on asm files. For ifs files
+ // we rely on the normal pipeline setup in the pipeline setup code above.
+ if (InputType == types::TY_IFS || InputType == types::TY_PP_Asm ||
+ InputType == types::TY_Asm)
+ continue;
+
+ Action *Current = C.MakeAction<InputAction>(*InputArg, InputType);
+
+ for (auto Phase : PhaseList) {
+ switch (Phase) {
+ default:
+ llvm_unreachable(
+ "IFS Pipeline can only consist of Compile followed by IfsMerge.");
+ case phases::Compile: {
+ // Only IfsMerge (llvm-ifs) can handle .o files by looking for ifs
+ // files where the .o file is located. The compile action can not
+ // handle this.
+ if (InputType == types::TY_Object)
+ break;
+
+ Current = C.MakeAction<CompileJobAction>(Current, types::TY_IFS_CPP);
+ break;
+ }
+ case phases::IfsMerge: {
+ assert(Phase == PhaseList.back() &&
+ "merging must be final compilation step.");
+ MergerInputs.push_back(Current);
+ Current = nullptr;
+ break;
+ }
+ }
+ }
+
+ // If we ended with something, add to the output list.
+ if (Current)
+ Actions.push_back(Current);
+ }
+
+ // Add an interface stubs merge action if necessary.
+ if (!MergerInputs.empty())
+ Actions.push_back(
+ C.MakeAction<IfsMergeJobAction>(MergerInputs, types::TY_Image));
+ }
+
// If --print-supported-cpus, -mcpu=? or -mtune=? is specified, build a custom
// Compile phase that prints out supported cpu models and quits.
if (Arg *A = Args.getLastArg(options::OPT_print_supported_cpus)) {
@@ -3590,8 +3662,6 @@ Action *Driver::ConstructPhaseAction(
return C.MakeAction<CompileJobAction>(Input, types::TY_ModuleFile);
if (Args.hasArg(options::OPT_verify_pch))
return C.MakeAction<VerifyPCHJobAction>(Input, types::TY_Nothing);
- if (Args.hasArg(options::OPT_emit_interface_stubs))
- return C.MakeAction<CompileJobAction>(Input, types::TY_IFS_CPP);
return C.MakeAction<CompileJobAction>(Input, types::TY_LLVM_BC);
}
case phases::Backend: {
@@ -3620,11 +3690,29 @@ void Driver::BuildJobs(Compilation &C) const {
Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o);
// It is an error to provide a -o option if we are making multiple output
- // files.
+ // files. There are exceptions:
+ //
+ // IfsMergeJob: when generating interface stubs enabled we want to be able to
+ // generate the stub file at the same time that we generate the real
+ // library/a.out. So when a .o, .so, etc are the output, with clang interface
+ // stubs there will also be a .ifs and .ifso at the same location.
+ //
+ // CompileJob of type TY_IFS_CPP: when generating interface stubs is enabled
+ // and -c is passed, we still want to be able to generate a .ifs file while
+ // we are also generating .o files. So we allow more than one output file in
+ // this case as well.
+ //
if (FinalOutput) {
unsigned NumOutputs = 0;
+ unsigned NumIfsOutputs = 0;
for (const Action *A : C.getActions())
- if (A->getType() != types::TY_Nothing)
+ if (A->getType() != types::TY_Nothing &&
+ !(A->getKind() == Action::IfsMergeJobClass ||
+ (A->getType() == clang::driver::types::TY_IFS_CPP &&
+ A->getKind() == clang::driver::Action::CompileJobClass &&
+ 0 == NumIfsOutputs++) ||
+ (A->getKind() == Action::BindArchClass && A->getInputs().size() &&
+ A->getInputs().front()->getKind() == Action::IfsMergeJobClass)))
++NumOutputs;
if (NumOutputs > 1) {
@@ -4699,6 +4787,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
auto &TC = ToolChains[Target.str()];
if (!TC) {
switch (Target.getOS()) {
+ case llvm::Triple::AIX:
+ TC = std::make_unique<toolchains::AIX>(*this, Target, Args);
+ break;
case llvm::Triple::Haiku:
TC = std::make_unique<toolchains::Haiku>(*this, Target, Args);
break;
@@ -4872,6 +4963,19 @@ bool Driver::ShouldUseClangCompiler(const JobAction &JA) const {
return true;
}
+bool Driver::ShouldUseFlangCompiler(const JobAction &JA) const {
+ // Say "no" if there is not exactly one input of a type flang understands.
+ if (JA.size() != 1 ||
+ !types::isFortran((*JA.input_begin())->getType()))
+ return false;
+
+ // And say "no" if this is not a kind of action flang understands.
+ if (!isa<PreprocessJobAction>(JA) && !isa<CompileJobAction>(JA) && !isa<BackendJobAction>(JA))
+ return false;
+
+ return true;
+}
+
/// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and return the
/// grouped values as integers. Numbers which are not provided are set to 0.
///
@@ -4957,3 +5061,26 @@ Driver::getIncludeExcludeOptionFlagMasks(bool IsClCompatMode) const {
bool clang::driver::isOptimizationLevelFast(const ArgList &Args) {
return Args.hasFlag(options::OPT_Ofast, options::OPT_O_Group, false);
}
+
+bool clang::driver::willEmitRemarks(const ArgList &Args) {
+ // -fsave-optimization-record enables it.
+ if (Args.hasFlag(options::OPT_fsave_optimization_record,
+ options::OPT_fno_save_optimization_record, false))
+ return true;
+
+ // -fsave-optimization-record=<format> enables it as well.
+ if (Args.hasFlag(options::OPT_fsave_optimization_record_EQ,
+ options::OPT_fno_save_optimization_record, false))
+ return true;
+
+ // -foptimization-record-file alone enables it too.
+ if (Args.hasFlag(options::OPT_foptimization_record_file_EQ,
+ options::OPT_fno_save_optimization_record, false))
+ return true;
+
+ // -foptimization-record-passes alone enables it too.
+ if (Args.hasFlag(options::OPT_foptimization_record_passes_EQ,
+ options::OPT_fno_save_optimization_record, false))
+ return true;
+ return false;
+}
diff --git a/clang/lib/Driver/Job.cpp b/clang/lib/Driver/Job.cpp
index 0a95e49694f9..d57c3a1cdbb8 100644
--- a/clang/lib/Driver/Job.cpp
+++ b/clang/lib/Driver/Job.cpp
@@ -19,8 +19,10 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -313,15 +315,46 @@ void Command::setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) {
Environment.push_back(nullptr);
}
-int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
- std::string *ErrMsg, bool *ExecutionFailed) const {
+void Command::PrintFileNames() const {
if (PrintInputFilenames) {
for (const char *Arg : InputFilenames)
llvm::outs() << llvm::sys::path::filename(Arg) << "\n";
llvm::outs().flush();
}
+}
+
+int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
+ std::string *ErrMsg, bool *ExecutionFailed) const {
+ PrintFileNames();
- SmallVector<const char*, 128> Argv;
+ SmallVector<const char *, 128> Argv;
+ if (ResponseFile == nullptr) {
+ Argv.push_back(Executable);
+ Argv.append(Arguments.begin(), Arguments.end());
+ Argv.push_back(nullptr);
+ } else {
+ // If the command is too large, we need to put arguments in a response file.
+ std::string RespContents;
+ llvm::raw_string_ostream SS(RespContents);
+
+ // Write file contents and build the Argv vector
+ writeResponseFile(SS);
+ buildArgvForResponseFile(Argv);
+ Argv.push_back(nullptr);
+ SS.flush();
+
+ // Save the response file in the appropriate encoding
+ if (std::error_code EC = writeFileWithEncoding(
+ ResponseFile, RespContents, Creator.getResponseFileEncoding())) {
+ if (ErrMsg)
+ *ErrMsg = EC.message();
+ if (ExecutionFailed)
+ *ExecutionFailed = true;
+ // Return -1 by convention (see llvm/include/llvm/Support/Program.h) to
+ // indicate the requested executable cannot be started.
+ return -1;
+ }
+ }
Optional<ArrayRef<StringRef>> Env;
std::vector<StringRef> ArgvVectorStorage;
@@ -332,42 +365,51 @@ int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
Env = makeArrayRef(ArgvVectorStorage);
}
- if (ResponseFile == nullptr) {
- Argv.push_back(Executable);
- Argv.append(Arguments.begin(), Arguments.end());
- Argv.push_back(nullptr);
+ auto Args = llvm::toStringRefArray(Argv.data());
+ return llvm::sys::ExecuteAndWait(Executable, Args, Env, Redirects,
+ /*secondsToWait*/ 0,
+ /*memoryLimit*/ 0, ErrMsg, ExecutionFailed);
+}
- auto Args = llvm::toStringRefArray(Argv.data());
- return llvm::sys::ExecuteAndWait(
- Executable, Args, Env, Redirects, /*secondsToWait*/ 0,
- /*memoryLimit*/ 0, ErrMsg, ExecutionFailed);
- }
+void CC1Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
+ CrashReportInfo *CrashInfo) const {
+ OS << " (in-process)";
+ Command::Print(OS, Terminator, Quote, CrashInfo);
+}
- // We need to put arguments in a response file (command is too large)
- // Open stream to store the response file contents
- std::string RespContents;
- llvm::raw_string_ostream SS(RespContents);
+int CC1Command::Execute(ArrayRef<llvm::Optional<StringRef>> /*Redirects*/,
+ std::string *ErrMsg, bool *ExecutionFailed) const {
+ PrintFileNames();
- // Write file contents and build the Argv vector
- writeResponseFile(SS);
- buildArgvForResponseFile(Argv);
+ SmallVector<const char *, 128> Argv;
+ Argv.push_back(getExecutable());
+ Argv.append(getArguments().begin(), getArguments().end());
Argv.push_back(nullptr);
- SS.flush();
- // Save the response file in the appropriate encoding
- if (std::error_code EC = writeFileWithEncoding(
- ResponseFile, RespContents, Creator.getResponseFileEncoding())) {
- if (ErrMsg)
- *ErrMsg = EC.message();
- if (ExecutionFailed)
- *ExecutionFailed = true;
- return -1;
+ // This flag simply indicates that the program couldn't start, which isn't
+ // applicable here.
+ if (ExecutionFailed)
+ *ExecutionFailed = false;
+
+ llvm::CrashRecoveryContext CRC;
+ CRC.DumpStackAndCleanupOnFailure = true;
+
+ const void *PrettyState = llvm::SavePrettyStackState();
+ const Driver &D = getCreator().getToolChain().getDriver();
+
+ int R = 0;
+ // Enter ExecuteCC1Tool() instead of starting up a new process
+ if (!CRC.RunSafely([&]() { R = D.CC1Main(Argv); })) {
+ llvm::RestorePrettyStackState(PrettyState);
+ return CRC.RetCode;
}
+ return R;
+}
- auto Args = llvm::toStringRefArray(Argv.data());
- return llvm::sys::ExecuteAndWait(Executable, Args, Env, Redirects,
- /*secondsToWait*/ 0,
- /*memoryLimit*/ 0, ErrMsg, ExecutionFailed);
+void CC1Command::setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) {
+ // We don't support set a new environment when calling into ExecuteCC1Tool()
+ llvm_unreachable(
+ "The CC1Command doesn't support changing the environment vars!");
}
FallbackCommand::FallbackCommand(const Action &Source_, const Tool &Creator_,
diff --git a/clang/lib/Driver/OptionUtils.cpp b/clang/lib/Driver/OptionUtils.cpp
new file mode 100644
index 000000000000..1f36ffc03cab
--- /dev/null
+++ b/clang/lib/Driver/OptionUtils.cpp
@@ -0,0 +1,47 @@
+//===--- OptionUtils.cpp - Utilities for command line arguments -----------===//
+//
+// 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/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticDriver.h"
+#include "clang/Driver/OptionUtils.h"
+#include "llvm/Option/ArgList.h"
+
+using namespace clang;
+using namespace llvm::opt;
+
+namespace {
+template <typename IntTy>
+IntTy getLastArgIntValueImpl(const ArgList &Args, OptSpecifier Id,
+ IntTy Default, DiagnosticsEngine *Diags,
+ unsigned Base) {
+ IntTy Res = Default;
+ if (Arg *A = Args.getLastArg(Id)) {
+ if (StringRef(A->getValue()).getAsInteger(Base, Res)) {
+ if (Diags)
+ Diags->Report(diag::err_drv_invalid_int_value)
+ << A->getAsString(Args) << A->getValue();
+ }
+ }
+ return Res;
+}
+} // namespace
+
+namespace clang {
+
+int getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default,
+ DiagnosticsEngine *Diags, unsigned Base) {
+ return getLastArgIntValueImpl<int>(Args, Id, Default, Diags, Base);
+}
+
+uint64_t getLastArgUInt64Value(const ArgList &Args, OptSpecifier Id,
+ uint64_t Default, DiagnosticsEngine *Diags,
+ unsigned Base) {
+ return getLastArgIntValueImpl<uint64_t>(Args, Id, Default, Diags, Base);
+}
+
+} // namespace clang
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index cc6c5e6ef438..ac9a294ee3fa 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -141,7 +141,7 @@ static void addDefaultBlacklists(const Driver &D, SanitizerMask Kinds,
clang::SmallString<64> Path(D.ResourceDir);
llvm::sys::path::append(Path, "share", BL.File);
- if (llvm::sys::fs::exists(Path))
+ if (D.getVFS().exists(Path))
BlacklistFiles.push_back(Path.str());
else if (BL.Mask == SanitizerKind::CFI)
// If cfi_blacklist.txt cannot be found in the resource dir, driver
@@ -557,29 +557,35 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
// Setup blacklist files.
// Add default blacklist from resource directory.
- addDefaultBlacklists(D, Kinds, BlacklistFiles);
+ addDefaultBlacklists(D, Kinds, SystemBlacklistFiles);
// Parse -f(no-)sanitize-blacklist options.
for (const auto *Arg : Args) {
if (Arg->getOption().matches(options::OPT_fsanitize_blacklist)) {
Arg->claim();
std::string BLPath = Arg->getValue();
- if (llvm::sys::fs::exists(BLPath)) {
- BlacklistFiles.push_back(BLPath);
- ExtraDeps.push_back(BLPath);
+ if (D.getVFS().exists(BLPath)) {
+ UserBlacklistFiles.push_back(BLPath);
} else {
D.Diag(clang::diag::err_drv_no_such_file) << BLPath;
}
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_blacklist)) {
Arg->claim();
- BlacklistFiles.clear();
- ExtraDeps.clear();
+ UserBlacklistFiles.clear();
+ SystemBlacklistFiles.clear();
}
}
// Validate blacklists format.
{
std::string BLError;
std::unique_ptr<llvm::SpecialCaseList> SCL(
- llvm::SpecialCaseList::create(BlacklistFiles, BLError));
+ llvm::SpecialCaseList::create(UserBlacklistFiles, D.getVFS(), BLError));
+ if (!SCL.get())
+ D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError;
+ }
+ {
+ std::string BLError;
+ std::unique_ptr<llvm::SpecialCaseList> SCL(llvm::SpecialCaseList::create(
+ SystemBlacklistFiles, D.getVFS(), BLError));
if (!SCL.get())
D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError;
}
@@ -952,15 +958,15 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
CmdArgs.push_back(
Args.MakeArgString("-fsanitize-trap=" + toString(TrapSanitizers)));
- for (const auto &BLPath : BlacklistFiles) {
+ for (const auto &BLPath : UserBlacklistFiles) {
SmallString<64> BlacklistOpt("-fsanitize-blacklist=");
BlacklistOpt += BLPath;
CmdArgs.push_back(Args.MakeArgString(BlacklistOpt));
}
- for (const auto &Dep : ExtraDeps) {
- SmallString<64> ExtraDepOpt("-fdepfile-entry=");
- ExtraDepOpt += Dep;
- CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt));
+ for (const auto &BLPath : SystemBlacklistFiles) {
+ SmallString<64> BlacklistOpt("-fsanitize-system-blacklist=");
+ BlacklistOpt += BLPath;
+ CmdArgs.push_back(Args.MakeArgString(BlacklistOpt));
}
if (MsanTrackOrigins)
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 357a5106ab39..3ebbd30195b3 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -11,6 +11,7 @@
#include "ToolChains/Arch/ARM.h"
#include "ToolChains/Clang.h"
#include "ToolChains/InterfaceStubs.h"
+#include "ToolChains/Flang.h"
#include "clang/Basic/ObjCRuntime.h"
#include "clang/Basic/Sanitizers.h"
#include "clang/Config/config.h"
@@ -67,7 +68,8 @@ static ToolChain::RTTIMode CalculateRTTIMode(const ArgList &Args,
}
// -frtti is default, except for the PS4 CPU.
- return (Triple.isPS4CPU()) ? ToolChain::RM_Disabled : ToolChain::RM_Enabled;
+ return (Triple.isPS4CPU() || Triple.isNVPTX()) ? ToolChain::RM_Disabled
+ : ToolChain::RM_Enabled;
}
ToolChain::ToolChain(const Driver &D, const llvm::Triple &T,
@@ -151,6 +153,7 @@ static const DriverSuffix *FindDriverSuffix(StringRef ProgName, size_t &Pos) {
{"cpp", "--driver-mode=cpp"},
{"cl", "--driver-mode=cl"},
{"++", "--driver-mode=g++"},
+ {"flang", "--driver-mode=flang"},
};
for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i) {
@@ -254,6 +257,12 @@ Tool *ToolChain::getClang() const {
return Clang.get();
}
+Tool *ToolChain::getFlang() const {
+ if (!Flang)
+ Flang.reset(new tools::Flang(*this));
+ return Flang.get();
+}
+
Tool *ToolChain::buildAssembler() const {
return new tools::ClangAs(*this);
}
@@ -493,6 +502,7 @@ bool ToolChain::needsGCovInstrumentation(const llvm::opt::ArgList &Args) {
}
Tool *ToolChain::SelectTool(const JobAction &JA) const {
+ if (D.IsFlangMode() && getDriver().ShouldUseFlangCompiler(JA)) return getFlang();
if (getDriver().ShouldUseClangCompiler(JA)) return getClang();
Action::ActionClass AC = JA.getKind();
if (AC == Action::AssembleJobClass && useIntegratedAs())
@@ -541,7 +551,15 @@ std::string ToolChain::GetLinkerPath() const {
}
types::ID ToolChain::LookupTypeForExtension(StringRef Ext) const {
- return types::lookupTypeForExtension(Ext);
+ types::ID id = types::lookupTypeForExtension(Ext);
+
+ // Flang always runs the preprocessor and has no notion of "preprocessed
+ // fortran". Here, TY_PP_Fortran is coerced to TY_Fortran to avoid treating
+ // them differently.
+ if (D.IsFlangMode() && id == types::TY_PP_Fortran)
+ id = types::TY_Fortran;
+
+ return id;
}
bool ToolChain::HasNativeLLVMSupport() const {
@@ -620,6 +638,8 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
Triple.setArchName("arm64");
return Triple.getTriple();
}
+ case llvm::Triple::aarch64_32:
+ return getTripleString();
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumb:
@@ -831,7 +851,7 @@ void ToolChain::addExternCSystemIncludeIfExists(const ArgList &DriverArgs,
/*static*/ void ToolChain::addSystemIncludes(const ArgList &DriverArgs,
ArgStringList &CC1Args,
ArrayRef<StringRef> Paths) {
- for (const auto Path : Paths) {
+ for (const auto &Path : Paths) {
CC1Args.push_back("-internal-isystem");
CC1Args.push_back(DriverArgs.MakeArgString(Path));
}
diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp
new file mode 100644
index 000000000000..6fbff61f7656
--- /dev/null
+++ b/clang/lib/Driver/ToolChains/AIX.cpp
@@ -0,0 +1,159 @@
+//===--- AIX.cpp - AIX ToolChain Implementations ----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "AIX.h"
+#include "Arch/PPC.h"
+#include "CommonArgs.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Options.h"
+#include "clang/Driver/SanitizerArgs.h"
+#include "llvm/Option/ArgList.h"
+
+using AIX = clang::driver::toolchains::AIX;
+using namespace clang::driver;
+using namespace clang::driver::tools;
+
+using namespace llvm::opt;
+
+void aix::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+
+ const bool IsArch32Bit = getToolChain().getTriple().isArch32Bit();
+ const bool IsArch64Bit = getToolChain().getTriple().isArch64Bit();
+ // Only support 32 and 64 bit.
+ if (!IsArch32Bit && !IsArch64Bit)
+ llvm_unreachable("Unsupported bit width value.");
+
+ // Specify the mode in which the as(1) command operates.
+ if (IsArch32Bit) {
+ CmdArgs.push_back("-a32");
+ } else {
+ // Must be 64-bit, otherwise asserted already.
+ CmdArgs.push_back("-a64");
+ }
+
+ // Accept an undefined symbol as an extern so that an error message is not
+ // displayed. Otherwise, undefined symbols are flagged with error messages.
+ // FIXME: This should be removed when the assembly generation from the
+ // compiler is able to write externs properly.
+ CmdArgs.push_back("-u");
+
+ // Accept any mixture of instructions.
+ // On Power for AIX and Linux, this behaviour matches that of GCC for both the
+ // user-provided assembler source case and the compiler-produced assembler
+ // source case. Yet XL with user-provided assembler source would not add this.
+ CmdArgs.push_back("-many");
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+
+ // Specify assembler output file.
+ assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ }
+
+ // Specify assembler input file.
+ // The system assembler on AIX takes exactly one input file. The driver is
+ // expected to invoke as(1) separately for each assembler source input file.
+ if (Inputs.size() != 1)
+ llvm_unreachable("Invalid number of input files.");
+ const InputInfo &II = Inputs[0];
+ assert((II.isFilename() || II.isNothing()) && "Invalid input.");
+ if (II.isFilename())
+ CmdArgs.push_back(II.getFilename());
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs, const ArgList &Args,
+ const char *LinkingOutput) const {
+ const AIX &ToolChain = static_cast<const AIX &>(getToolChain());
+ ArgStringList CmdArgs;
+
+ const bool IsArch32Bit = ToolChain.getTriple().isArch32Bit();
+ const bool IsArch64Bit = ToolChain.getTriple().isArch64Bit();
+ // Only support 32 and 64 bit.
+ if (!(IsArch32Bit || IsArch64Bit))
+ llvm_unreachable("Unsupported bit width value.");
+
+ // Force static linking when "-static" is present.
+ if (Args.hasArg(options::OPT_static))
+ CmdArgs.push_back("-bnso");
+
+ // Specify linker output file.
+ assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ }
+
+ // Set linking mode (i.e., 32/64-bit) and the address of
+ // text and data sections based on arch bit width.
+ if (IsArch32Bit) {
+ CmdArgs.push_back("-b32");
+ CmdArgs.push_back("-bpT:0x10000000");
+ CmdArgs.push_back("-bpD:0x20000000");
+ } else {
+ // Must be 64-bit, otherwise asserted already.
+ CmdArgs.push_back("-b64");
+ CmdArgs.push_back("-bpT:0x100000000");
+ CmdArgs.push_back("-bpD:0x110000000");
+ }
+
+ auto getCrt0Basename = [&Args, IsArch32Bit] {
+ // Enable gprofiling when "-pg" is specified.
+ if (Args.hasArg(options::OPT_pg))
+ return IsArch32Bit ? "gcrt0.o" : "gcrt0_64.o";
+ // Enable profiling when "-p" is specified.
+ else if (Args.hasArg(options::OPT_p))
+ return IsArch32Bit ? "mcrt0.o" : "mcrt0_64.o";
+ else
+ return IsArch32Bit ? "crt0.o" : "crt0_64.o";
+ };
+
+ if (!Args.hasArg(options::OPT_nostdlib)) {
+ CmdArgs.push_back(
+ Args.MakeArgString(ToolChain.GetFilePath(getCrt0Basename())));
+ }
+
+ // Specify linker input file(s).
+ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
+
+ // Add directory to library search path.
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+ ToolChain.AddFilePathLibArgs(Args, CmdArgs);
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ // Support POSIX threads if "-pthreads" or "-pthread" is present.
+ if (Args.hasArg(options::OPT_pthreads, options::OPT_pthread))
+ CmdArgs.push_back("-lpthreads");
+
+ CmdArgs.push_back("-lc");
+ }
+
+ const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+/// AIX - AIX tool chain which can call as(1) and ld(1) directly.
+AIX::AIX(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
+ : ToolChain(D, Triple, Args) {
+ getFilePaths().push_back(getDriver().SysRoot + "/usr/lib");
+}
+
+auto AIX::buildAssembler() const -> Tool * { return new aix::Assembler(*this); }
+
+auto AIX::buildLinker() const -> Tool * { return new aix::Linker(*this); }
diff --git a/clang/lib/Driver/ToolChains/AIX.h b/clang/lib/Driver/ToolChains/AIX.h
new file mode 100644
index 000000000000..69b948bc0ea8
--- /dev/null
+++ b/clang/lib/Driver/ToolChains/AIX.h
@@ -0,0 +1,75 @@
+//===--- AIX.h - AIX ToolChain Implementations ------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AIX_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AIX_H
+
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+
+/// aix -- Directly call system default assembler and linker.
+namespace aix {
+
+class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
+public:
+ Assembler(const ToolChain &TC) : Tool("aix::Assembler", "assembler", 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;
+};
+
+class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+public:
+ Linker(const ToolChain &TC) : Tool("aix::Linker", "linker", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+} // end namespace aix
+
+} // end namespace tools
+} // end namespace driver
+} // end namespace clang
+
+namespace clang {
+namespace driver {
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY AIX : public ToolChain {
+public:
+ AIX(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+ bool isPICDefault() const override { return true; }
+ bool isPIEDefault() const override { return false; }
+ bool isPICDefaultForced() const override { return true; }
+
+protected:
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AIX_H
diff --git a/clang/lib/Driver/ToolChains/AMDGPU.h b/clang/lib/Driver/ToolChains/AMDGPU.h
index 5585cc534861..f4c78bea5cc9 100644
--- a/clang/lib/Driver/ToolChains/AMDGPU.h
+++ b/clang/lib/Driver/ToolChains/AMDGPU.h
@@ -55,7 +55,7 @@ protected:
public:
AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
- unsigned GetDefaultDwarfVersion() const override { return 5; }
+ unsigned GetDefaultDwarfVersion() const override { return 4; }
bool IsIntegratedAssemblerDefault() const override { return true; }
bool IsMathErrnoDefault() const override { return false; }
diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
index 3a5fe6ddeaed..9c27504dccf5 100644
--- a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
@@ -43,10 +43,11 @@ std::string aarch64::getAArch64TargetCPU(const ArgList &Args,
else if (CPU.size())
return CPU;
- // Make sure we pick "cyclone" if -arch is used or when targetting a Darwin
- // OS.
+ // Make sure we pick the appropriate Apple CPU if -arch is used or when
+ // targetting a Darwin OS.
if (Args.getLastArg(options::OPT_arch) || Triple.isOSDarwin())
- return "cyclone";
+ return Triple.getArch() == llvm::Triple::aarch64_32 ? "apple-s4"
+ : "apple-a7";
return "generic";
}
@@ -139,7 +140,7 @@ getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune,
// Handle CPU name is 'native'.
if (MtuneLowerCase == "native")
MtuneLowerCase = llvm::sys::getHostCPUName();
- if (MtuneLowerCase == "cyclone") {
+ if (MtuneLowerCase == "cyclone" || MtuneLowerCase.find("apple") == 0) {
Features.push_back("+zcm");
Features.push_back("+zcz");
}
diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/clang/lib/Driver/ToolChains/Arch/ARM.cpp
index 68a57310ad40..a1923e731489 100644
--- a/clang/lib/Driver/ToolChains/Arch/ARM.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/ARM.cpp
@@ -63,12 +63,13 @@ static void getARMHWDivFeatures(const Driver &D, const Arg *A,
}
// Handle -mfpu=.
-static void getARMFPUFeatures(const Driver &D, const Arg *A,
- const ArgList &Args, StringRef FPU,
- std::vector<StringRef> &Features) {
+static unsigned getARMFPUFeatures(const Driver &D, const Arg *A,
+ const ArgList &Args, StringRef FPU,
+ std::vector<StringRef> &Features) {
unsigned FPUID = llvm::ARM::parseFPU(FPU);
if (!llvm::ARM::getFPUFeatures(FPUID, Features))
D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
+ return FPUID;
}
// Decode ARM features from string like +[no]featureA+[no]featureB+...
@@ -388,18 +389,20 @@ void arm::getARMTargetFeatures(const ToolChain &TC,
checkARMCPUName(D, CPUArg, Args, CPUName, ArchName,
ExtensionFeatures, Triple);
// Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=.
+ unsigned FPUID = llvm::ARM::FK_INVALID;
const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ);
if (WaFPU) {
if (FPUArg)
D.Diag(clang::diag::warn_drv_unused_argument)
<< FPUArg->getAsString(Args);
- getARMFPUFeatures(D, WaFPU, Args, StringRef(WaFPU->getValue()).substr(6),
- Features);
+ (void)getARMFPUFeatures(D, WaFPU, Args, StringRef(WaFPU->getValue()).substr(6),
+ Features);
} else if (FPUArg) {
- getARMFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features);
+ FPUID = getARMFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features);
} else if (Triple.isAndroid() && getARMSubArchVersionNumber(Triple) >= 7) {
const char *AndroidFPU = "neon";
- if (!llvm::ARM::getFPUFeatures(llvm::ARM::parseFPU(AndroidFPU), Features))
+ FPUID = llvm::ARM::parseFPU(AndroidFPU);
+ if (!llvm::ARM::getFPUFeatures(FPUID, Features))
D.Diag(clang::diag::err_drv_clang_unsupported)
<< std::string("-mfpu=") + AndroidFPU;
}
@@ -454,21 +457,21 @@ fp16_fml_fallthrough:
if (ABI == arm::FloatABI::Soft) {
llvm::ARM::getFPUFeatures(llvm::ARM::FK_NONE, Features);
- // Disable all features relating to hardware FP.
- // FIXME: Disabling fpregs should be enough all by itself, since all
- // the other FP features are dependent on it. However
- // there is currently no easy way to test this in clang, so for
- // now just be explicit and disable all known dependent features
- // as well.
- for (std::string Feature : {
- "vfp2", "vfp2sp",
- "vfp3", "vfp3sp", "vfp3d16", "vfp3d16sp",
- "vfp4", "vfp4sp", "vfp4d16", "vfp4d16sp",
- "fp-armv8", "fp-armv8sp", "fp-armv8d16", "fp-armv8d16sp",
- "fullfp16", "neon", "crypto", "dotprod", "fp16fml",
- "mve", "mve.fp",
- "fp64", "d32", "fpregs"})
- Features.push_back(Args.MakeArgString("-" + Feature));
+ // Disable all features relating to hardware FP, not already disabled by the
+ // above call.
+ Features.insert(Features.end(), {"-neon", "-crypto", "-dotprod", "-fp16fml",
+ "-mve", "-mve.fp", "-fpregs"});
+ } else if (FPUID == llvm::ARM::FK_NONE) {
+ // -mfpu=none is *very* similar to -mfloat-abi=soft, only that it should not
+ // disable MVE-I.
+ Features.insert(Features.end(),
+ {"-neon", "-crypto", "-dotprod", "-fp16fml", "-mve.fp"});
+ // Even though we remove MVE-FP, we still need to check if it was originally
+ // present among the requested extensions, because it implies MVE-I, which
+ // should not be disabled by -mfpu-none.
+ if (!llvm::is_contained(Features, "+mve") &&
+ !llvm::is_contained(Features, "+mve.fp"))
+ Features.emplace_back("-fpregs");
}
// En/disable crc code generation.
diff --git a/clang/lib/Driver/ToolChains/Arch/PPC.cpp b/clang/lib/Driver/ToolChains/Arch/PPC.cpp
index 3e02e57e0f6c..f1baadaebf41 100644
--- a/clang/lib/Driver/ToolChains/Arch/PPC.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/PPC.cpp
@@ -53,10 +53,12 @@ std::string ppc::getPPCTargetCPU(const ArgList &Args) {
.Case("7450", "7450")
.Case("G4+", "g4+")
.Case("750", "750")
+ .Case("8548", "e500")
.Case("970", "970")
.Case("G5", "g5")
.Case("a2", "a2")
.Case("a2q", "a2q")
+ .Case("e500", "e500")
.Case("e500mc", "e500mc")
.Case("e5500", "e5500")
.Case("power3", "pwr3")
@@ -68,6 +70,7 @@ std::string ppc::getPPCTargetCPU(const ArgList &Args) {
.Case("power7", "pwr7")
.Case("power8", "pwr8")
.Case("power9", "pwr9")
+ .Case("future", "future")
.Case("pwr3", "pwr3")
.Case("pwr4", "pwr4")
.Case("pwr5", "pwr5")
@@ -101,6 +104,9 @@ const char *ppc::getPPCAsmModeForCPU(StringRef Name) {
void ppc::getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args,
std::vector<StringRef> &Features) {
+ if (Triple.getSubArch() == llvm::Triple::PPCSubArch_spe)
+ Features.push_back("+spe");
+
handleTargetFeaturesGroup(Args, Features, options::OPT_m_ppc_Features_Group);
ppc::FloatABI FloatABI = ppc::getPPCFloatABI(D, Args);
diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
index 624788a5874e..8c343b8693f3 100644
--- a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
@@ -357,16 +357,75 @@ static bool getArchFeatures(const Driver &D, StringRef MArch,
void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args,
std::vector<StringRef> &Features) {
- llvm::Optional<StringRef> MArch;
- if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
- MArch = A->getValue();
- else if (Triple.getOS() == llvm::Triple::Linux)
- // RISC-V Linux defaults to rv{32,64}gc.
- MArch = Triple.getArch() == llvm::Triple::riscv32 ? "rv32gc" : "rv64gc";
+ StringRef MArch = getRISCVArch(Args, Triple);
- if (MArch.hasValue() && !getArchFeatures(D, *MArch, Features, Args))
+ if (!getArchFeatures(D, MArch, Features, Args))
return;
+ // Handle features corresponding to "-ffixed-X" options
+ if (Args.hasArg(options::OPT_ffixed_x1))
+ Features.push_back("+reserve-x1");
+ if (Args.hasArg(options::OPT_ffixed_x2))
+ Features.push_back("+reserve-x2");
+ if (Args.hasArg(options::OPT_ffixed_x3))
+ Features.push_back("+reserve-x3");
+ if (Args.hasArg(options::OPT_ffixed_x4))
+ Features.push_back("+reserve-x4");
+ if (Args.hasArg(options::OPT_ffixed_x5))
+ Features.push_back("+reserve-x5");
+ if (Args.hasArg(options::OPT_ffixed_x6))
+ Features.push_back("+reserve-x6");
+ if (Args.hasArg(options::OPT_ffixed_x7))
+ Features.push_back("+reserve-x7");
+ if (Args.hasArg(options::OPT_ffixed_x8))
+ Features.push_back("+reserve-x8");
+ if (Args.hasArg(options::OPT_ffixed_x9))
+ Features.push_back("+reserve-x9");
+ if (Args.hasArg(options::OPT_ffixed_x10))
+ Features.push_back("+reserve-x10");
+ if (Args.hasArg(options::OPT_ffixed_x11))
+ Features.push_back("+reserve-x11");
+ if (Args.hasArg(options::OPT_ffixed_x12))
+ Features.push_back("+reserve-x12");
+ if (Args.hasArg(options::OPT_ffixed_x13))
+ Features.push_back("+reserve-x13");
+ if (Args.hasArg(options::OPT_ffixed_x14))
+ Features.push_back("+reserve-x14");
+ if (Args.hasArg(options::OPT_ffixed_x15))
+ Features.push_back("+reserve-x15");
+ if (Args.hasArg(options::OPT_ffixed_x16))
+ Features.push_back("+reserve-x16");
+ if (Args.hasArg(options::OPT_ffixed_x17))
+ Features.push_back("+reserve-x17");
+ if (Args.hasArg(options::OPT_ffixed_x18))
+ Features.push_back("+reserve-x18");
+ if (Args.hasArg(options::OPT_ffixed_x19))
+ Features.push_back("+reserve-x19");
+ if (Args.hasArg(options::OPT_ffixed_x20))
+ Features.push_back("+reserve-x20");
+ if (Args.hasArg(options::OPT_ffixed_x21))
+ Features.push_back("+reserve-x21");
+ if (Args.hasArg(options::OPT_ffixed_x22))
+ Features.push_back("+reserve-x22");
+ if (Args.hasArg(options::OPT_ffixed_x23))
+ Features.push_back("+reserve-x23");
+ if (Args.hasArg(options::OPT_ffixed_x24))
+ Features.push_back("+reserve-x24");
+ if (Args.hasArg(options::OPT_ffixed_x25))
+ Features.push_back("+reserve-x25");
+ if (Args.hasArg(options::OPT_ffixed_x26))
+ Features.push_back("+reserve-x26");
+ if (Args.hasArg(options::OPT_ffixed_x27))
+ Features.push_back("+reserve-x27");
+ if (Args.hasArg(options::OPT_ffixed_x28))
+ Features.push_back("+reserve-x28");
+ if (Args.hasArg(options::OPT_ffixed_x29))
+ Features.push_back("+reserve-x29");
+ if (Args.hasArg(options::OPT_ffixed_x30))
+ Features.push_back("+reserve-x30");
+ if (Args.hasArg(options::OPT_ffixed_x31))
+ Features.push_back("+reserve-x31");
+
// -mrelax is default, unless -mno-relax is specified.
if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, true))
Features.push_back("+relax");
@@ -391,12 +450,132 @@ StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
Triple.getArch() == llvm::Triple::riscv64) &&
"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
+ // defined in config.gcc. This function is based on the logic in GCC 9.2.0. We
+ // deviate from GCC's default only on baremetal targets (UnknownOS) where
+ // neither `-march` nor `-mabi` is specified.
+ //
+ // The logic uses the following, in order:
+ // 1. Explicit choices using `--with-abi=`
+ // 2. A default based on `--with-arch=`, if provided
+ // 3. A default based on the target triple's arch
+ //
+ // The logic in config.gcc is a little circular but it is not inconsistent.
+ //
+ // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
+ // and `-mabi=` respectively instead.
+
+ // 1. If `-mabi=` is specified, use it.
if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
return A->getValue();
- // RISC-V Linux defaults to ilp32d/lp64d
- if (Triple.getOS() == llvm::Triple::Linux)
- return Triple.getArch() == llvm::Triple::riscv32 ? "ilp32d" : "lp64d";
- else
- return Triple.getArch() == llvm::Triple::riscv32 ? "ilp32" : "lp64";
+ // 2. Choose a default based on `-march=`
+ //
+ // rv32g | rv32*d -> ilp32d
+ // rv32e -> ilp32e
+ // rv32* -> ilp32
+ // rv64g | rv64*d -> lp64d
+ // rv64* -> lp64
+ if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
+ StringRef MArch = A->getValue();
+
+ if (MArch.startswith_lower("rv32")) {
+ // FIXME: parse `March` to find `D` extension properly
+ if (MArch.substr(4).contains_lower("d") ||
+ MArch.startswith_lower("rv32g"))
+ return "ilp32d";
+ else if (MArch.startswith_lower("rv32e"))
+ return "ilp32e";
+ else
+ return "ilp32";
+ } else if (MArch.startswith_lower("rv64")) {
+ // FIXME: parse `March` to find `D` extension properly
+ if (MArch.substr(4).contains_lower("d") ||
+ MArch.startswith_lower("rv64g"))
+ return "lp64d";
+ else
+ return "lp64";
+ }
+ }
+
+ // 3. Choose a default based on the 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.getOS() == llvm::Triple::UnknownOS)
+ return "ilp32";
+ else
+ return "ilp32d";
+ } else {
+ if (Triple.getOS() == llvm::Triple::UnknownOS)
+ return "lp64";
+ else
+ return "lp64d";
+ }
+}
+
+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");
+
+ // 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
+ // defined in config.gcc. This function is based on the logic in GCC 9.2.0. We
+ // deviate from GCC's default only on baremetal targets (UnknownOS) where
+ // neither `-march` nor `-mabi` is specified.
+ //
+ // The logic uses the following, in order:
+ // 1. Explicit choices using `--with-arch=`
+ // 2. A default based on `--with-abi=`, if provided
+ // 3. A default based on the target triple's arch
+ //
+ // The logic in config.gcc is a little circular but it is not inconsistent.
+ //
+ // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
+ // and `-mabi=` respectively instead.
+ //
+ // Clang does not yet support MULTILIB_REUSE, so we use `rv{XLEN}imafdc`
+ // instead of `rv{XLEN}gc` though they are (currently) equivalent.
+
+ // 1. If `-march=` is specified, use it.
+ if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
+ return A->getValue();
+
+ // 2. Choose a default based on `-mabi=`
+ //
+ // ilp32e -> rv32e
+ // ilp32 | ilp32f | ilp32d -> rv32imafdc
+ // lp64 | lp64f | lp64d -> rv64imafdc
+ if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
+ StringRef MABI = A->getValue();
+
+ if (MABI.equals_lower("ilp32e"))
+ return "rv32e";
+ else if (MABI.startswith_lower("ilp32"))
+ return "rv32imafdc";
+ else if (MABI.startswith_lower("lp64"))
+ return "rv64imafdc";
+ }
+
+ // 3. Choose a default based on the triple
+ //
+ // 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.getOS() == llvm::Triple::UnknownOS)
+ return "rv32imac";
+ else
+ return "rv32imafdc";
+ } else {
+ if (Triple.getOS() == llvm::Triple::UnknownOS)
+ return "rv64imac";
+ else
+ return "rv64imafdc";
+ }
}
diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.h b/clang/lib/Driver/ToolChains/Arch/RISCV.h
index 10eaf3c897b6..d4a519cdab34 100644
--- a/clang/lib/Driver/ToolChains/Arch/RISCV.h
+++ b/clang/lib/Driver/ToolChains/Arch/RISCV.h
@@ -24,6 +24,8 @@ void getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
std::vector<llvm::StringRef> &Features);
StringRef getRISCVABI(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple);
+StringRef getRISCVArch(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/SystemZ.cpp b/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp
index ca60b85cf8a0..2b77d59fdc66 100644
--- a/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp
@@ -9,15 +9,27 @@
#include "SystemZ.h"
#include "clang/Driver/Options.h"
#include "llvm/Option/ArgList.h"
+#include "llvm/Support/Host.h"
using namespace clang::driver;
using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;
-const char *systemz::getSystemZTargetCPU(const ArgList &Args) {
- if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ))
- return A->getValue();
+std::string systemz::getSystemZTargetCPU(const ArgList &Args) {
+ if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) {
+ llvm::StringRef CPUName = A->getValue();
+
+ if (CPUName == "native") {
+ std::string CPU = llvm::sys::getHostCPUName();
+ if (!CPU.empty() && CPU != "generic")
+ return CPU;
+ else
+ return "";
+ }
+
+ return CPUName;
+ }
return "z10";
}
diff --git a/clang/lib/Driver/ToolChains/Arch/SystemZ.h b/clang/lib/Driver/ToolChains/Arch/SystemZ.h
index 11d77fa01cc8..77dcbc47be5c 100644
--- a/clang/lib/Driver/ToolChains/Arch/SystemZ.h
+++ b/clang/lib/Driver/ToolChains/Arch/SystemZ.h
@@ -11,6 +11,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Option/Option.h"
+#include <string>
#include <vector>
namespace clang {
@@ -18,7 +19,7 @@ namespace driver {
namespace tools {
namespace systemz {
-const char *getSystemZTargetCPU(const llvm::opt::ArgList &Args);
+std::string getSystemZTargetCPU(const llvm::opt::ArgList &Args);
void getSystemZTargetFeatures(const llvm::opt::ArgList &Args,
std::vector<llvm::StringRef> &Features);
diff --git a/clang/lib/Driver/ToolChains/Arch/X86.cpp b/clang/lib/Driver/ToolChains/Arch/X86.cpp
index d2b97bf6ad71..d1e0c8253b79 100644
--- a/clang/lib/Driver/ToolChains/Arch/X86.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/X86.cpp
@@ -63,8 +63,7 @@ const char *x86::getX86TargetCPU(const ArgList &Args,
// Select the default CPU if none was given (or detection failed).
- if (Triple.getArch() != llvm::Triple::x86_64 &&
- Triple.getArch() != llvm::Triple::x86)
+ if (!Triple.isX86())
return nullptr; // This routine is only handling x86 targets.
bool Is64Bit = Triple.getArch() == llvm::Triple::x86_64;
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 55d631733add..9b3055413e9e 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -302,6 +302,96 @@ static void ParseMPreferVectorWidth(const Driver &D, const ArgList &Args,
}
}
+static void getWebAssemblyTargetFeatures(const ArgList &Args,
+ std::vector<StringRef> &Features) {
+ handleTargetFeaturesGroup(Args, Features, options::OPT_m_wasm_Features_Group);
+}
+
+static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple,
+ const ArgList &Args, ArgStringList &CmdArgs,
+ bool ForAS) {
+ const Driver &D = TC.getDriver();
+ std::vector<StringRef> Features;
+ switch (Triple.getArch()) {
+ default:
+ break;
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ mips::getMIPSTargetFeatures(D, Triple, Args, Features);
+ break;
+
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ arm::getARMTargetFeatures(TC, Triple, Args, CmdArgs, Features, ForAS);
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ ppc::getPPCTargetFeatures(D, Triple, Args, Features);
+ break;
+ case llvm::Triple::riscv32:
+ case llvm::Triple::riscv64:
+ riscv::getRISCVTargetFeatures(D, Triple, Args, Features);
+ break;
+ case llvm::Triple::systemz:
+ systemz::getSystemZTargetFeatures(Args, Features);
+ break;
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_32:
+ case llvm::Triple::aarch64_be:
+ aarch64::getAArch64TargetFeatures(D, Triple, Args, Features);
+ break;
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ x86::getX86TargetFeatures(D, Triple, Args, Features);
+ break;
+ case llvm::Triple::hexagon:
+ hexagon::getHexagonTargetFeatures(D, Args, Features);
+ break;
+ case llvm::Triple::wasm32:
+ case llvm::Triple::wasm64:
+ getWebAssemblyTargetFeatures(Args, Features);
+ break;
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcel:
+ case llvm::Triple::sparcv9:
+ sparc::getSparcTargetFeatures(D, Args, Features);
+ break;
+ case llvm::Triple::r600:
+ case llvm::Triple::amdgcn:
+ amdgpu::getAMDGPUTargetFeatures(D, Args, Features);
+ break;
+ case llvm::Triple::msp430:
+ msp430::getMSP430TargetFeatures(D, Args, Features);
+ }
+
+ // Find the last of each feature.
+ llvm::StringMap<unsigned> LastOpt;
+ for (unsigned I = 0, N = Features.size(); I < N; ++I) {
+ StringRef Name = Features[I];
+ assert(Name[0] == '-' || Name[0] == '+');
+ LastOpt[Name.drop_front(1)] = I;
+ }
+
+ for (unsigned I = 0, N = Features.size(); I < N; ++I) {
+ // If this feature was overridden, ignore it.
+ StringRef Name = Features[I];
+ llvm::StringMap<unsigned>::iterator LastI = LastOpt.find(Name.drop_front(1));
+ assert(LastI != LastOpt.end());
+ unsigned Last = LastI->second;
+ if (Last != I)
+ continue;
+
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back(Name.data());
+ }
+}
+
static bool
shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime,
const llvm::Triple &Triple) {
@@ -378,15 +468,20 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType,
CmdArgs.push_back("-fexceptions");
}
-static bool ShouldDisableAutolink(const ArgList &Args, const ToolChain &TC) {
+static bool ShouldEnableAutolink(const ArgList &Args, const ToolChain &TC,
+ const JobAction &JA) {
bool Default = true;
if (TC.getTriple().isOSDarwin()) {
// The native darwin assembler doesn't support the linker_option directives,
// so we disable them if we think the .s file will be passed to it.
Default = TC.useIntegratedAs();
}
- return !Args.hasFlag(options::OPT_fautolink, options::OPT_fno_autolink,
- Default);
+ // The linker_option directives are intended for host compilation.
+ if (JA.isDeviceOffloading(Action::OFK_Cuda) ||
+ JA.isDeviceOffloading(Action::OFK_HIP))
+ Default = false;
+ return Args.hasFlag(options::OPT_fautolink, options::OPT_fno_autolink,
+ Default);
}
static bool ShouldDisableDwarfDirectory(const ArgList &Args,
@@ -443,6 +538,8 @@ static bool useFramePointerForTargetByDefault(const ArgList &Args,
case llvm::Triple::ppc64le:
case llvm::Triple::riscv32:
case llvm::Triple::riscv64:
+ case llvm::Triple::amdgcn:
+ case llvm::Triple::r600:
return !areOptimizationsEnabled(Args);
default:
break;
@@ -506,9 +603,9 @@ getFramePointerKind(const ArgList &Args, const llvm::Triple &Triple) {
bool OmitFP = A && A->getOption().matches(options::OPT_fomit_frame_pointer);
bool NoOmitFP =
A && A->getOption().matches(options::OPT_fno_omit_frame_pointer);
- bool KeepLeaf =
- Args.hasFlag(options::OPT_momit_leaf_frame_pointer,
- options::OPT_mno_omit_leaf_frame_pointer, Triple.isPS4CPU());
+ bool KeepLeaf = Args.hasFlag(options::OPT_momit_leaf_frame_pointer,
+ options::OPT_mno_omit_leaf_frame_pointer,
+ Triple.isAArch64() || Triple.isPS4CPU());
if (NoOmitFP || mustUseNonLeafFramePointerForTarget(Triple) ||
(!OmitFP && useFramePointerForTargetByDefault(Args, Triple))) {
if (KeepLeaf)
@@ -533,16 +630,33 @@ static void addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs,
/// Add a CC1 and CC1AS option to specify the debug file path prefix map.
static void addDebugPrefixMapArg(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs) {
- for (const Arg *A : Args.filtered(options::OPT_fdebug_prefix_map_EQ)) {
+ for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ,
+ options::OPT_fdebug_prefix_map_EQ)) {
StringRef Map = A->getValue();
if (Map.find('=') == StringRef::npos)
- D.Diag(diag::err_drv_invalid_argument_to_fdebug_prefix_map) << Map;
+ D.Diag(diag::err_drv_invalid_argument_to_option)
+ << Map << A->getOption().getName();
else
CmdArgs.push_back(Args.MakeArgString("-fdebug-prefix-map=" + Map));
A->claim();
}
}
+/// Add a CC1 and CC1AS option to specify the macro file path prefix map.
+static void addMacroPrefixMapArg(const Driver &D, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ,
+ options::OPT_fmacro_prefix_map_EQ)) {
+ StringRef Map = A->getValue();
+ if (Map.find('=') == StringRef::npos)
+ D.Diag(diag::err_drv_invalid_argument_to_option)
+ << Map << A->getOption().getName();
+ else
+ CmdArgs.push_back(Args.MakeArgString("-fmacro-prefix-map=" + Map));
+ A->claim();
+ }
+}
+
/// Vectorize at all optimization levels greater than 1 except for -Oz.
/// For -Oz the loop vectorizer is disabled, while the slp vectorizer is
/// enabled.
@@ -802,7 +916,9 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
if ((Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) &&
(EmitCovNotes || EmitCovData) && Output.isFilename()) {
SmallString<128> OutputFilename;
- if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o))
+ if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT__SLASH_Fo))
+ OutputFilename = FinalOutput->getValue();
+ else if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o))
OutputFilename = FinalOutput->getValue();
else
OutputFilename = llvm::sys::path::filename(Output.getBaseInput());
@@ -883,6 +999,9 @@ static void RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs,
case codegenoptions::DebugLineTablesOnly:
CmdArgs.push_back("-debug-info-kind=line-tables-only");
break;
+ case codegenoptions::DebugInfoConstructor:
+ CmdArgs.push_back("-debug-info-kind=constructor");
+ break;
case codegenoptions::LimitedDebugInfo:
CmdArgs.push_back("-debug-info-kind=limited");
break;
@@ -1248,6 +1367,8 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
// For IAMCU add special include arguments.
getToolChain().AddIAMCUIncludeArgs(Args, CmdArgs);
}
+
+ addMacroPrefixMapArg(D, Args, CmdArgs);
}
// FIXME: Move to target hook.
@@ -1257,6 +1378,7 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) {
return true;
case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_32:
case llvm::Triple::aarch64_be:
case llvm::Triple::arm:
case llvm::Triple::armeb:
@@ -1296,6 +1418,116 @@ static bool isNoCommonDefault(const llvm::Triple &Triple) {
}
}
+static bool hasMultipleInvocations(const llvm::Triple &Triple,
+ const ArgList &Args) {
+ // Supported only on Darwin where we invoke the compiler multiple times
+ // followed by an invocation to lipo.
+ if (!Triple.isOSDarwin())
+ return false;
+ // If more than one "-arch <arch>" is specified, we're targeting multiple
+ // architectures resulting in a fat binary.
+ return Args.getAllArgValues(options::OPT_arch).size() > 1;
+}
+
+static bool checkRemarksOptions(const Driver &D, const ArgList &Args,
+ const llvm::Triple &Triple) {
+ // When enabling remarks, we need to error if:
+ // * The remark file is specified but we're targeting multiple architectures,
+ // which means more than one remark file is being generated.
+ bool hasMultipleInvocations = ::hasMultipleInvocations(Triple, Args);
+ bool hasExplicitOutputFile =
+ Args.getLastArg(options::OPT_foptimization_record_file_EQ);
+ if (hasMultipleInvocations && hasExplicitOutputFile) {
+ D.Diag(diag::err_drv_invalid_output_with_multiple_archs)
+ << "-foptimization-record-file";
+ return false;
+ }
+ return true;
+}
+
+static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs,
+ const llvm::Triple &Triple,
+ const InputInfo &Input,
+ const InputInfo &Output, const JobAction &JA) {
+ StringRef Format = "yaml";
+ if (const Arg *A = Args.getLastArg(options::OPT_fsave_optimization_record_EQ))
+ Format = A->getValue();
+
+ CmdArgs.push_back("-opt-record-file");
+
+ const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ);
+ if (A) {
+ CmdArgs.push_back(A->getValue());
+ } else {
+ bool hasMultipleArchs =
+ Triple.isOSDarwin() && // Only supported on Darwin platforms.
+ Args.getAllArgValues(options::OPT_arch).size() > 1;
+
+ SmallString<128> F;
+
+ if (Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) {
+ if (Arg *FinalOutput = Args.getLastArg(options::OPT_o))
+ F = FinalOutput->getValue();
+ } else {
+ if (Format != "yaml" && // For YAML, keep the original behavior.
+ Triple.isOSDarwin() && // Enable this only on darwin, since it's the only platform supporting .dSYM bundles.
+ Output.isFilename())
+ F = Output.getFilename();
+ }
+
+ if (F.empty()) {
+ // Use the input filename.
+ F = llvm::sys::path::stem(Input.getBaseInput());
+
+ // If we're compiling for an offload architecture (i.e. a CUDA device),
+ // we need to make the file name for the device compilation different
+ // from the host compilation.
+ if (!JA.isDeviceOffloading(Action::OFK_None) &&
+ !JA.isDeviceOffloading(Action::OFK_Host)) {
+ llvm::sys::path::replace_extension(F, "");
+ F += Action::GetOffloadingFileNamePrefix(JA.getOffloadingDeviceKind(),
+ Triple.normalize());
+ F += "-";
+ F += JA.getOffloadingArch();
+ }
+ }
+
+ // If we're having more than one "-arch", we should name the files
+ // differently so that every cc1 invocation writes to a different file.
+ // We're doing that by appending "-<arch>" with "<arch>" being the arch
+ // name from the triple.
+ if (hasMultipleArchs) {
+ // First, remember the extension.
+ SmallString<64> OldExtension = llvm::sys::path::extension(F);
+ // then, remove it.
+ llvm::sys::path::replace_extension(F, "");
+ // attach -<arch> to it.
+ F += "-";
+ F += Triple.getArchName();
+ // put back the extension.
+ llvm::sys::path::replace_extension(F, OldExtension);
+ }
+
+ SmallString<32> Extension;
+ Extension += "opt.";
+ Extension += Format;
+
+ llvm::sys::path::replace_extension(F, Extension);
+ CmdArgs.push_back(Args.MakeArgString(F));
+ }
+
+ if (const Arg *A =
+ Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) {
+ CmdArgs.push_back("-opt-record-passes");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ if (!Format.empty()) {
+ CmdArgs.push_back("-opt-record-format");
+ CmdArgs.push_back(Format.data());
+ }
+}
+
namespace {
void RenderARMABI(const llvm::Triple &Triple, const ArgList &Args,
ArgStringList &CmdArgs) {
@@ -1379,6 +1611,7 @@ void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple,
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");
@@ -1432,56 +1665,6 @@ void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple,
}
}
-// Parse -mbranch-protection=<protection>[+<protection>]* where
-// <protection> ::= standard | none | [bti,pac-ret[+b-key,+leaf]*]
-// Returns a triple of (return address signing Scope, signing key, require
-// landing pads)
-static std::tuple<StringRef, StringRef, bool>
-ParseAArch64BranchProtection(const Driver &D, const ArgList &Args,
- const Arg *A) {
- StringRef Scope = "none";
- StringRef Key = "a_key";
- bool IndirectBranches = false;
-
- StringRef Value = A->getValue();
- // This maps onto -mbranch-protection=<scope>+<key>
-
- if (Value.equals("standard")) {
- Scope = "non-leaf";
- Key = "a_key";
- IndirectBranches = true;
-
- } else if (!Value.equals("none")) {
- SmallVector<StringRef, 4> BranchProtection;
- StringRef(A->getValue()).split(BranchProtection, '+');
-
- auto Protection = BranchProtection.begin();
- while (Protection != BranchProtection.end()) {
- if (Protection->equals("bti"))
- IndirectBranches = true;
- else if (Protection->equals("pac-ret")) {
- Scope = "non-leaf";
- while (++Protection != BranchProtection.end()) {
- // Inner loop as "leaf" and "b-key" options must only appear attached
- // to pac-ret.
- if (Protection->equals("leaf"))
- Scope = "all";
- else if (Protection->equals("b-key"))
- Key = "b_key";
- else
- break;
- }
- Protection--;
- } else
- D.Diag(diag::err_invalid_branch_protection)
- << *Protection << A->getAsString(Args);
- Protection++;
- }
- }
-
- return std::make_tuple(Scope, Key, IndirectBranches);
-}
-
namespace {
void RenderAArch64ABI(const llvm::Triple &Triple, const ArgList &Args,
ArgStringList &CmdArgs) {
@@ -1553,9 +1736,16 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
<< Scope << A->getAsString(Args);
Key = "a_key";
IndirectBranches = false;
- } else
- std::tie(Scope, Key, IndirectBranches) =
- ParseAArch64BranchProtection(D, Args, A);
+ } else {
+ StringRef Err;
+ llvm::AArch64::ParsedBranchProtection PBP;
+ if (!llvm::AArch64::parseBranchProtection(A->getValue(), PBP, Err))
+ D.Diag(diag::err_invalid_branch_protection)
+ << Err << A->getAsString(Args);
+ Scope = PBP.Scope;
+ Key = PBP.Key;
+ IndirectBranches = PBP.BranchTargetEnforcement;
+ }
CmdArgs.push_back(
Args.MakeArgString(Twine("-msign-return-address=") + Scope));
@@ -1713,7 +1903,8 @@ void Clang::AddPPCTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
// Select the ABI to use.
const char *ABIName = nullptr;
- if (getToolChain().getTriple().isOSLinux())
+ const llvm::Triple &T = getToolChain().getTriple();
+ if (T.isOSBinFormatELF()) {
switch (getToolChain().getArch()) {
case llvm::Triple::ppc64: {
// When targeting a processor that supports QPX, or if QPX is
@@ -1728,7 +1919,10 @@ void Clang::AddPPCTargetArgs(const ArgList &Args,
break;
}
- ABIName = "elfv1";
+ if (T.isMusl() || (T.isOSFreeBSD() && T.getOSMajorVersion() >= 13))
+ ABIName = "elfv2";
+ else
+ ABIName = "elfv1";
break;
}
case llvm::Triple::ppc64le:
@@ -1737,6 +1931,7 @@ void Clang::AddPPCTargetArgs(const ArgList &Args,
default:
break;
}
+ }
bool IEEELongDouble = false;
for (const Arg *A : Args.filtered(options::OPT_mabi_EQ)) {
@@ -1804,12 +1999,75 @@ void Clang::AddSparcTargetArgs(const ArgList &Args,
void Clang::AddSystemZTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
- if (Args.hasFlag(options::OPT_mbackchain, options::OPT_mno_backchain, false))
+ bool HasBackchain = Args.hasFlag(options::OPT_mbackchain,
+ options::OPT_mno_backchain, false);
+ bool HasPackedStack = Args.hasFlag(options::OPT_mpacked_stack,
+ options::OPT_mno_packed_stack, false);
+ if (HasBackchain && HasPackedStack) {
+ const Driver &D = getToolChain().getDriver();
+ D.Diag(diag::err_drv_unsupported_opt)
+ << Args.getLastArg(options::OPT_mpacked_stack)->getAsString(Args) +
+ " " + Args.getLastArg(options::OPT_mbackchain)->getAsString(Args);
+ }
+ if (HasBackchain)
CmdArgs.push_back("-mbackchain");
+ if (HasPackedStack)
+ CmdArgs.push_back("-mpacked-stack");
+}
+
+static void addX86AlignBranchArgs(const Driver &D, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ if (Args.hasArg(options::OPT_mbranches_within_32B_boundaries)) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-x86-branches-within-32B-boundaries");
+ }
+ if (const Arg *A = Args.getLastArg(options::OPT_malign_branch_boundary_EQ)) {
+ StringRef Value = A->getValue();
+ unsigned Boundary;
+ if (Value.getAsInteger(10, Boundary) || Boundary < 16 ||
+ !llvm::isPowerOf2_64(Boundary)) {
+ D.Diag(diag::err_drv_invalid_argument_to_option)
+ << Value << A->getOption().getName();
+ } else {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back(
+ Args.MakeArgString("-x86-align-branch-boundary=" + Twine(Boundary)));
+ }
+ }
+ if (const Arg *A = Args.getLastArg(options::OPT_malign_branch_EQ)) {
+ std::string AlignBranch;
+ for (StringRef T : A->getValues()) {
+ if (T != "fused" && T != "jcc" && T != "jmp" && T != "call" &&
+ T != "ret" && T != "indirect")
+ D.Diag(diag::err_drv_invalid_malign_branch_EQ)
+ << T << "fused, jcc, jmp, call, ret, indirect";
+ if (!AlignBranch.empty())
+ AlignBranch += '+';
+ AlignBranch += T;
+ }
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back(Args.MakeArgString("-x86-align-branch=" + AlignBranch));
+ }
+ if (const Arg *A =
+ Args.getLastArg(options::OPT_malign_branch_prefix_size_EQ)) {
+ StringRef Value = A->getValue();
+ unsigned PrefixSize;
+ if (Value.getAsInteger(10, PrefixSize) || PrefixSize > 5) {
+ D.Diag(diag::err_drv_invalid_argument_to_option)
+ << Value << A->getOption().getName();
+ } else {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back(Args.MakeArgString("-x86-align-branch-prefix-size=" +
+ Twine(PrefixSize)));
+ }
+ }
}
void Clang::AddX86TargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
+ const Driver &D = getToolChain().getDriver();
+ addX86AlignBranchArgs(D, Args, CmdArgs);
+
if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) ||
Args.hasArg(options::OPT_mkernel) ||
Args.hasArg(options::OPT_fapple_kext))
@@ -1839,10 +2097,10 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
CmdArgs.push_back("-mllvm");
CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value));
} else {
- getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument)
+ D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Value;
}
- } else if (getToolChain().getDriver().IsCLMode()) {
+ } else if (D.IsCLMode()) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-x86-asm-syntax=intel");
}
@@ -2193,6 +2451,12 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
} else if (Value == "-fdebug-compilation-dir") {
CmdArgs.push_back("-fdebug-compilation-dir");
TakeNextArg = true;
+ } else if (Value.consume_front("-fdebug-compilation-dir=")) {
+ // The flag is a -Wa / -Xassembler argument and Options doesn't
+ // parse the argument, so this isn't automatically aliased to
+ // -fdebug-compilation-dir (without '=') here.
+ CmdArgs.push_back("-fdebug-compilation-dir");
+ CmdArgs.push_back(Value.data());
} else {
D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Value;
@@ -2229,9 +2493,18 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
bool AssociativeMath = false;
bool ReciprocalMath = false;
bool SignedZeros = true;
- bool TrappingMath = true;
+ bool TrappingMath = false; // Implemented via -ffp-exception-behavior
+ bool TrappingMathPresent = false; // Is trapping-math in args, and not
+ // overriden by ffp-exception-behavior?
+ bool RoundingFPMath = false;
+ bool RoundingMathPresent = false; // Is rounding-math in args?
+ // -ffp-model values: strict, fast, precise
+ StringRef FPModel = "";
+ // -ffp-exception-behavior options: strict, maytrap, ignore
+ StringRef FPExceptionBehavior = "";
StringRef DenormalFPMath = "";
StringRef FPContract = "";
+ bool StrictFPModel = false;
if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) {
CmdArgs.push_back("-mlimit-float-precision");
@@ -2239,7 +2512,65 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
}
for (const Arg *A : Args) {
- switch (A->getOption().getID()) {
+ auto optID = A->getOption().getID();
+ bool PreciseFPModel = false;
+ switch (optID) {
+ default:
+ break;
+ case options::OPT_ffp_model_EQ: {
+ // If -ffp-model= is seen, reset to fno-fast-math
+ HonorINFs = true;
+ HonorNaNs = true;
+ // Turning *off* -ffast-math restores the toolchain default.
+ MathErrno = TC.IsMathErrnoDefault();
+ AssociativeMath = false;
+ ReciprocalMath = false;
+ SignedZeros = true;
+ // -fno_fast_math restores default denormal and fpcontract handling
+ DenormalFPMath = "";
+ FPContract = "";
+ StringRef Val = A->getValue();
+ if (OFastEnabled && !Val.equals("fast")) {
+ // Only -ffp-model=fast is compatible with OFast, ignore.
+ D.Diag(clang::diag::warn_drv_overriding_flag_option)
+ << Args.MakeArgString("-ffp-model=" + Val)
+ << "-Ofast";
+ break;
+ }
+ StrictFPModel = false;
+ PreciseFPModel = true;
+ // ffp-model= is a Driver option, it is entirely rewritten into more
+ // granular options before being passed into cc1.
+ // Use the gcc option in the switch below.
+ if (!FPModel.empty() && !FPModel.equals(Val)) {
+ D.Diag(clang::diag::warn_drv_overriding_flag_option)
+ << Args.MakeArgString("-ffp-model=" + FPModel)
+ << Args.MakeArgString("-ffp-model=" + Val);
+ FPContract = "";
+ }
+ if (Val.equals("fast")) {
+ optID = options::OPT_ffast_math;
+ FPModel = Val;
+ FPContract = "fast";
+ } else if (Val.equals("precise")) {
+ optID = options::OPT_ffp_contract;
+ FPModel = Val;
+ FPContract = "fast";
+ PreciseFPModel = true;
+ } else if (Val.equals("strict")) {
+ StrictFPModel = true;
+ optID = options::OPT_frounding_math;
+ FPExceptionBehavior = "strict";
+ FPModel = Val;
+ TrappingMath = true;
+ } else
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << Val;
+ break;
+ }
+ }
+
+ switch (optID) {
// If this isn't an FP option skip the claim below
default: continue;
@@ -2256,20 +2587,83 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
case options::OPT_fno_reciprocal_math: ReciprocalMath = false; break;
case options::OPT_fsigned_zeros: SignedZeros = true; break;
case options::OPT_fno_signed_zeros: SignedZeros = false; break;
- case options::OPT_ftrapping_math: TrappingMath = true; break;
- case options::OPT_fno_trapping_math: TrappingMath = false; break;
+ case options::OPT_ftrapping_math:
+ if (!TrappingMathPresent && !FPExceptionBehavior.empty() &&
+ !FPExceptionBehavior.equals("strict"))
+ // Warn that previous value of option is overridden.
+ D.Diag(clang::diag::warn_drv_overriding_flag_option)
+ << Args.MakeArgString("-ffp-exception-behavior=" + FPExceptionBehavior)
+ << "-ftrapping-math";
+ TrappingMath = true;
+ TrappingMathPresent = true;
+ FPExceptionBehavior = "strict";
+ break;
+ case options::OPT_fno_trapping_math:
+ if (!TrappingMathPresent && !FPExceptionBehavior.empty() &&
+ !FPExceptionBehavior.equals("ignore"))
+ // Warn that previous value of option is overridden.
+ D.Diag(clang::diag::warn_drv_overriding_flag_option)
+ << Args.MakeArgString("-ffp-exception-behavior=" + FPExceptionBehavior)
+ << "-fno-trapping-math";
+ TrappingMath = false;
+ TrappingMathPresent = true;
+ FPExceptionBehavior = "ignore";
+ break;
+
+ case options::OPT_frounding_math:
+ RoundingFPMath = true;
+ RoundingMathPresent = true;
+ break;
+
+ case options::OPT_fno_rounding_math:
+ RoundingFPMath = false;
+ RoundingMathPresent = false;
+ break;
case options::OPT_fdenormal_fp_math_EQ:
DenormalFPMath = A->getValue();
break;
- // Validate and pass through -fp-contract option.
+ // Validate and pass through -ffp-contract option.
case options::OPT_ffp_contract: {
StringRef Val = A->getValue();
- if (Val == "fast" || Val == "on" || Val == "off")
+ if (PreciseFPModel) {
+ // -ffp-model=precise enables ffp-contract=fast as a side effect
+ // the FPContract value has already been set to a string literal
+ // and the Val string isn't a pertinent value.
+ ;
+ } else if (Val.equals("fast") || Val.equals("on") || Val.equals("off"))
FPContract = Val;
else
D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << Val;
+ break;
+ }
+
+ // Validate and pass through -ffp-model option.
+ case options::OPT_ffp_model_EQ:
+ // This should only occur in the error case
+ // since the optID has been replaced by a more granular
+ // floating point option.
+ break;
+
+ // Validate and pass through -ffp-exception-behavior option.
+ case options::OPT_ffp_exception_behavior_EQ: {
+ StringRef Val = A->getValue();
+ if (!TrappingMathPresent && !FPExceptionBehavior.empty() &&
+ !FPExceptionBehavior.equals(Val))
+ // Warn that previous value of option is overridden.
+ D.Diag(clang::diag::warn_drv_overriding_flag_option)
+ << Args.MakeArgString("-ffp-exception-behavior=" + FPExceptionBehavior)
+ << Args.MakeArgString("-ffp-exception-behavior=" + Val);
+ TrappingMath = TrappingMathPresent = false;
+ if (Val.equals("ignore") || Val.equals("maytrap"))
+ FPExceptionBehavior = Val;
+ else if (Val.equals("strict")) {
+ FPExceptionBehavior = Val;
+ TrappingMath = TrappingMathPresent = true;
+ } else
+ D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Val;
break;
}
@@ -2288,12 +2682,14 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
ReciprocalMath = true;
SignedZeros = false;
TrappingMath = false;
+ FPExceptionBehavior = "";
break;
case options::OPT_fno_unsafe_math_optimizations:
AssociativeMath = false;
ReciprocalMath = false;
SignedZeros = true;
TrappingMath = true;
+ FPExceptionBehavior = "strict";
// -fno_unsafe_math_optimizations restores default denormal handling
DenormalFPMath = "";
break;
@@ -2311,6 +2707,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
ReciprocalMath = true;
SignedZeros = false;
TrappingMath = false;
+ RoundingFPMath = false;
// If fast-math is set then set the fp-contract mode to fast.
FPContract = "fast";
break;
@@ -2324,12 +2721,31 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
AssociativeMath = false;
ReciprocalMath = false;
SignedZeros = true;
- TrappingMath = true;
+ TrappingMath = false;
+ RoundingFPMath = false;
// -fno_fast_math restores default denormal and fpcontract handling
DenormalFPMath = "";
FPContract = "";
break;
}
+ if (StrictFPModel) {
+ // If -ffp-model=strict has been specified on command line but
+ // subsequent options conflict then emit warning diagnostic.
+ if (HonorINFs && HonorNaNs &&
+ !AssociativeMath && !ReciprocalMath &&
+ SignedZeros && TrappingMath && RoundingFPMath &&
+ DenormalFPMath.empty() && FPContract.empty())
+ // OK: Current Arg doesn't conflict with -ffp-model=strict
+ ;
+ 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()));
+ }
+ }
// If we handled this option claim it
A->claim();
@@ -2357,7 +2773,11 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
if (ReciprocalMath)
CmdArgs.push_back("-freciprocal-math");
- if (!TrappingMath)
+ if (TrappingMath) {
+ // FP Exception Behavior is also set to strict
+ assert(FPExceptionBehavior.equals("strict"));
+ CmdArgs.push_back("-ftrapping-math");
+ } else if (TrappingMathPresent)
CmdArgs.push_back("-fno-trapping-math");
if (!DenormalFPMath.empty())
@@ -2367,14 +2787,37 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
if (!FPContract.empty())
CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract));
+ if (!RoundingFPMath)
+ CmdArgs.push_back(Args.MakeArgString("-fno-rounding-math"));
+
+ if (RoundingFPMath && RoundingMathPresent)
+ CmdArgs.push_back(Args.MakeArgString("-frounding-math"));
+
+ if (!FPExceptionBehavior.empty())
+ CmdArgs.push_back(Args.MakeArgString("-ffp-exception-behavior=" +
+ FPExceptionBehavior));
+
ParseMRecip(D, Args, CmdArgs);
// -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the
// individual features enabled by -ffast-math instead of the option itself as
// that's consistent with gcc's behaviour.
if (!HonorINFs && !HonorNaNs && !MathErrno && AssociativeMath &&
- ReciprocalMath && !SignedZeros && !TrappingMath)
+ ReciprocalMath && !SignedZeros && !TrappingMath && !RoundingFPMath) {
CmdArgs.push_back("-ffast-math");
+ if (FPModel.equals("fast")) {
+ if (FPContract.equals("fast"))
+ // All set, do nothing.
+ ;
+ else if (FPContract.empty())
+ // Enable -ffp-contract=fast
+ CmdArgs.push_back(Args.MakeArgString("-ffp-contract=fast"));
+ else
+ D.Diag(clang::diag::warn_drv_overriding_flag_option)
+ << "-ffp-model=fast"
+ << Args.MakeArgString("-ffp-contract=" + FPContract);
+ }
+ }
// Handle __FINITE_MATH_ONLY__ similarly.
if (!HonorINFs && !HonorNaNs)
@@ -2423,8 +2866,13 @@ static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs,
CmdArgs.push_back("-analyzer-disable-checker=unix.Vfork");
}
- if (Triple.isOSDarwin())
+ if (Triple.isOSDarwin()) {
CmdArgs.push_back("-analyzer-checker=osx");
+ CmdArgs.push_back(
+ "-analyzer-checker=security.insecureAPI.decodeValueOfObjCType");
+ }
+ else if (Triple.isOSFuchsia())
+ CmdArgs.push_back("-analyzer-checker=fuchsia");
CmdArgs.push_back("-analyzer-checker=deadcode");
@@ -3145,12 +3593,11 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D,
// This avoids having to monkey around further in cc1 other than to disable
// codeview if not running in a Windows environment. Perhaps even that
// decision should be made in the driver as well though.
- unsigned DWARFVersion = 0;
llvm::DebuggerKind DebuggerTuning = TC.getDefaultDebuggerTuning();
bool SplitDWARFInlining =
Args.hasFlag(options::OPT_fsplit_dwarf_inlining,
- options::OPT_fno_split_dwarf_inlining, true);
+ options::OPT_fno_split_dwarf_inlining, false);
Args.ClaimAllArgs(options::OPT_g_Group);
@@ -3198,11 +3645,16 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D,
}
// If a -gdwarf argument appeared, remember it.
- if (const Arg *A =
- Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3,
- options::OPT_gdwarf_4, options::OPT_gdwarf_5))
- if (checkDebugInfoOption(A, Args, D, TC))
- DWARFVersion = DwarfVersionNum(A->getSpelling());
+ const Arg *GDwarfN = Args.getLastArg(
+ options::OPT_gdwarf_2, options::OPT_gdwarf_3, options::OPT_gdwarf_4,
+ options::OPT_gdwarf_5, options::OPT_gdwarf);
+ bool EmitDwarf = false;
+ if (GDwarfN) {
+ if (checkDebugInfoOption(GDwarfN, Args, D, TC))
+ EmitDwarf = true;
+ else
+ GDwarfN = nullptr;
+ }
if (const Arg *A = Args.getLastArg(options::OPT_gcodeview)) {
if (checkDebugInfoOption(A, Args, D, TC))
@@ -3211,18 +3663,36 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D,
// If the user asked for debug info but did not explicitly specify -gcodeview
// or -gdwarf, ask the toolchain for the default format.
- if (!EmitCodeView && DWARFVersion == 0 &&
+ if (!EmitCodeView && !EmitDwarf &&
DebugInfoKind != codegenoptions::NoDebugInfo) {
switch (TC.getDefaultDebugFormat()) {
case codegenoptions::DIF_CodeView:
EmitCodeView = true;
break;
case codegenoptions::DIF_DWARF:
- DWARFVersion = TC.GetDefaultDwarfVersion();
+ EmitDwarf = true;
break;
}
}
+ unsigned DWARFVersion = 0;
+ unsigned DefaultDWARFVersion = ParseDebugDefaultVersion(TC, Args);
+ if (EmitDwarf) {
+ // Start with the platform default DWARF version
+ DWARFVersion = TC.GetDefaultDwarfVersion();
+ assert(DWARFVersion && "toolchain default DWARF version must be nonzero");
+
+ // If the user specified a default DWARF version, that takes precedence
+ // over the platform default.
+ if (DefaultDWARFVersion)
+ DWARFVersion = DefaultDWARFVersion;
+
+ // Override with a user-specified DWARF version
+ if (GDwarfN)
+ if (auto ExplicitVersion = DwarfVersionNum(GDwarfN->getSpelling()))
+ DWARFVersion = ExplicitVersion;
+ }
+
// -gline-directives-only supported only for the DWARF debug info.
if (DWARFVersion == 0 && DebugInfoKind == codegenoptions::DebugDirectivesOnly)
DebugInfoKind = codegenoptions::NoDebugInfo;
@@ -3296,9 +3766,20 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D,
}
}
+ // 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");
+ }
+
// Adjust the debug info kind for the given toolchain.
TC.adjustDebugInfoKind(DebugInfoKind, Args);
+ // When emitting remarks, we need at least debug lines in the output.
+ if (willEmitRemarks(Args) &&
+ DebugInfoKind <= codegenoptions::DebugDirectivesOnly)
+ DebugInfoKind = codegenoptions::DebugLineTablesOnly;
+
RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DWARFVersion,
DebuggerTuning);
@@ -3339,6 +3820,10 @@ 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");
+
if (Args.hasFlag(options::OPT_fdebug_types_section,
options::OPT_fno_debug_types_section, false)) {
if (!T.isOSBinFormatELF()) {
@@ -3641,6 +4126,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_fthinlto_index_EQ);
}
+ if (Args.getLastArg(options::OPT_fthin_link_bitcode_EQ))
+ Args.AddLastArg(CmdArgs, options::OPT_fthin_link_bitcode_EQ);
+
if (Args.getLastArg(options::OPT_save_temps_EQ))
Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ);
@@ -3653,7 +4141,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Disable all llvm IR level optimizations.
CmdArgs.push_back("-disable-llvm-passes");
- // Render target options such as -fuse-init-array on modern ELF platforms.
+ // Render target options.
TC.addClangTargetOptions(Args, CmdArgs, JA.getOffloadingDeviceKind());
// reject options that shouldn't be supported in bitcode
@@ -3718,6 +4206,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
RenderARMABI(Triple, Args, CmdArgs);
break;
case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_32:
case llvm::Triple::aarch64_be:
RenderAArch64ABI(Triple, Args, CmdArgs);
break;
@@ -4009,8 +4498,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
RenderFloatingPointOptions(TC, D, OFastEnabled, Args, CmdArgs);
if (Arg *A = Args.getLastArg(options::OPT_LongDouble_Group)) {
- if (TC.getArch() == llvm::Triple::x86 ||
- TC.getArch() == llvm::Triple::x86_64)
+ if (TC.getTriple().isX86())
A->render(Args, CmdArgs);
else if ((TC.getArch() == llvm::Triple::ppc || TC.getTriple().isPPC64()) &&
(A->getOption().getID() != options::OPT_mlong_double_80))
@@ -4097,6 +4585,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue());
}
+ if (Arg *A = Args.getLastArg(options::OPT_mtls_size_EQ)) {
+ StringRef Value = A->getValue();
+ unsigned TLSSize = 0;
+ Value.getAsInteger(10, TLSSize);
+ if (!Triple.isAArch64() || !Triple.isOSBinFormatELF())
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getOption().getName() << TripleStr;
+ if (TLSSize != 12 && TLSSize != 24 && TLSSize != 32 && TLSSize != 48)
+ D.Diag(diag::err_drv_invalid_int_value)
+ << A->getOption().getName() << Value;
+ Args.AddLastArg(CmdArgs, options::OPT_mtls_size_EQ);
+ }
+
// Add the target cpu
std::string CPU = getCPUName(Args, Triple, /*FromAs*/ false);
if (!CPU.empty()) {
@@ -4362,7 +4863,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (ShouldDisableDwarfDirectory(Args, TC))
CmdArgs.push_back("-fno-dwarf-directory-asm");
- if (ShouldDisableAutolink(Args, TC))
+ if (!ShouldEnableAutolink(Args, TC, JA))
CmdArgs.push_back("-fno-autolink");
// Add in -fdebug-compilation-dir if necessary.
@@ -4394,9 +4895,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_fexperimental_new_constant_interpreter))
CmdArgs.push_back("-fexperimental-new-constant-interpreter");
- if (Args.hasArg(options::OPT_fforce_experimental_new_constant_interpreter))
- CmdArgs.push_back("-fforce-experimental-new-constant-interpreter");
-
if (Arg *A = Args.getLastArg(options::OPT_fbracket_depth_EQ)) {
CmdArgs.push_back("-fbracket-depth");
CmdArgs.push_back(A->getValue());
@@ -4532,6 +5030,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fnoopenmp-use-tls");
Args.AddLastArg(CmdArgs, options::OPT_fopenmp_simd,
options::OPT_fno_openmp_simd);
+ Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_enable_irbuilder);
Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ);
Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_cuda_number_of_sm_EQ);
Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_cuda_blocks_per_sm_EQ);
@@ -4576,11 +5075,50 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
const XRayArgs &XRay = TC.getXRayArgs();
XRay.addArgs(TC, Args, CmdArgs, InputType);
- if (TC.SupportsProfiling())
+ if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ)) {
+ StringRef S0 = A->getValue(), S = S0;
+ unsigned Size, Start = 0;
+ if (!Triple.isAArch64() && Triple.getArch() != llvm::Triple::x86 &&
+ Triple.getArch() != llvm::Triple::x86_64)
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getAsString(Args) << TripleStr;
+ else if (S.consumeInteger(10, Size) ||
+ (!S.empty() && (!S.consume_front(",") ||
+ S.consumeInteger(10, Start) || !S.empty())))
+ D.Diag(diag::err_drv_invalid_argument_to_option)
+ << S0 << A->getOption().getName();
+ else if (Start)
+ D.Diag(diag::err_drv_unsupported_fpatchable_function_entry_argument);
+ else
+ CmdArgs.push_back(Args.MakeArgString(A->getSpelling() + Twine(Size)));
+ }
+
+ if (TC.SupportsProfiling()) {
Args.AddLastArg(CmdArgs, options::OPT_pg);
- if (TC.SupportsProfiling())
- Args.AddLastArg(CmdArgs, options::OPT_mfentry);
+ llvm::Triple::ArchType Arch = TC.getArch();
+ if (Arg *A = Args.getLastArg(options::OPT_mfentry)) {
+ if (Arch == llvm::Triple::systemz || TC.getTriple().isX86())
+ A->render(Args, CmdArgs);
+ else
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getAsString(Args) << TripleStr;
+ }
+ if (Arg *A = Args.getLastArg(options::OPT_mnop_mcount)) {
+ if (Arch == llvm::Triple::systemz)
+ A->render(Args, CmdArgs);
+ else
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getAsString(Args) << TripleStr;
+ }
+ if (Arg *A = Args.getLastArg(options::OPT_mrecord_mcount)) {
+ if (Arch == llvm::Triple::systemz)
+ A->render(Args, CmdArgs);
+ else
+ 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)))
@@ -4595,6 +5133,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ);
Args.AddLastArg(CmdArgs, options::OPT_ftrapv);
Args.AddLastArg(CmdArgs, options::OPT_malign_double);
+ Args.AddLastArg(CmdArgs, options::OPT_fno_temp_file);
if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) {
CmdArgs.push_back("-ftrapv-handler");
@@ -5112,66 +5651,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fapple-pragma-pack");
// Remarks can be enabled with any of the `-f.*optimization-record.*` flags.
- if (Args.hasFlag(options::OPT_fsave_optimization_record,
- options::OPT_foptimization_record_file_EQ,
- options::OPT_fno_save_optimization_record, false) ||
- Args.hasFlag(options::OPT_fsave_optimization_record_EQ,
- options::OPT_fno_save_optimization_record, false) ||
- Args.hasFlag(options::OPT_foptimization_record_passes_EQ,
- options::OPT_fno_save_optimization_record, false)) {
- CmdArgs.push_back("-opt-record-file");
-
- const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ);
- if (A) {
- CmdArgs.push_back(A->getValue());
- } else {
- SmallString<128> F;
-
- if (Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) {
- if (Arg *FinalOutput = Args.getLastArg(options::OPT_o))
- F = FinalOutput->getValue();
- }
-
- if (F.empty()) {
- // Use the input filename.
- F = llvm::sys::path::stem(Input.getBaseInput());
-
- // If we're compiling for an offload architecture (i.e. a CUDA device),
- // we need to make the file name for the device compilation different
- // from the host compilation.
- if (!JA.isDeviceOffloading(Action::OFK_None) &&
- !JA.isDeviceOffloading(Action::OFK_Host)) {
- llvm::sys::path::replace_extension(F, "");
- F += Action::GetOffloadingFileNamePrefix(JA.getOffloadingDeviceKind(),
- Triple.normalize());
- F += "-";
- F += JA.getOffloadingArch();
- }
- }
-
- std::string Extension = "opt.";
- if (const Arg *A =
- Args.getLastArg(options::OPT_fsave_optimization_record_EQ))
- Extension += A->getValue();
- else
- Extension += "yaml";
-
- llvm::sys::path::replace_extension(F, Extension);
- CmdArgs.push_back(Args.MakeArgString(F));
- }
-
- if (const Arg *A =
- Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) {
- CmdArgs.push_back("-opt-record-passes");
- CmdArgs.push_back(A->getValue());
- }
-
- if (const Arg *A =
- Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) {
- CmdArgs.push_back("-opt-record-format");
- CmdArgs.push_back(A->getValue());
- }
- }
+ if (willEmitRemarks(Args) && checkRemarksOptions(D, Args, Triple))
+ renderRemarksOptions(Args, CmdArgs, Triple, Input, Output, JA);
bool RewriteImports = Args.hasFlag(options::OPT_frewrite_imports,
options::OPT_fno_rewrite_imports, false);
@@ -5331,6 +5812,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fcuda-short-ptr");
}
+ if (IsHIP)
+ CmdArgs.push_back("-fcuda-allow-variadic-functions");
+
// OpenMP offloading device jobs take the argument -fopenmp-host-ir-file-path
// to specify the result of the compile phase on the host, so the meaningful
// device declarations can be identified. Also, -fopenmp-is-device is passed
@@ -5395,7 +5879,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fwhole-program-vtables");
}
- bool DefaultsSplitLTOUnit = WholeProgramVTables || Sanitize.needsLTO();
+ bool DefaultsSplitLTOUnit =
+ (WholeProgramVTables || Sanitize.needsLTO()) &&
+ (D.getLTOMode() == LTOK_Full || TC.canSplitThinLTOUnit());
bool SplitLTOUnit =
Args.hasFlag(options::OPT_fsplit_lto_unit,
options::OPT_fno_split_lto_unit, DefaultsSplitLTOUnit);
@@ -5467,11 +5953,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// We only support -moutline in AArch64 right now. If we're not compiling
// for AArch64, emit a warning and ignore the flag. Otherwise, add the
// proper mllvm flags.
- if (Triple.getArch() != llvm::Triple::aarch64) {
+ if (Triple.getArch() != llvm::Triple::aarch64 &&
+ Triple.getArch() != llvm::Triple::aarch64_32) {
D.Diag(diag::warn_drv_moutline_unsupported_opt) << Triple.getArchName();
} else {
- CmdArgs.push_back("-mllvm");
- CmdArgs.push_back("-enable-machine-outliner");
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-enable-machine-outliner");
}
} else {
// Disable all outlining behaviour.
@@ -5485,7 +5972,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
TC.getTriple().isOSBinFormatCOFF()) &&
!TC.getTriple().isPS4() &&
!TC.getTriple().isOSNetBSD() &&
- !Distro(D.getVFS()).IsGentoo() &&
+ !Distro(D.getVFS(), TC.getTriple()).IsGentoo() &&
!TC.getTriple().isAndroid() &&
TC.useIntegratedAs()))
CmdArgs.push_back("-faddrsig");
@@ -5503,8 +5990,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Output.getType() == types::TY_Dependencies) {
// Handled with other dependency code.
} else if (Output.isFilename()) {
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
+ if (Output.getType() == clang::driver::types::TY_IFS_CPP ||
+ Output.getType() == clang::driver::types::TY_IFS) {
+ SmallString<128> OutputFilename(Output.getFilename());
+ llvm::sys::path::replace_extension(OutputFilename, "ifs");
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Args.MakeArgString(OutputFilename));
+ } else {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ }
} else {
assert(Output.isNothing() && "Invalid output.");
}
@@ -5538,6 +6033,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// fails, so that the main compilation's fallback to cl.exe runs.
C.addCommand(std::make_unique<ForceSuccessCommand>(JA, *this, Exec,
CmdArgs, Inputs));
+ } else if (D.CC1Main && !D.CCGenDiagnostics) {
+ // Invoke the CC1 directly in this process
+ C.addCommand(
+ std::make_unique<CC1Command>(JA, *this, Exec, CmdArgs, Inputs));
} else {
C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
@@ -5872,8 +6371,7 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
}
unsigned VolatileOptionID;
- if (getToolChain().getArch() == llvm::Triple::x86_64 ||
- getToolChain().getArch() == llvm::Triple::x86)
+ if (getToolChain().getTriple().isX86())
VolatileOptionID = options::OPT__SLASH_volatile_ms;
else
VolatileOptionID = options::OPT__SLASH_volatile_iso;
@@ -5967,26 +6465,19 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
}
if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) {
- SmallVector<StringRef, 1> SplitArgs;
- StringRef(A->getValue()).split(SplitArgs, ",");
- bool Instrument = false;
- bool NoChecks = false;
- for (StringRef Arg : SplitArgs) {
- if (Arg.equals_lower("cf"))
- Instrument = true;
- else if (Arg.equals_lower("cf-"))
- Instrument = false;
- else if (Arg.equals_lower("nochecks"))
- NoChecks = true;
- else if (Arg.equals_lower("nochecks-"))
- NoChecks = false;
- else
- D.Diag(diag::err_drv_invalid_value) << A->getSpelling() << Arg;
- }
- // Currently there's no support emitting CFG instrumentation; the flag only
- // emits the table of address-taken functions.
- if (Instrument || NoChecks)
+ StringRef GuardArgs = A->getValue();
+ // The only valid options are "cf", "cf,nochecks", and "cf-".
+ if (GuardArgs.equals_lower("cf")) {
+ // Emit CFG instrumentation and the table of address-taken functions.
CmdArgs.push_back("-cfguard");
+ } else if (GuardArgs.equals_lower("cf,nochecks")) {
+ // Emit only the table of address-taken functions.
+ CmdArgs.push_back("-cfguard-no-checks");
+ } else if (GuardArgs.equals_lower("cf-")) {
+ // Do nothing, but we might want to emit a security warning in future.
+ } else {
+ D.Diag(diag::err_drv_invalid_value) << A->getSpelling() << GuardArgs;
+ }
}
}
@@ -6040,6 +6531,8 @@ void ClangAs::AddMIPSTargetArgs(const ArgList &Args,
void ClangAs::AddX86TargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
+ addX86AlignBranchArgs(getToolChain().getDriver(), Args, CmdArgs);
+
if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) {
StringRef Value = A->getValue();
if (Value == "intel" || Value == "att") {
@@ -6134,6 +6627,11 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
if (WantDebug)
DwarfVersion = DwarfVersionNum(A->getSpelling());
}
+
+ unsigned DefaultDwarfVersion = ParseDebugDefaultVersion(getToolChain(), Args);
+ if (DwarfVersion == 0)
+ DwarfVersion = DefaultDwarfVersion;
+
if (DwarfVersion == 0)
DwarfVersion = getToolChain().GetDefaultDwarfVersion();
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 10743559e048..37ec73468570 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -11,12 +11,8 @@
#include "Arch/ARM.h"
#include "Arch/Mips.h"
#include "Arch/PPC.h"
-#include "Arch/RISCV.h"
-#include "Arch/Sparc.h"
#include "Arch/SystemZ.h"
#include "Arch/X86.h"
-#include "AMDGPU.h"
-#include "MSP430.h"
#include "HIP.h"
#include "Hexagon.h"
#include "InputInfo.h"
@@ -257,6 +253,7 @@ std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T,
return "";
case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_32:
case llvm::Triple::aarch64_be:
return aarch64::getAArch64TargetCPU(Args, T, A);
@@ -488,14 +485,6 @@ void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args,
if (!StatsFile.empty())
CmdArgs.push_back(
Args.MakeArgString(Twine("-plugin-opt=stats-file=") + StatsFile));
-
- getTargetFeatures(ToolChain, ToolChain.getTriple(), Args, CmdArgs,
- /* ForAS= */ false, /* ForLTOPlugin= */ true);
-
- StringRef ABIName = tools::getTargetABI(Args, ToolChain.getTriple());
- if (!ABIName.empty())
- CmdArgs.push_back(
- Args.MakeArgString(Twine("-plugin-opt=-target-abi=") + ABIName));
}
void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args,
@@ -1138,6 +1127,21 @@ unsigned tools::ParseFunctionAlignment(const ToolChain &TC,
return Value ? llvm::Log2_32_Ceil(std::min(Value, 65536u)) : Value;
}
+unsigned tools::ParseDebugDefaultVersion(const ToolChain &TC,
+ const ArgList &Args) {
+ const Arg *A = Args.getLastArg(options::OPT_fdebug_default_version);
+
+ if (!A)
+ return 0;
+
+ unsigned Value = 0;
+ if (StringRef(A->getValue()).getAsInteger(10, Value) || Value > 5 ||
+ Value < 2)
+ TC.getDriver().Diag(diag::err_drv_invalid_int_value)
+ << A->getAsString(Args) << A->getValue();
+ return Value;
+}
+
void tools::AddAssemblerKPIC(const ToolChain &ToolChain, const ArgList &Args,
ArgStringList &CmdArgs) {
llvm::Reloc::Model RelocationModel;
@@ -1205,7 +1209,10 @@ static void AddUnwindLibrary(const ToolChain &TC, const Driver &D,
break;
}
case ToolChain::UNW_CompilerRT:
- CmdArgs.push_back("-lunwind");
+ if (LGT == LibGccType::StaticLibGcc)
+ CmdArgs.push_back("-l:libunwind.a");
+ else
+ CmdArgs.push_back("-l:libunwind.so");
break;
}
@@ -1392,111 +1399,3 @@ void tools::addMultilibFlag(bool Enabled, const char *const Flag,
Multilib::flags_list &Flags) {
Flags.push_back(std::string(Enabled ? "+" : "-") + Flag);
}
-
-static void getWebAssemblyTargetFeatures(const ArgList &Args,
- std::vector<StringRef> &Features) {
- handleTargetFeaturesGroup(Args, Features, options::OPT_m_wasm_Features_Group);
-}
-
-void tools::getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple,
- const ArgList &Args, ArgStringList &CmdArgs, bool ForAS,
- bool ForLTOPlugin) {
-
- const Driver &D = TC.getDriver();
- std::vector<StringRef> Features;
- switch (Triple.getArch()) {
- default:
- break;
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- mips::getMIPSTargetFeatures(D, Triple, Args, Features);
- break;
-
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
- arm::getARMTargetFeatures(TC, Triple, Args, CmdArgs, Features, ForAS);
- break;
-
- case llvm::Triple::ppc:
- case llvm::Triple::ppc64:
- case llvm::Triple::ppc64le:
- ppc::getPPCTargetFeatures(D, Triple, Args, Features);
- break;
- case llvm::Triple::riscv32:
- case llvm::Triple::riscv64:
- riscv::getRISCVTargetFeatures(D, Triple, Args, Features);
- break;
- case llvm::Triple::systemz:
- systemz::getSystemZTargetFeatures(Args, Features);
- break;
- case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_be:
- aarch64::getAArch64TargetFeatures(D, Triple, Args, Features);
- break;
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- x86::getX86TargetFeatures(D, Triple, Args, Features);
- break;
- case llvm::Triple::hexagon:
- hexagon::getHexagonTargetFeatures(D, Args, Features);
- break;
- case llvm::Triple::wasm32:
- case llvm::Triple::wasm64:
- getWebAssemblyTargetFeatures(Args, Features);
- break;
- case llvm::Triple::sparc:
- case llvm::Triple::sparcel:
- case llvm::Triple::sparcv9:
- sparc::getSparcTargetFeatures(D, Args, Features);
- break;
- case llvm::Triple::r600:
- case llvm::Triple::amdgcn:
- amdgpu::getAMDGPUTargetFeatures(D, Args, Features);
- break;
- case llvm::Triple::msp430:
- msp430::getMSP430TargetFeatures(D, Args, Features);
- }
-
- // Find the last of each feature.
- llvm::StringMap<unsigned> LastOpt;
- for (unsigned I = 0, N = Features.size(); I < N; ++I) {
- StringRef Name = Features[I];
- assert(Name[0] == '-' || Name[0] == '+');
- LastOpt[Name.drop_front(1)] = I;
- }
-
- for (unsigned I = 0, N = Features.size(); I < N; ++I) {
- // If this feature was overridden, ignore it.
- StringRef Name = Features[I];
- llvm::StringMap<unsigned>::iterator LastI =
- LastOpt.find(Name.drop_front(1));
- assert(LastI != LastOpt.end());
- unsigned Last = LastI->second;
- if (Last != I)
- continue;
- if (!ForLTOPlugin) {
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back(Name.data());
- } else {
- CmdArgs.push_back(
- Args.MakeArgString(Twine("-plugin-opt=-mattr=") + Name));
- }
- }
-}
-
-StringRef tools::getTargetABI(const ArgList &Args, const llvm::Triple &Triple) {
- // TODO: Support the other target ABI
- switch (Triple.getArch()) {
- default:
- break;
- case llvm::Triple::riscv32:
- case llvm::Triple::riscv64:
- return tools::riscv::getRISCVABI(Args, Triple);
- break;
- }
- return StringRef();
-}
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.h b/clang/lib/Driver/ToolChains/CommonArgs.h
index 79468e6b8926..84b9d2cf59b4 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.h
+++ b/clang/lib/Driver/ToolChains/CommonArgs.h
@@ -68,6 +68,9 @@ 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);
+
void AddAssemblerKPIC(const ToolChain &ToolChain,
const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs);
@@ -118,14 +121,6 @@ SmallString<128> getStatsFileName(const llvm::opt::ArgList &Args,
void addMultilibFlag(bool Enabled, const char *const Flag,
Multilib::flags_list &Flags);
-StringRef getTargetABI(const llvm::opt::ArgList &Args,
- const llvm::Triple &Triple);
-
-void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs, bool ForAS,
- bool ForLTOPlugin = false);
-
} // end namespace tools
} // end namespace driver
} // end namespace clang
diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp
index 8c704a3078ad..02871d2ce411 100644
--- a/clang/lib/Driver/ToolChains/Cuda.cpp
+++ b/clang/lib/Driver/ToolChains/Cuda.cpp
@@ -115,7 +115,8 @@ CudaInstallationDetector::CudaInstallationDetector(
for (const char *Ver : Versions)
Candidates.emplace_back(D.SysRoot + "/usr/local/cuda-" + Ver);
- if (Distro(D.getVFS()).IsDebian() || Distro(D.getVFS()).IsUbuntu())
+ Distro Dist(D.getVFS(), llvm::Triple(llvm::sys::getProcessTriple()));
+ if (Dist.IsDebian() || Dist.IsUbuntu())
// Special case for Debian to have nvidia-cuda-toolkit work
// out of the box. More info on http://bugs.debian.org/882505
Candidates.emplace_back(D.SysRoot + "/usr/lib/cuda");
diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp
index ee08b8208d93..344a14fe1ea7 100644
--- a/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -19,6 +19,7 @@
#include "clang/Driver/SanitizerArgs.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/ArgList.h"
+#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/TargetParser.h"
@@ -57,6 +58,7 @@ llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) {
.Cases("armv7", "armv7em", "armv7k", "armv7m", llvm::Triple::arm)
.Cases("armv7s", "xscale", llvm::Triple::arm)
.Case("arm64", llvm::Triple::aarch64)
+ .Case("arm64_32", llvm::Triple::aarch64_32)
.Case("r600", llvm::Triple::r600)
.Case("amdgcn", llvm::Triple::amdgcn)
.Case("nvptx", llvm::Triple::nvptx)
@@ -122,8 +124,7 @@ void darwin::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
AddMachOArch(Args, CmdArgs);
// Use -force_cpusubtype_ALL on x86 by default.
- if (getToolChain().getArch() == llvm::Triple::x86 ||
- getToolChain().getArch() == llvm::Triple::x86_64 ||
+ if (getToolChain().getTriple().isX86() ||
Args.hasArg(options::OPT_force__cpusubtype__ALL))
CmdArgs.push_back("-force_cpusubtype_ALL");
@@ -334,7 +335,10 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args,
Args.AddAllArgs(CmdArgs, options::OPT_init);
// Add the deployment target.
- MachOTC.addMinVersionArgs(Args, CmdArgs);
+ if (!Version[0] || Version[0] >= 520)
+ MachOTC.addPlatformVersionArgs(Args, CmdArgs);
+ else
+ MachOTC.addMinVersionArgs(Args, CmdArgs);
Args.AddLastArg(CmdArgs, options::OPT_nomultidefs);
Args.AddLastArg(CmdArgs, options::OPT_multi__module);
@@ -737,7 +741,7 @@ Darwin::Darwin(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
CudaInstallation(D, Triple, Args) {}
types::ID MachO::LookupTypeForExtension(StringRef Ext) const {
- types::ID Ty = types::lookupTypeForExtension(Ext);
+ types::ID Ty = ToolChain::LookupTypeForExtension(Ext);
// Darwin always preprocesses assembly files (unless -x is used explicitly).
if (Ty == types::TY_PP_Asm)
@@ -831,6 +835,9 @@ StringRef MachO::getMachOArchName(const ArgList &Args) const {
default:
return getDefaultUniversalArchName();
+ case llvm::Triple::aarch64_32:
+ return "arm64_32";
+
case llvm::Triple::aarch64:
return "arm64";
@@ -1061,7 +1068,6 @@ StringRef Darwin::getPlatformFamily() const {
StringRef Darwin::getSDKName(StringRef isysroot) {
// Assume SDK has path: SOME_PATH/SDKs/PlatformXX.YY.sdk
- llvm::sys::path::const_iterator SDKDir;
auto BeginSDK = llvm::sys::path::begin(isysroot);
auto EndSDK = llvm::sys::path::end(isysroot);
for (auto IT = BeginSDK; IT != EndSDK; ++IT) {
@@ -1110,6 +1116,19 @@ static void addExportedSymbol(ArgStringList &CmdArgs, const char *Symbol) {
CmdArgs.push_back(Symbol);
}
+/// Add a sectalign directive for \p Segment and \p Section to the maximum
+/// expected page size for Darwin.
+///
+/// On iPhone 6+ the max supported page size is 16K. On macOS, the max is 4K.
+/// Use a common alignment constant (16K) for now, and reduce the alignment on
+/// macOS if it proves important.
+static void addSectalignToPage(const ArgList &Args, ArgStringList &CmdArgs,
+ StringRef Segment, StringRef Section) {
+ for (const char *A : {"-sectalign", Args.MakeArgString(Segment),
+ Args.MakeArgString(Section), "0x4000"})
+ CmdArgs.push_back(A);
+}
+
void Darwin::addProfileRTLibs(const ArgList &Args,
ArgStringList &CmdArgs) const {
if (!needsProfileRT(Args)) return;
@@ -1117,11 +1136,13 @@ void Darwin::addProfileRTLibs(const ArgList &Args,
AddLinkRuntimeLib(Args, CmdArgs, "profile",
RuntimeLinkOptions(RLO_AlwaysLink | RLO_FirstLink));
+ bool ForGCOV = needsGCovInstrumentation(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 (needsGCovInstrumentation(Args)) {
+ if (ForGCOV) {
addExportedSymbol(CmdArgs, "___gcov_flush");
addExportedSymbol(CmdArgs, "_flush_fn_list");
addExportedSymbol(CmdArgs, "_writeout_fn_list");
@@ -1131,6 +1152,24 @@ void Darwin::addProfileRTLibs(const ArgList &Args,
}
addExportedSymbol(CmdArgs, "_lprofDirMode");
}
+
+ // Align __llvm_prf_{cnts,data} sections to the maximum expected page
+ // alignment. This allows profile counters to be mmap()'d to disk. Note that
+ // it's not enough to just page-align __llvm_prf_cnts: the following section
+ // must also be page-aligned so that its data is not clobbered by mmap().
+ //
+ // The section alignment is only needed when continuous profile sync is
+ // enabled, but this is expected to be the default in Xcode. Specifying the
+ // extra alignment also allows the same binary to be used with/without sync
+ // enabled.
+ if (!ForGCOV) {
+ for (auto IPSK : {llvm::IPSK_cnts, llvm::IPSK_data}) {
+ addSectalignToPage(
+ Args, CmdArgs, "__DATA",
+ llvm::getInstrProfSectionName(IPSK, llvm::Triple::MachO,
+ /*AddSegmentInfo=*/false));
+ }
+ }
}
void DarwinClang::AddLinkSanitizerLibArgs(const ArgList &Args,
@@ -1493,8 +1532,8 @@ getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver,
Targets[Darwin::TvOS] = "";
} else {
// Don't allow conflicts in any other platform.
- int FirstTarget = llvm::array_lengthof(Targets);
- for (int I = 0; I != llvm::array_lengthof(Targets); ++I) {
+ unsigned FirstTarget = llvm::array_lengthof(Targets);
+ for (unsigned I = 0; I != llvm::array_lengthof(Targets); ++I) {
if (Targets[I].empty())
continue;
if (FirstTarget == llvm::array_lengthof(Targets))
@@ -1607,7 +1646,7 @@ inferDeploymentTargetFromArch(DerivedArgList &Args, const Darwin &Toolchain,
if (MachOArchName == "armv7" || MachOArchName == "armv7s" ||
MachOArchName == "arm64")
OSTy = llvm::Triple::IOS;
- else if (MachOArchName == "armv7k")
+ else if (MachOArchName == "armv7k" || MachOArchName == "arm64_32")
OSTy = llvm::Triple::WatchOS;
else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" &&
MachOArchName != "armv7em")
@@ -1796,9 +1835,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
DarwinEnvironmentKind Environment = OSTarget->getEnvironment();
// Recognize iOS targets with an x86 architecture as the iOS simulator.
if (Environment == NativeEnvironment && Platform != MacOS &&
- OSTarget->canInferSimulatorFromArch() &&
- (getTriple().getArch() == llvm::Triple::x86 ||
- getTriple().getArch() == llvm::Triple::x86_64))
+ OSTarget->canInferSimulatorFromArch() && getTriple().isX86())
Environment = Simulator;
setTarget(Platform, Environment, Major, Minor, Micro);
@@ -2194,8 +2231,7 @@ DerivedArgList *MachO::TranslateArgs(const DerivedArgList &Args,
}
}
- if (getTriple().getArch() == llvm::Triple::x86 ||
- getTriple().getArch() == llvm::Triple::x86_64)
+ if (getTriple().isX86())
if (!Args.hasArgNoClaim(options::OPT_mtune_EQ))
DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_mtune_EQ),
"core2");
@@ -2451,7 +2487,7 @@ bool MachO::isPICDefaultForced() const {
bool MachO::SupportsProfiling() const {
// Profiling instrumentation is only supported on x86.
- return getArch() == llvm::Triple::x86 || getArch() == llvm::Triple::x86_64;
+ return getTriple().isX86();
}
void Darwin::addMinVersionArgs(const ArgList &Args,
@@ -2478,6 +2514,45 @@ void Darwin::addMinVersionArgs(const ArgList &Args,
CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString()));
}
+static const char *getPlatformName(Darwin::DarwinPlatformKind Platform,
+ Darwin::DarwinEnvironmentKind Environment) {
+ switch (Platform) {
+ case Darwin::MacOS:
+ return "macos";
+ case Darwin::IPhoneOS:
+ if (Environment == Darwin::NativeEnvironment ||
+ Environment == Darwin::Simulator)
+ return "ios";
+ // FIXME: Add macCatalyst support here ("\"mac catalyst\"").
+ llvm_unreachable("macCatalyst isn't yet supported");
+ case Darwin::TvOS:
+ return "tvos";
+ case Darwin::WatchOS:
+ return "watchos";
+ }
+ llvm_unreachable("invalid platform");
+}
+
+void Darwin::addPlatformVersionArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const {
+ // -platform_version <platform> <target_version> <sdk_version>
+ // Both the target and SDK version support only up to 3 components.
+ CmdArgs.push_back("-platform_version");
+ std::string PlatformName = getPlatformName(TargetPlatform, TargetEnvironment);
+ if (TargetEnvironment == Darwin::Simulator)
+ PlatformName += "-simulator";
+ CmdArgs.push_back(Args.MakeArgString(PlatformName));
+ VersionTuple TargetVersion = getTargetVersion().withoutBuild();
+ CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString()));
+ if (SDKInfo) {
+ VersionTuple SDKVersion = SDKInfo->getVersion().withoutBuild();
+ CmdArgs.push_back(Args.MakeArgString(SDKVersion.getAsString()));
+ } else {
+ // Use a blank SDK version if it's not present.
+ CmdArgs.push_back("0.0.0");
+ }
+}
+
void Darwin::addStartObjectFileArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
// Derived from startfile spec.
diff --git a/clang/lib/Driver/ToolChains/Darwin.h b/clang/lib/Driver/ToolChains/Darwin.h
index 2dc7c85880f7..1b193a4c4eb9 100644
--- a/clang/lib/Driver/ToolChains/Darwin.h
+++ b/clang/lib/Driver/ToolChains/Darwin.h
@@ -167,6 +167,10 @@ public:
virtual void addMinVersionArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const {}
+ virtual void addPlatformVersionArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const {
+ }
+
/// On some iOS platforms, kernel and kernel modules were built statically. Is
/// this such a target?
virtual bool isKernelStatic() const { return false; }
@@ -258,6 +262,9 @@ public:
return "";
}
+ // Darwin toolchain uses legacy thin LTO API, which is not
+ // capable of unit splitting.
+ bool canSplitThinLTOUnit() const override { return false; }
/// }
};
@@ -311,6 +318,9 @@ public:
void addMinVersionArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const override;
+ void addPlatformVersionArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
void addStartObjectFileArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const override;
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
new file mode 100644
index 000000000000..9b9eb81fa111
--- /dev/null
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -0,0 +1,79 @@
+//===-- Flang.cpp - Flang+LLVM ToolChain Implementations --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "Flang.h"
+#include "CommonArgs.h"
+
+#include "clang/Driver/Options.h"
+
+#include <cassert>
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang;
+using namespace llvm::opt;
+
+void Flang::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const ArgList &Args, const char *LinkingOutput) const {
+ const auto &TC = getToolChain();
+ const llvm::Triple &Triple = TC.getEffectiveTriple();
+ const std::string &TripleStr = Triple.getTriple();
+
+ ArgStringList CmdArgs;
+
+ CmdArgs.push_back("-fc1");
+
+ CmdArgs.push_back("-triple");
+ CmdArgs.push_back(Args.MakeArgString(TripleStr));
+
+ if (isa<PreprocessJobAction>(JA)) {
+ CmdArgs.push_back("-E");
+ } else if (isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) {
+ if (JA.getType() == types::TY_Nothing) {
+ CmdArgs.push_back("-fsyntax-only");
+ } else if (JA.getType() == types::TY_AST) {
+ CmdArgs.push_back("-emit-ast");
+ } else if (JA.getType() == types::TY_LLVM_IR ||
+ JA.getType() == types::TY_LTO_IR) {
+ CmdArgs.push_back("-emit-llvm");
+ } else if (JA.getType() == types::TY_LLVM_BC ||
+ JA.getType() == types::TY_LTO_BC) {
+ CmdArgs.push_back("-emit-llvm-bc");
+ } else if (JA.getType() == types::TY_PP_Asm) {
+ CmdArgs.push_back("-S");
+ } else {
+ assert(false && "Unexpected output type!");
+ }
+ } else if (isa<AssembleJobAction>(JA)) {
+ CmdArgs.push_back("-emit-obj");
+ } else {
+ assert(false && "Unexpected action class for Flang tool.");
+ }
+
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Invalid output.");
+ }
+
+ const InputInfo &Input = Inputs[0];
+ assert(Input.isFilename() && "Invalid input.");
+ CmdArgs.push_back(Input.getFilename());
+
+ const auto& D = C.getDriver();
+ const char* Exec = Args.MakeArgString(D.GetProgramPath("flang", TC));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+Flang::Flang(const ToolChain &TC)
+ : Tool("flang", "flang frontend", TC, RF_Full) {}
+
+Flang::~Flang() {}
diff --git a/clang/lib/Driver/ToolChains/Flang.h b/clang/lib/Driver/ToolChains/Flang.h
new file mode 100644
index 000000000000..19e3a8c28f7e
--- /dev/null
+++ b/clang/lib/Driver/ToolChains/Flang.h
@@ -0,0 +1,46 @@
+//===--- Flang.h - Flang Tool and ToolChain Implementations ====-*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FLANG_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FLANG_H
+
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/Action.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/ToolChain.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/Compiler.h"
+
+namespace clang {
+namespace driver {
+
+namespace tools {
+
+/// Flang compiler tool.
+class LLVM_LIBRARY_VISIBILITY Flang : public Tool {
+public:
+ Flang(const ToolChain &TC);
+ ~Flang() override;
+
+ bool hasGoodDiagnostics() const override { return true; }
+ bool hasIntegratedAssembler() const override { return true; }
+ bool hasIntegratedCPP() const override { return true; }
+ bool canEmitIR() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+} // end namespace tools
+
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FLANG_H
diff --git a/clang/lib/Driver/ToolChains/FreeBSD.cpp b/clang/lib/Driver/ToolChains/FreeBSD.cpp
index 7c891a24ba30..c5c6f530f48c 100644
--- a/clang/lib/Driver/ToolChains/FreeBSD.cpp
+++ b/clang/lib/Driver/ToolChains/FreeBSD.cpp
@@ -12,6 +12,7 @@
#include "Arch/Sparc.h"
#include "CommonArgs.h"
#include "clang/Driver/Compilation.h"
+#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/SanitizerArgs.h"
#include "llvm/Option/ArgList.h"
@@ -30,6 +31,7 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
const char *LinkingOutput) const {
claimNoWarnArgs(Args);
ArgStringList CmdArgs;
+ const auto &D = getToolChain().getDriver();
// When building 32-bit code on FreeBSD/amd64, we have to explicitly
// instruct as in the base system to assemble 32-bit code.
@@ -103,6 +105,19 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
}
}
+ for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ,
+ options::OPT_fdebug_prefix_map_EQ)) {
+ StringRef Map = A->getValue();
+ if (Map.find('=') == StringRef::npos)
+ D.Diag(diag::err_drv_invalid_argument_to_option)
+ << Map << A->getOption().getName();
+ else {
+ CmdArgs.push_back(Args.MakeArgString("--debug-prefix-map"));
+ CmdArgs.push_back(Args.MakeArgString(Map));
+ }
+ A->claim();
+ }
+
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
CmdArgs.push_back("-o");
@@ -155,11 +170,10 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-dynamic-linker");
CmdArgs.push_back("/libexec/ld-elf.so.1");
}
- if (ToolChain.getTriple().getOSMajorVersion() >= 9) {
- if (Arch == llvm::Triple::arm || Arch == llvm::Triple::sparc ||
- Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) {
+ const llvm::Triple &T = ToolChain.getTriple();
+ if (T.getOSMajorVersion() >= 9) {
+ if (Arch == llvm::Triple::arm || Arch == llvm::Triple::sparc || T.isX86())
CmdArgs.push_back("--hash-style=both");
- }
}
CmdArgs.push_back("--enable-new-dtags");
}
@@ -397,6 +411,11 @@ void FreeBSD::AddCXXStdlibLibArgs(const ArgList &Args,
}
}
+void FreeBSD::AddCudaIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
+}
+
Tool *FreeBSD::buildAssembler() const {
return new tools::freebsd::Assembler(*this);
}
@@ -420,6 +439,8 @@ llvm::ExceptionHandling FreeBSD::GetExceptionModel(const ArgList &Args) const {
bool FreeBSD::HasNativeLLVMSupport() const { return true; }
+bool FreeBSD::IsUnwindTablesDefault(const ArgList &Args) const { return true; }
+
bool FreeBSD::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); }
SanitizerMask FreeBSD::getSupportedSanitizers() const {
@@ -445,3 +466,12 @@ SanitizerMask FreeBSD::getSupportedSanitizers() const {
Res |= SanitizerKind::Memory;
return Res;
}
+
+void FreeBSD::addClangTargetOptions(const ArgList &DriverArgs,
+ ArgStringList &CC1Args,
+ Action::OffloadKind) const {
+ if (!DriverArgs.hasFlag(options::OPT_fuse_init_array,
+ options::OPT_fno_use_init_array,
+ getTriple().getOSMajorVersion() >= 12))
+ CC1Args.push_back("-fno-use-init-array");
+}
diff --git a/clang/lib/Driver/ToolChains/FreeBSD.h b/clang/lib/Driver/ToolChains/FreeBSD.h
index d17b3808ffac..84bdbfd9a312 100644
--- a/clang/lib/Driver/ToolChains/FreeBSD.h
+++ b/clang/lib/Driver/ToolChains/FreeBSD.h
@@ -64,15 +64,22 @@ public:
llvm::opt::ArgStringList &CC1Args) const override;
void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const override;
+ void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
llvm::ExceptionHandling GetExceptionModel(
const llvm::opt::ArgList &Args) const override;
+ bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
bool isPIEDefault() const override;
SanitizerMask getSupportedSanitizers() const override;
unsigned GetDefaultDwarfVersion() const override;
// Until dtrace (via CTF) and LLDB can deal with distributed debug info,
// FreeBSD defaults to standalone/full debug info.
bool GetDefaultStandaloneDebug() const override { return true; }
+ void
+ addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
protected:
Tool *buildAssembler() const override;
diff --git a/clang/lib/Driver/ToolChains/Fuchsia.cpp b/clang/lib/Driver/ToolChains/Fuchsia.cpp
index e7d38ff9f227..808d0408d0d4 100644
--- a/clang/lib/Driver/ToolChains/Fuchsia.cpp
+++ b/clang/lib/Driver/ToolChains/Fuchsia.cpp
@@ -46,6 +46,9 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// handled somewhere else.
Args.ClaimAllArgs(options::OPT_w);
+ CmdArgs.push_back("-z");
+ CmdArgs.push_back("now");
+
const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
if (llvm::sys::path::filename(Exec).equals_lower("ld.lld") ||
llvm::sys::path::stem(Exec).equals_lower("ld.lld")) {
@@ -224,7 +227,7 @@ Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple,
std::string Fuchsia::ComputeEffectiveClangTriple(const ArgList &Args,
types::ID InputType) const {
llvm::Triple Triple(ComputeLLVMTriple(Args, InputType));
- return (Triple.getArchName() + "-" + Triple.getOSName()).str();
+ return Triple.str();
}
Tool *Fuchsia::buildLinker() const {
@@ -258,9 +261,9 @@ Fuchsia::GetCXXStdlibType(const ArgList &Args) const {
void Fuchsia::addClangTargetOptions(const ArgList &DriverArgs,
ArgStringList &CC1Args,
Action::OffloadKind) const {
- if (DriverArgs.hasFlag(options::OPT_fuse_init_array,
- options::OPT_fno_use_init_array, true))
- CC1Args.push_back("-fuse-init-array");
+ if (!DriverArgs.hasFlag(options::OPT_fuse_init_array,
+ options::OPT_fno_use_init_array, true))
+ CC1Args.push_back("-fno-use-init-array");
}
void Fuchsia::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
@@ -343,5 +346,17 @@ SanitizerMask Fuchsia::getSupportedSanitizers() const {
}
SanitizerMask Fuchsia::getDefaultSanitizers() const {
- return SanitizerKind::SafeStack;
+ SanitizerMask Res;
+ switch (getTriple().getArch()) {
+ case llvm::Triple::aarch64:
+ Res |= SanitizerKind::ShadowCallStack;
+ break;
+ case llvm::Triple::x86_64:
+ Res |= SanitizerKind::SafeStack;
+ break;
+ default:
+ // TODO: Enable SafeStack on RISC-V once tested.
+ break;
+ }
+ return Res;
}
diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp
index c302a31cd2e1..da197e476621 100644
--- a/clang/lib/Driver/ToolChains/Gnu.cpp
+++ b/clang/lib/Driver/ToolChains/Gnu.cpp
@@ -709,11 +709,9 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C,
StringRef ABIName = riscv::getRISCVABI(Args, getToolChain().getTriple());
CmdArgs.push_back("-mabi");
CmdArgs.push_back(ABIName.data());
- if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
- StringRef MArch = A->getValue();
- CmdArgs.push_back("-march");
- CmdArgs.push_back(MArch.data());
- }
+ StringRef MArchName = riscv::getRISCVArch(Args, getToolChain().getTriple());
+ CmdArgs.push_back("-march");
+ CmdArgs.push_back(MArchName.data());
break;
}
case llvm::Triple::sparc:
@@ -864,12 +862,25 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C,
case llvm::Triple::systemz: {
// Always pass an -march option, since our default of z10 is later
// than the GNU assembler's default.
- StringRef CPUName = systemz::getSystemZTargetCPU(Args);
+ std::string CPUName = systemz::getSystemZTargetCPU(Args);
CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName));
break;
}
}
+ for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ,
+ options::OPT_fdebug_prefix_map_EQ)) {
+ StringRef Map = A->getValue();
+ if (Map.find('=') == StringRef::npos)
+ D.Diag(diag::err_drv_invalid_argument_to_option)
+ << Map << A->getOption().getName();
+ else {
+ CmdArgs.push_back(Args.MakeArgString("--debug-prefix-map"));
+ CmdArgs.push_back(Args.MakeArgString(Map));
+ }
+ A->claim();
+ }
+
Args.AddAllArgs(CmdArgs, options::OPT_I);
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
@@ -1393,7 +1404,8 @@ bool clang::driver::findMIPSMultilibs(const Driver &D,
addMultilibFlag(CPUName == "mips32r6", "march=mips32r6", Flags);
addMultilibFlag(CPUName == "mips64", "march=mips64", Flags);
addMultilibFlag(CPUName == "mips64r2" || CPUName == "mips64r3" ||
- CPUName == "mips64r5" || CPUName == "octeon",
+ CPUName == "mips64r5" || CPUName == "octeon" ||
+ CPUName == "octeon+",
"march=mips64r2", Flags);
addMultilibFlag(CPUName == "mips64r6", "march=mips64r6", Flags);
addMultilibFlag(isMicroMips(Args), "mmicromips", Flags);
@@ -1504,9 +1516,65 @@ static bool findMSP430Multilibs(const Driver &D,
return false;
}
+static void findRISCVBareMetalMultilibs(const Driver &D,
+ const llvm::Triple &TargetTriple,
+ StringRef Path, const ArgList &Args,
+ DetectedMultilibs &Result) {
+ FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
+ struct RiscvMultilib {
+ StringRef march;
+ StringRef mabi;
+ };
+ // currently only support the set of multilibs like riscv-gnu-toolchain does.
+ // TODO: support MULTILIB_REUSE
+ SmallVector<RiscvMultilib, 8> RISCVMultilibSet = {
+ {"rv32i", "ilp32"}, {"rv32im", "ilp32"}, {"rv32iac", "ilp32"},
+ {"rv32imac", "ilp32"}, {"rv32imafc", "ilp32f"}, {"rv64imac", "lp64"},
+ {"rv64imafdc", "lp64d"}};
+
+ std::vector<Multilib> Ms;
+ for (auto Element : RISCVMultilibSet) {
+ // multilib path rule is ${march}/${mabi}
+ Ms.emplace_back(
+ makeMultilib((Twine(Element.march) + "/" + Twine(Element.mabi)).str())
+ .flag(Twine("+march=", Element.march).str())
+ .flag(Twine("+mabi=", Element.mabi).str()));
+ }
+ MultilibSet RISCVMultilibs =
+ MultilibSet()
+ .Either(ArrayRef<Multilib>(Ms))
+ .FilterOut(NonExistent)
+ .setFilePathsCallback([](const Multilib &M) {
+ return std::vector<std::string>(
+ {M.gccSuffix(),
+ "/../../../../riscv64-unknown-elf/lib" + M.gccSuffix(),
+ "/../../../../riscv32-unknown-elf/lib" + M.gccSuffix()});
+ });
+
+
+ Multilib::flags_list Flags;
+ llvm::StringSet<> Added_ABIs;
+ StringRef ABIName = tools::riscv::getRISCVABI(Args, TargetTriple);
+ StringRef MArch = tools::riscv::getRISCVArch(Args, TargetTriple);
+ for (auto Element : RISCVMultilibSet) {
+ addMultilibFlag(MArch == Element.march,
+ Twine("march=", Element.march).str().c_str(), Flags);
+ if (!Added_ABIs.count(Element.mabi)) {
+ Added_ABIs.insert(Element.mabi);
+ addMultilibFlag(ABIName == Element.mabi,
+ Twine("mabi=", Element.mabi).str().c_str(), Flags);
+ }
+ }
+
+ if (RISCVMultilibs.select(Flags, Result.SelectedMultilib))
+ Result.Multilibs = RISCVMultilibs;
+}
+
static void findRISCVMultilibs(const Driver &D,
const llvm::Triple &TargetTriple, StringRef Path,
const ArgList &Args, DetectedMultilibs &Result) {
+ if (TargetTriple.getOS() == llvm::Triple::UnknownOS)
+ return findRISCVBareMetalMultilibs(D, TargetTriple, Path, Args, Result);
FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
Multilib Ilp32 = makeMultilib("lib32/ilp32").flag("+m32").flag("+mabi=ilp32");
@@ -2002,7 +2070,9 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
static const char *const PPCLibDirs[] = {"/lib32", "/lib"};
static const char *const PPCTriples[] = {
"powerpc-linux-gnu", "powerpc-unknown-linux-gnu", "powerpc-linux-gnuspe",
- "powerpc-suse-linux", "powerpc-montavista-linuxspe"};
+ // On 32-bit PowerPC systems running SUSE Linux, gcc is configured as a
+ // 64-bit compiler which defaults to "-m32", hence "powerpc64-suse-linux".
+ "powerpc64-suse-linux", "powerpc-montavista-linuxspe"};
static const char *const PPC64LibDirs[] = {"/lib64", "/lib"};
static const char *const PPC64Triples[] = {
"powerpc64-linux-gnu", "powerpc64-unknown-linux-gnu",
@@ -2545,9 +2615,6 @@ bool Generic_GCC::isPICDefault() const {
switch (getArch()) {
case llvm::Triple::x86_64:
return getTriple().isOSWindows();
- case llvm::Triple::ppc64:
- // Big endian PPC is PIC by default
- return !getTriple().isOSBinFormatMachO() && !getTriple().isMacOSX();
case llvm::Triple::mips64:
case llvm::Triple::mips64el:
return true;
@@ -2616,19 +2683,49 @@ void Generic_GCC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
}
}
-void
-Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const {
- // FIXME: The Linux behavior would probaby be a better approach here.
- addSystemInclude(DriverArgs, CC1Args,
- getDriver().SysRoot + "/usr/include/c++/v1");
+static std::string DetectLibcxxIncludePath(llvm::vfs::FileSystem &vfs,
+ StringRef base) {
+ std::error_code EC;
+ int MaxVersion = 0;
+ std::string MaxVersionString;
+ for (llvm::vfs::directory_iterator LI = vfs.dir_begin(base, EC), LE;
+ !EC && LI != LE; LI = LI.increment(EC)) {
+ StringRef VersionText = llvm::sys::path::filename(LI->path());
+ int Version;
+ if (VersionText[0] == 'v' &&
+ !VersionText.slice(1, StringRef::npos).getAsInteger(10, Version)) {
+ if (Version > MaxVersion) {
+ MaxVersion = Version;
+ MaxVersionString = VersionText;
+ }
+ }
+ }
+ return MaxVersion ? (base + "/" + MaxVersionString).str() : "";
}
void
-Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const {
- // By default, we don't assume we know where libstdc++ might be installed.
- // FIXME: If we have a valid GCCInstallation, use it.
+Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ const std::string& SysRoot = getDriver().SysRoot;
+ auto AddIncludePath = [&](std::string Path) {
+ std::string IncludePath = DetectLibcxxIncludePath(getVFS(), Path);
+ if (IncludePath.empty() || !getVFS().exists(IncludePath))
+ return false;
+ addSystemInclude(DriverArgs, CC1Args, IncludePath);
+ return true;
+ };
+ // Android never uses the libc++ headers installed alongside the toolchain,
+ // which are generally incompatible with the NDK libraries anyway.
+ if (!getTriple().isAndroid())
+ if (AddIncludePath(getDriver().Dir + "/../include/c++"))
+ return;
+ // If this is a development, non-installed, clang, libcxx will
+ // not be found at ../include/c++ but it likely to be found at
+ // one of the following two locations:
+ if (AddIncludePath(SysRoot + "/usr/local/include/c++"))
+ return;
+ if (AddIncludePath(SysRoot + "/usr/include/c++"))
+ return;
}
/// Helper to add the variant paths of a libstdc++ installation.
@@ -2664,6 +2761,60 @@ bool Generic_GCC::addLibStdCXXIncludePaths(
return true;
}
+bool
+Generic_GCC::addGCCLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ // Use GCCInstallation to know where libstdc++ headers are installed.
+ if (!GCCInstallation.isValid())
+ return false;
+
+ // By default, look for the C++ headers in an include directory adjacent to
+ // the lib directory of the GCC installation. Note that this is expect to be
+ // equivalent to '/usr/include/c++/X.Y' in almost all cases.
+ StringRef LibDir = GCCInstallation.getParentLibPath();
+ StringRef InstallDir = GCCInstallation.getInstallPath();
+ StringRef TripleStr = GCCInstallation.getTriple().str();
+ const Multilib &Multilib = GCCInstallation.getMultilib();
+ const std::string GCCMultiarchTriple = getMultiarchTriple(
+ getDriver(), GCCInstallation.getTriple(), getDriver().SysRoot);
+ const std::string TargetMultiarchTriple =
+ getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot);
+ const GCCVersion &Version = GCCInstallation.getVersion();
+
+ // The primary search for libstdc++ supports multiarch variants.
+ if (addLibStdCXXIncludePaths(LibDir.str() + "/../include",
+ "/c++/" + Version.Text, TripleStr,
+ GCCMultiarchTriple, TargetMultiarchTriple,
+ Multilib.includeSuffix(), DriverArgs, CC1Args))
+ return true;
+
+ // Otherwise, fall back on a bunch of options which don't use multiarch
+ // layouts for simplicity.
+ const std::string LibStdCXXIncludePathCandidates[] = {
+ // Gentoo is weird and places its headers inside the GCC install,
+ // so if the first attempt to find the headers fails, try these patterns.
+ InstallDir.str() + "/include/g++-v" + Version.Text,
+ InstallDir.str() + "/include/g++-v" + Version.MajorStr + "." +
+ Version.MinorStr,
+ InstallDir.str() + "/include/g++-v" + Version.MajorStr,
+ };
+
+ for (const auto &IncludePath : LibStdCXXIncludePathCandidates) {
+ if (addLibStdCXXIncludePaths(IncludePath, /*Suffix*/ "", TripleStr,
+ /*GCCMultiarchTriple*/ "",
+ /*TargetMultiarchTriple*/ "",
+ Multilib.includeSuffix(), DriverArgs, CC1Args))
+ return true;
+ }
+ return false;
+}
+
+void
+Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args);
+}
+
llvm::opt::DerivedArgList *
Generic_GCC::TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef,
Action::OffloadKind DeviceOffloadKind) const {
@@ -2712,23 +2863,7 @@ void Generic_ELF::anchor() {}
void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs,
ArgStringList &CC1Args,
Action::OffloadKind) const {
- const Generic_GCC::GCCVersion &V = GCCInstallation.getVersion();
- bool UseInitArrayDefault =
- getTriple().getArch() == llvm::Triple::aarch64 ||
- getTriple().getArch() == llvm::Triple::aarch64_be ||
- (getTriple().isOSFreeBSD() &&
- getTriple().getOSMajorVersion() >= 12) ||
- (getTriple().getOS() == llvm::Triple::Linux &&
- ((!GCCInstallation.isValid() || !V.isOlderThan(4, 7, 0)) ||
- getTriple().isAndroid())) ||
- getTriple().getOS() == llvm::Triple::NaCl ||
- (getTriple().getVendor() == llvm::Triple::MipsTechnologies &&
- !getTriple().hasEnvironment()) ||
- getTriple().getOS() == llvm::Triple::Solaris ||
- getTriple().getArch() == llvm::Triple::riscv32 ||
- getTriple().getArch() == llvm::Triple::riscv64;
-
- if (DriverArgs.hasFlag(options::OPT_fuse_init_array,
- options::OPT_fno_use_init_array, UseInitArrayDefault))
- CC1Args.push_back("-fuse-init-array");
+ if (!DriverArgs.hasFlag(options::OPT_fuse_init_array,
+ options::OPT_fno_use_init_array, true))
+ CC1Args.push_back("-fno-use-init-array");
}
diff --git a/clang/lib/Driver/ToolChains/Gnu.h b/clang/lib/Driver/ToolChains/Gnu.h
index 3bb38c498b35..083f74c05477 100644
--- a/clang/lib/Driver/ToolChains/Gnu.h
+++ b/clang/lib/Driver/ToolChains/Gnu.h
@@ -300,6 +300,11 @@ protected:
Tool *buildAssembler() const override;
Tool *buildLinker() const override;
+ virtual std::string getMultiarchTriple(const Driver &D,
+ const llvm::Triple &TargetTriple,
+ StringRef SysRoot) const
+ { return TargetTriple.str(); }
+
/// \name ToolChain Implementation Helper Functions
/// @{
@@ -322,6 +327,10 @@ protected:
addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const;
+ bool
+ addGCCLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+
bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix, StringRef GCCTriple,
StringRef GCCMultiarchTriple,
StringRef TargetMultiarchTriple,
diff --git a/clang/lib/Driver/ToolChains/HIP.cpp b/clang/lib/Driver/ToolChains/HIP.cpp
index ad9384df6a24..f89e648948ab 100644
--- a/clang/lib/Driver/ToolChains/HIP.cpp
+++ b/clang/lib/Driver/ToolChains/HIP.cpp
@@ -62,6 +62,34 @@ static const char *getOutputFileName(Compilation &C, StringRef Base,
}
return OutputFileName;
}
+
+static void addOptLevelArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs,
+ bool IsLlc = false) {
+ if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
+ StringRef OOpt = "3";
+ 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", IsLlc ? "2" : "s")
+ .Case("z", IsLlc ? "2" : "z")
+ .Case("g", "1")
+ .Default("2");
+ }
+ CmdArgs.push_back(Args.MakeArgString("-O" + OOpt));
+ }
+}
} // namespace
const char *AMDGCN::Linker::constructLLVMLinkCommand(
@@ -93,25 +121,7 @@ const char *AMDGCN::Linker::constructOptCommand(
// The input to opt is the output from llvm-link.
OptArgs.push_back(InputFileName);
// Pass optimization arg to opt.
- if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
- StringRef OOpt = "3";
- 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)) {
- // -Os, -Oz, and -O(anything else) map to -O2
- OOpt = llvm::StringSwitch<const char *>(A->getValue())
- .Case("1", "1")
- .Case("2", "2")
- .Case("3", "3")
- .Case("s", "2")
- .Case("z", "2")
- .Default("2");
- }
- OptArgs.push_back(Args.MakeArgString("-O" + OOpt));
- }
+ addOptLevelArgs(Args, OptArgs);
OptArgs.push_back("-mtriple=amdgcn-amd-amdhsa");
OptArgs.push_back(Args.MakeArgString("-mcpu=" + SubArchName));
@@ -136,10 +146,15 @@ const char *AMDGCN::Linker::constructLlcCommand(
llvm::StringRef OutputFilePrefix, const char *InputFileName,
bool OutputIsAsm) const {
// Construct llc command.
- ArgStringList LlcArgs{
- InputFileName, "-mtriple=amdgcn-amd-amdhsa",
- Args.MakeArgString(Twine("-filetype=") + (OutputIsAsm ? "asm" : "obj")),
- Args.MakeArgString("-mcpu=" + SubArchName)};
+ ArgStringList LlcArgs;
+ // The input to llc is the output from opt.
+ LlcArgs.push_back(InputFileName);
+ // Pass optimization arg to llc.
+ addOptLevelArgs(Args, LlcArgs, /*IsLlc=*/true);
+ LlcArgs.push_back("-mtriple=amdgcn-amd-amdhsa");
+ LlcArgs.push_back(Args.MakeArgString("-mcpu=" + SubArchName));
+ LlcArgs.push_back(
+ Args.MakeArgString(Twine("-filetype=") + (OutputIsAsm ? "asm" : "obj")));
// Extract all the -m options
std::vector<llvm::StringRef> Features;
@@ -292,6 +307,20 @@ void HIPToolChain::addClangTargetOptions(
false))
CC1Args.push_back("-fgpu-rdc");
+ StringRef MaxThreadsPerBlock =
+ 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();
+ CC1Args.push_back(DriverArgs.MakeArgStringRef(ArgStr));
+ }
+
+ if (DriverArgs.hasFlag(options::OPT_fgpu_allow_device_init,
+ options::OPT_fno_gpu_allow_device_init, false))
+ CC1Args.push_back("-fgpu-allow-device-init");
+
+ CC1Args.push_back("-fcuda-allow-variadic-functions");
+
// Default to "hidden" visibility, as object level linking will not be
// supported for the foreseeable future.
if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ,
@@ -337,9 +366,8 @@ void HIPToolChain::addClangTargetOptions(
else
WaveFrontSizeBC = "oclc_wavefrontsize64_off.amdgcn.bc";
- BCLibs.append({"hip.amdgcn.bc", "opencl.amdgcn.bc", "ocml.amdgcn.bc",
- "ockl.amdgcn.bc", "oclc_finite_only_off.amdgcn.bc",
- FlushDenormalControlBC,
+ BCLibs.append({"hip.amdgcn.bc", "ocml.amdgcn.bc", "ockl.amdgcn.bc",
+ "oclc_finite_only_off.amdgcn.bc", FlushDenormalControlBC,
"oclc_correctly_rounded_sqrt_on.amdgcn.bc",
"oclc_unsafe_math_off.amdgcn.bc", ISAVerBC,
WaveFrontSizeBC});
diff --git a/clang/lib/Driver/ToolChains/HIP.h b/clang/lib/Driver/ToolChains/HIP.h
index 2d146ce5cc6f..c4f944e458bf 100644
--- a/clang/lib/Driver/ToolChains/HIP.h
+++ b/clang/lib/Driver/ToolChains/HIP.h
@@ -113,7 +113,7 @@ public:
computeMSVCVersion(const Driver *D,
const llvm::opt::ArgList &Args) const override;
- unsigned GetDefaultDwarfVersion() const override { return 2; }
+ unsigned GetDefaultDwarfVersion() const override { return 4; }
const ToolChain &HostTC;
diff --git a/clang/lib/Driver/ToolChains/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp
index 96cc084e2821..e4d9ea8a70f9 100644
--- a/clang/lib/Driver/ToolChains/Hexagon.cpp
+++ b/clang/lib/Driver/ToolChains/Hexagon.cpp
@@ -209,7 +209,11 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
bool IncStartFiles = !Args.hasArg(options::OPT_nostartfiles);
bool IncDefLibs = !Args.hasArg(options::OPT_nodefaultlibs);
bool UseG0 = false;
+ const char *Exec = Args.MakeArgString(HTC.GetLinkerPath());
+ bool UseLLD = (llvm::sys::path::filename(Exec).equals_lower("ld.lld") ||
+ llvm::sys::path::stem(Exec).equals_lower("ld.lld"));
bool UseShared = IsShared && !IsStatic;
+ StringRef CpuVer = toolchains::HexagonToolChain::GetTargetCPUVersion(Args);
//----------------------------------------------------------------------------
// Silence warnings for various options
@@ -232,9 +236,10 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
for (const auto &Opt : HTC.ExtraOpts)
CmdArgs.push_back(Opt.c_str());
- CmdArgs.push_back("-march=hexagon");
- StringRef CpuVer = toolchains::HexagonToolChain::GetTargetCPUVersion(Args);
- CmdArgs.push_back(Args.MakeArgString("-mcpu=hexagon" + CpuVer));
+ if (!UseLLD) {
+ CmdArgs.push_back("-march=hexagon");
+ CmdArgs.push_back(Args.MakeArgString("-mcpu=hexagon" + CpuVer));
+ }
if (IsShared) {
CmdArgs.push_back("-shared");
@@ -574,7 +579,7 @@ const StringRef HexagonToolChain::GetDefaultCPU() {
const StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) {
Arg *CpuArg = nullptr;
- if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ, options::OPT_march_EQ))
+ if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
CpuArg = A;
StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU();
diff --git a/clang/lib/Driver/ToolChains/Hurd.cpp b/clang/lib/Driver/ToolChains/Hurd.cpp
index 92b0a7f2483f..72166ca9f359 100644
--- a/clang/lib/Driver/ToolChains/Hurd.cpp
+++ b/clang/lib/Driver/ToolChains/Hurd.cpp
@@ -27,9 +27,9 @@ using tools::addPathIfExists;
/// a target-triple directory in the library and header search paths.
/// Unfortunately, this triple does not align with the vanilla target triple,
/// so we provide a rough mapping here.
-static std::string getMultiarchTriple(const Driver &D,
- const llvm::Triple &TargetTriple,
- StringRef SysRoot) {
+std::string Hurd::getMultiarchTriple(const Driver &D,
+ const llvm::Triple &TargetTriple,
+ StringRef SysRoot) const {
if (TargetTriple.getArch() == llvm::Triple::x86) {
// We use the existence of '/lib/<triple>' as a directory to detect some
// common hurd triples that don't quite match the Clang triple for both
@@ -70,6 +70,10 @@ Hurd::Hurd(const Driver &D, const llvm::Triple &Triple,
const std::string OSLibDir = getOSLibDir(Triple, Args);
const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot);
+#ifdef ENABLE_LINKER_BUILD_ID
+ ExtraOpts.push_back("--build-id");
+#endif
+
// If we are currently running Clang inside of the requested system root, add
// its parent library paths to those searched.
// FIXME: It's not clear whether we should use the driver's installed
diff --git a/clang/lib/Driver/ToolChains/Hurd.h b/clang/lib/Driver/ToolChains/Hurd.h
index a2c3d074e9f9..86c6c3f734dd 100644
--- a/clang/lib/Driver/ToolChains/Hurd.h
+++ b/clang/lib/Driver/ToolChains/Hurd.h
@@ -36,6 +36,10 @@ public:
protected:
Tool *buildAssembler() const override;
Tool *buildLinker() const override;
+
+ std::string getMultiarchTriple(const Driver &D,
+ const llvm::Triple &TargetTriple,
+ StringRef SysRoot) const override;
};
} // end namespace toolchains
diff --git a/clang/lib/Driver/ToolChains/InterfaceStubs.cpp b/clang/lib/Driver/ToolChains/InterfaceStubs.cpp
index 6677843b2c53..8f947e79bd1f 100644
--- a/clang/lib/Driver/ToolChains/InterfaceStubs.cpp
+++ b/clang/lib/Driver/ToolChains/InterfaceStubs.cpp
@@ -9,6 +9,7 @@
#include "InterfaceStubs.h"
#include "CommonArgs.h"
#include "clang/Driver/Compilation.h"
+#include "llvm/Support/Path.h"
namespace clang {
namespace driver {
@@ -21,13 +22,38 @@ void Merger::ConstructJob(Compilation &C, const JobAction &JA,
std::string Merger = getToolChain().GetProgramPath(getShortName());
llvm::opt::ArgStringList CmdArgs;
CmdArgs.push_back("-action");
- CmdArgs.push_back(Args.getLastArg(options::OPT_emit_merged_ifs)
- ? "write-ifs"
- : "write-bin");
+ const bool WriteBin = !Args.getLastArg(options::OPT_emit_merged_ifs);
+ CmdArgs.push_back(WriteBin ? "write-bin" : "write-ifs");
CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
- for (const auto &Input : Inputs)
- CmdArgs.push_back(Input.getFilename());
+
+ // Normally we want to write to a side-car file ending in ".ifso" so for
+ // example if `clang -emit-interface-stubs -shared -o libhello.so` were
+ // invoked then we would like to get libhello.so and libhello.ifso. If the
+ // stdout stream is given as the output file (ie `-o -`), that is the one
+ // exception where we will just append to the same filestream as the normal
+ // output.
+ SmallString<128> OutputFilename(Output.getFilename());
+ if (OutputFilename != "-") {
+ if (Args.hasArg(options::OPT_shared))
+ llvm::sys::path::replace_extension(OutputFilename,
+ (WriteBin ? "ifso" : "ifs"));
+ else
+ OutputFilename += (WriteBin ? ".ifso" : ".ifs");
+ }
+
+ CmdArgs.push_back(Args.MakeArgString(OutputFilename.c_str()));
+
+ // Here we append the input files. If the input files are object files, then
+ // we look for .ifs files present in the same location as the object files.
+ for (const auto &Input : Inputs) {
+ if (!Input.isFilename())
+ continue;
+ SmallString<128> InputFilename(Input.getFilename());
+ if (Input.getType() == types::TY_Object)
+ llvm::sys::path::replace_extension(InputFilename, ".ifs");
+ CmdArgs.push_back(Args.MakeArgString(InputFilename.c_str()));
+ }
+
C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Merger),
CmdArgs, Inputs));
}
diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp
index 087783875ffe..bff1ab1009be 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -37,9 +37,9 @@ using tools::addPathIfExists;
/// a target-triple directory in the library and header search paths.
/// Unfortunately, this triple does not align with the vanilla target triple,
/// so we provide a rough mapping here.
-static std::string getMultiarchTriple(const Driver &D,
+std::string Linux::getMultiarchTriple(const Driver &D,
const llvm::Triple &TargetTriple,
- StringRef SysRoot) {
+ StringRef SysRoot) const {
llvm::Triple::EnvironmentType TargetEnvironment =
TargetTriple.getEnvironment();
bool IsAndroid = TargetTriple.isAndroid();
@@ -240,7 +240,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
.str());
}
- Distro Distro(D.getVFS());
+ Distro Distro(D.getVFS(), Triple);
if (Distro.IsAlpineLinux() || Triple.isAndroid()) {
ExtraOpts.push_back("-z");
@@ -511,7 +511,7 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const {
const llvm::Triple::ArchType Arch = getArch();
const llvm::Triple &Triple = getTriple();
- const Distro Distro(getDriver().getVFS());
+ const Distro Distro(getDriver().getVFS(), Triple);
if (Triple.isAndroid())
return Triple.isArch64Bit() ? "/system/bin/linker64" : "/system/bin/linker";
@@ -865,81 +865,23 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);
}
-static std::string DetectLibcxxIncludePath(llvm::vfs::FileSystem &vfs,
- StringRef base) {
- std::error_code EC;
- int MaxVersion = 0;
- std::string MaxVersionString = "";
- for (llvm::vfs::directory_iterator LI = vfs.dir_begin(base, EC), LE;
- !EC && LI != LE; LI = LI.increment(EC)) {
- StringRef VersionText = llvm::sys::path::filename(LI->path());
- int Version;
- if (VersionText[0] == 'v' &&
- !VersionText.slice(1, StringRef::npos).getAsInteger(10, Version)) {
- if (Version > MaxVersion) {
- MaxVersion = Version;
- MaxVersionString = VersionText;
- }
- }
- }
- return MaxVersion ? (base + "/" + MaxVersionString).str() : "";
-}
-
-void Linux::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const {
- const std::string& SysRoot = computeSysRoot();
- const std::string LibCXXIncludePathCandidates[] = {
- DetectLibcxxIncludePath(getVFS(), getDriver().Dir + "/../include/c++"),
- // If this is a development, non-installed, clang, libcxx will
- // not be found at ../include/c++ but it likely to be found at
- // one of the following two locations:
- DetectLibcxxIncludePath(getVFS(), SysRoot + "/usr/local/include/c++"),
- DetectLibcxxIncludePath(getVFS(), SysRoot + "/usr/include/c++") };
- for (const auto &IncludePath : LibCXXIncludePathCandidates) {
- if (IncludePath.empty() || !getVFS().exists(IncludePath))
- continue;
- // Use the first candidate that exists.
- addSystemInclude(DriverArgs, CC1Args, IncludePath);
- return;
- }
-}
-
void Linux::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
+ // Try generic GCC detection first.
+ if (Generic_GCC::addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args))
+ return;
+
// We need a detected GCC installation on Linux to provide libstdc++'s
- // headers.
+ // headers in odd Linuxish places.
if (!GCCInstallation.isValid())
return;
- // By default, look for the C++ headers in an include directory adjacent to
- // the lib directory of the GCC installation. Note that this is expect to be
- // equivalent to '/usr/include/c++/X.Y' in almost all cases.
StringRef LibDir = GCCInstallation.getParentLibPath();
- StringRef InstallDir = GCCInstallation.getInstallPath();
StringRef TripleStr = GCCInstallation.getTriple().str();
const Multilib &Multilib = GCCInstallation.getMultilib();
- const std::string GCCMultiarchTriple = getMultiarchTriple(
- getDriver(), GCCInstallation.getTriple(), getDriver().SysRoot);
- const std::string TargetMultiarchTriple =
- getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot);
const GCCVersion &Version = GCCInstallation.getVersion();
- // The primary search for libstdc++ supports multiarch variants.
- if (addLibStdCXXIncludePaths(LibDir.str() + "/../include",
- "/c++/" + Version.Text, TripleStr,
- GCCMultiarchTriple, TargetMultiarchTriple,
- Multilib.includeSuffix(), DriverArgs, CC1Args))
- return;
-
- // Otherwise, fall back on a bunch of options which don't use multiarch
- // layouts for simplicity.
const std::string LibStdCXXIncludePathCandidates[] = {
- // Gentoo is weird and places its headers inside the GCC install,
- // so if the first attempt to find the headers fails, try these patterns.
- InstallDir.str() + "/include/g++-v" + Version.Text,
- InstallDir.str() + "/include/g++-v" + Version.MajorStr + "." +
- Version.MinorStr,
- InstallDir.str() + "/include/g++-v" + Version.MajorStr,
// Android standalone toolchain has C++ headers in yet another place.
LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text,
// Freescale SDK C++ headers are directly in <sysroot>/usr/include/c++,
diff --git a/clang/lib/Driver/ToolChains/Linux.h b/clang/lib/Driver/ToolChains/Linux.h
index 4c61994691c7..f5518eac218a 100644
--- a/clang/lib/Driver/ToolChains/Linux.h
+++ b/clang/lib/Driver/ToolChains/Linux.h
@@ -26,9 +26,6 @@ public:
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;
void addLibStdCxxIncludePaths(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
@@ -52,6 +49,10 @@ public:
protected:
Tool *buildAssembler() const override;
Tool *buildLinker() const override;
+
+ std::string getMultiarchTriple(const Driver &D,
+ const llvm::Triple &TargetTriple,
+ StringRef SysRoot) const override;
};
} // end namespace toolchains
diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp
index 1d31844bfcc8..4e143f6a5d3f 100644
--- a/clang/lib/Driver/ToolChains/MSVC.cpp
+++ b/clang/lib/Driver/ToolChains/MSVC.cpp
@@ -422,6 +422,17 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link);
+ // Control Flow Guard checks
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) {
+ StringRef GuardArgs = A->getValue();
+ if (GuardArgs.equals_lower("cf") || GuardArgs.equals_lower("cf,nochecks")) {
+ // MSVC doesn't yet support the "nochecks" modifier.
+ CmdArgs.push_back("-guard:cf");
+ } else if (GuardArgs.equals_lower("cf-")) {
+ CmdArgs.push_back("-guard:cf-");
+ }
+ }
+
if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
options::OPT_fno_openmp, false)) {
CmdArgs.push_back("-nodefaultlib:vcomp.lib");
@@ -679,6 +690,17 @@ std::unique_ptr<Command> visualstudio::Compiler::GetCommand(
: "/Zc:threadSafeInit-");
}
+ // Control Flow Guard checks
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) {
+ StringRef GuardArgs = A->getValue();
+ if (GuardArgs.equals_lower("cf") || GuardArgs.equals_lower("cf,nochecks")) {
+ // MSVC doesn't yet support the "nochecks" modifier.
+ CmdArgs.push_back("/guard:cf");
+ } else if (GuardArgs.equals_lower("cf-")) {
+ CmdArgs.push_back("/guard:cf-");
+ }
+ }
+
// Pass through all unknown arguments so that the fallback command can see
// them too.
Args.AddAllArgs(CmdArgs, options::OPT_UNKNOWN);
diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp
index 0d851114c225..8f24384e688b 100644
--- a/clang/lib/Driver/ToolChains/MinGW.cpp
+++ b/clang/lib/Driver/ToolChains/MinGW.cpp
@@ -160,7 +160,19 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
+ const char *OutputFile = Output.getFilename();
+ // GCC implicitly adds an .exe extension if it is given an output file name
+ // that lacks an extension. However, GCC only does this when actually
+ // running on windows, not when operating as a cross compiler. As some users
+ // have come to rely on this behaviour, try to replicate it.
+#ifdef _WIN32
+ if (!llvm::sys::path::has_extension(OutputFile))
+ CmdArgs.push_back(Args.MakeArgString(Twine(OutputFile) + ".exe"));
+ else
+ CmdArgs.push_back(OutputFile);
+#else
+ CmdArgs.push_back(OutputFile);
+#endif
Args.AddAllArgs(CmdArgs, options::OPT_e);
// FIXME: add -N, -n flags
diff --git a/clang/lib/Driver/ToolChains/NetBSD.cpp b/clang/lib/Driver/ToolChains/NetBSD.cpp
index 405142204199..0100a387d6c3 100644
--- a/clang/lib/Driver/ToolChains/NetBSD.cpp
+++ b/clang/lib/Driver/ToolChains/NetBSD.cpp
@@ -505,7 +505,7 @@ void NetBSD::addClangTargetOptions(const ArgList &DriverArgs,
getTriple().getArch() == llvm::Triple::arm ||
getTriple().getArch() == llvm::Triple::armeb;
- if (DriverArgs.hasFlag(options::OPT_fuse_init_array,
- options::OPT_fno_use_init_array, UseInitArrayDefault))
- CC1Args.push_back("-fuse-init-array");
+ if (!DriverArgs.hasFlag(options::OPT_fuse_init_array,
+ options::OPT_fno_use_init_array, UseInitArrayDefault))
+ CC1Args.push_back("-fno-use-init-array");
}
diff --git a/clang/lib/Driver/ToolChains/OpenBSD.cpp b/clang/lib/Driver/ToolChains/OpenBSD.cpp
index e93f5fcc3d81..80343c0394cb 100644
--- a/clang/lib/Driver/ToolChains/OpenBSD.cpp
+++ b/clang/lib/Driver/ToolChains/OpenBSD.cpp
@@ -267,3 +267,12 @@ Tool *OpenBSD::buildAssembler() const {
}
Tool *OpenBSD::buildLinker() const { return new tools::openbsd::Linker(*this); }
+
+void OpenBSD::addClangTargetOptions(const ArgList &DriverArgs,
+ ArgStringList &CC1Args,
+ Action::OffloadKind) const {
+ // Support for .init_array is still new (Aug 2016).
+ if (!DriverArgs.hasFlag(options::OPT_fuse_init_array,
+ options::OPT_fno_use_init_array, false))
+ CC1Args.push_back("-fno-use-init-array");
+}
diff --git a/clang/lib/Driver/ToolChains/OpenBSD.h b/clang/lib/Driver/ToolChains/OpenBSD.h
index c92d109b7c16..9f1ee0f66402 100644
--- a/clang/lib/Driver/ToolChains/OpenBSD.h
+++ b/clang/lib/Driver/ToolChains/OpenBSD.h
@@ -75,6 +75,11 @@ public:
SanitizerMask getSupportedSanitizers() const override;
+ void
+ addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
+
protected:
Tool *buildAssembler() const override;
Tool *buildLinker() const override;
diff --git a/clang/lib/Driver/ToolChains/PS4CPU.h b/clang/lib/Driver/ToolChains/PS4CPU.h
index e9f0891c1194..18852b2808cb 100644
--- a/clang/lib/Driver/ToolChains/PS4CPU.h
+++ b/clang/lib/Driver/ToolChains/PS4CPU.h
@@ -84,6 +84,10 @@ public:
SanitizerMask getSupportedSanitizers() const override;
+ // PS4 toolchain uses legacy thin LTO API, which is not
+ // capable of unit splitting.
+ bool canSplitThinLTOUnit() const override { return false; }
+
protected:
Tool *buildAssembler() const override;
Tool *buildLinker() const override;
diff --git a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp
index 22dc5117f196..ddc329e3c722 100644
--- a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp
+++ b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp
@@ -7,7 +7,6 @@
//===----------------------------------------------------------------------===//
#include "RISCVToolchain.h"
-#include "Arch/RISCV.h"
#include "CommonArgs.h"
#include "InputInfo.h"
#include "clang/Driver/Compilation.h"
@@ -23,29 +22,60 @@ using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;
+static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs,
+ const Multilib &Multilib,
+ StringRef InstallPath,
+ ToolChain::path_list &Paths) {
+ if (const auto &PathsCallback = Multilibs.filePathsCallback())
+ for (const auto &Path : PathsCallback(Multilib))
+ addPathIfExists(D, InstallPath + Path, Paths);
+}
+
/// RISCV Toolchain
RISCVToolChain::RISCVToolChain(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
: Generic_ELF(D, Triple, Args) {
GCCInstallation.init(Triple, Args);
- getFilePaths().push_back(computeSysRoot() + "/lib");
if (GCCInstallation.isValid()) {
+ Multilibs = GCCInstallation.getMultilibs();
+ SelectedMultilib = GCCInstallation.getMultilib();
+ path_list &Paths = getFilePaths();
+ // Add toolchain/multilib specific file paths.
+ addMultilibsFilePaths(D, Multilibs, SelectedMultilib,
+ GCCInstallation.getInstallPath(), Paths);
getFilePaths().push_back(GCCInstallation.getInstallPath().str());
- getProgramPaths().push_back(
- (GCCInstallation.getParentLibPath() + "/../bin").str());
+ ToolChain::path_list &PPaths = getProgramPaths();
+ // Multilib cross-compiler GCC installations put ld in a triple-prefixed
+ // directory off of the parent of the GCC installation.
+ PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" +
+ GCCInstallation.getTriple().str() + "/bin")
+ .str());
+ PPaths.push_back((GCCInstallation.getParentLibPath() + "/../bin").str());
+ } else {
+ getProgramPaths().push_back(D.Dir);
}
+ getFilePaths().push_back(computeSysRoot() + "/lib");
}
Tool *RISCVToolChain::buildLinker() const {
return new tools::RISCV::Linker(*this);
}
+ToolChain::RuntimeLibType RISCVToolChain::GetDefaultRuntimeLibType() const {
+ return GCCInstallation.isValid() ?
+ ToolChain::RLT_Libgcc : ToolChain::RLT_CompilerRT;
+}
+
+ToolChain::UnwindLibType
+RISCVToolChain::GetUnwindLibType(const llvm::opt::ArgList &Args) const {
+ return ToolChain::UNW_None;
+}
+
void RISCVToolChain::addClangTargetOptions(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
Action::OffloadKind) const {
CC1Args.push_back("-nostdsysteminc");
- CC1Args.push_back("-fuse-init-array");
}
void RISCVToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
@@ -74,17 +104,22 @@ std::string RISCVToolChain::computeSysRoot() const {
if (!getDriver().SysRoot.empty())
return getDriver().SysRoot;
- if (!GCCInstallation.isValid())
- return std::string();
-
- StringRef LibDir = GCCInstallation.getParentLibPath();
- StringRef TripleStr = GCCInstallation.getTriple().str();
- std::string SysRootDir = LibDir.str() + "/../" + TripleStr.str();
+ SmallString<128> SysRootDir;
+ if (GCCInstallation.isValid()) {
+ StringRef LibDir = GCCInstallation.getParentLibPath();
+ StringRef TripleStr = GCCInstallation.getTriple().str();
+ llvm::sys::path::append(SysRootDir, LibDir, "..", TripleStr);
+ } else {
+ // Use the triple as provided to the driver. Unlike the parsed triple
+ // this has not been normalized to always contain every field.
+ llvm::sys::path::append(SysRootDir, getDriver().Dir, "..",
+ getDriver().getTargetTriple());
+ }
if (!llvm::sys::fs::exists(SysRootDir))
return std::string();
- return SysRootDir;
+ return SysRootDir.str();
}
void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA,
@@ -99,20 +134,35 @@ void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (!D.SysRoot.empty())
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
- std::string Linker = getToolChain().GetProgramPath(getShortName());
-
- if (D.isUsingLTO()) {
- assert(!Inputs.empty() && "Must have at least one input.");
- AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0],
- D.getLTOMode() == LTOK_Thin);
+ bool IsRV64 = ToolChain.getArch() == llvm::Triple::riscv64;
+ CmdArgs.push_back("-m");
+ if (IsRV64) {
+ CmdArgs.push_back("elf64lriscv");
+ } else {
+ CmdArgs.push_back("elf32lriscv");
}
+ std::string Linker = getToolChain().GetProgramPath(getShortName());
+
bool WantCRTs =
!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles);
+ const char *crtbegin, *crtend;
+ auto RuntimeLib = ToolChain.GetRuntimeLibType(Args);
+ if (RuntimeLib == ToolChain::RLT_Libgcc) {
+ crtbegin = "crtbegin.o";
+ crtend = "crtend.o";
+ } else {
+ assert (RuntimeLib == ToolChain::RLT_CompilerRT);
+ crtbegin = ToolChain.getCompilerRTArgString(Args, "crtbegin",
+ ToolChain::FT_Object);
+ crtend = ToolChain.getCompilerRTArgString(Args, "crtend",
+ ToolChain::FT_Object);
+ }
+
if (WantCRTs) {
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
}
Args.AddAllArgs(CmdArgs, options::OPT_L);
@@ -133,11 +183,11 @@ void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-lc");
CmdArgs.push_back("-lgloss");
CmdArgs.push_back("--end-group");
- CmdArgs.push_back("-lgcc");
+ AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args);
}
if (WantCRTs)
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend)));
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
diff --git a/clang/lib/Driver/ToolChains/RISCVToolchain.h b/clang/lib/Driver/ToolChains/RISCVToolchain.h
index 673d749d76ff..bb7f64849bcb 100644
--- a/clang/lib/Driver/ToolChains/RISCVToolchain.h
+++ b/clang/lib/Driver/ToolChains/RISCVToolchain.h
@@ -25,7 +25,9 @@ public:
void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
Action::OffloadKind) const override;
- bool HasNativeLLVMSupport() const override { return true; }
+ RuntimeLibType GetDefaultRuntimeLibType() const override;
+ UnwindLibType
+ GetUnwindLibType(const llvm::opt::ArgList &Args) const override;
void
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp
index 3add913b700f..907f86b8233c 100644
--- a/clang/lib/Driver/ToolChains/WebAssembly.cpp
+++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp
@@ -8,6 +8,7 @@
#include "WebAssembly.h"
#include "CommonArgs.h"
+#include "clang/Basic/Version.h"
#include "clang/Config/config.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
@@ -90,6 +91,39 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Output.getFilename());
C.addCommand(std::make_unique<Command>(JA, *this, Linker, CmdArgs, Inputs));
+
+ // When optimizing, if wasm-opt is available, run it.
+ if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
+ auto WasmOptPath = getToolChain().GetProgramPath("wasm-opt");
+ if (WasmOptPath != "wasm-opt") {
+ StringRef OOpt = "s";
+ if (A->getOption().matches(options::OPT_O4) ||
+ A->getOption().matches(options::OPT_Ofast))
+ OOpt = "4";
+ else if (A->getOption().matches(options::OPT_O0))
+ OOpt = "0";
+ else if (A->getOption().matches(options::OPT_O))
+ OOpt = A->getValue();
+
+ if (OOpt != "0") {
+ const char *WasmOpt = Args.MakeArgString(WasmOptPath);
+ ArgStringList CmdArgs;
+ CmdArgs.push_back(Output.getFilename());
+ CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt));
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ C.addCommand(std::make_unique<Command>(JA, *this, WasmOpt, CmdArgs, Inputs));
+ }
+ }
+ }
+}
+
+/// Given a base library directory, append path components to form the
+/// LTO directory.
+static std::string AppendLTOLibDir(const std::string &Dir) {
+ // The version allows the path to be keyed to the specific version of
+ // LLVM in used, as the bitcode format is not stable.
+ return Dir + "/llvm-lto/" LLVM_VERSION_STRING;
}
WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple,
@@ -100,16 +134,24 @@ WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple,
getProgramPaths().push_back(getDriver().getInstalledDir());
+ auto SysRoot = getDriver().SysRoot;
if (getTriple().getOS() == llvm::Triple::UnknownOS) {
// Theoretically an "unknown" OS should mean no standard libraries, however
// it could also mean that a custom set of libraries is in use, so just add
// /lib to the search path. Disable multiarch in this case, to discourage
// paths containing "unknown" from acquiring meanings.
- getFilePaths().push_back(getDriver().SysRoot + "/lib");
+ getFilePaths().push_back(SysRoot + "/lib");
} else {
const std::string MultiarchTriple =
- getMultiarchTriple(getDriver(), Triple, getDriver().SysRoot);
- getFilePaths().push_back(getDriver().SysRoot + "/lib/" + MultiarchTriple);
+ getMultiarchTriple(getDriver(), Triple, SysRoot);
+ if (D.isUsingLTO()) {
+ // For LTO, enable use of lto-enabled sysroot libraries too, if available.
+ // Note that the directory is keyed to the LLVM revision, as LLVM's
+ // bitcode format is not stable.
+ auto Dir = AppendLTOLibDir(SysRoot + "/lib/" + MultiarchTriple);
+ getFilePaths().push_back(Dir);
+ }
+ getFilePaths().push_back(SysRoot + "/lib/" + MultiarchTriple);
}
}
@@ -137,9 +179,9 @@ bool WebAssembly::HasNativeLLVMSupport() const { return true; }
void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs,
ArgStringList &CC1Args,
Action::OffloadKind) const {
- if (DriverArgs.hasFlag(clang::driver::options::OPT_fuse_init_array,
- options::OPT_fno_use_init_array, true))
- CC1Args.push_back("-fuse-init-array");
+ if (!DriverArgs.hasFlag(clang::driver::options::OPT_fuse_init_array,
+ options::OPT_fno_use_init_array, true))
+ CC1Args.push_back("-fno-use-init-array");
// '-pthread' implies atomics, bulk-memory, mutable-globals, and sign-ext
if (DriverArgs.hasFlag(options::OPT_pthread, options::OPT_no_pthread,
@@ -181,6 +223,12 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs,
getDriver().Diag(diag::err_drv_argument_not_allowed_with)
<< "-fwasm-exceptions"
<< "-mno-exception-handling";
+ // '-fwasm-exceptions' is not compatible with '-mno-reference-types'
+ if (DriverArgs.hasFlag(options::OPT_mno_reference_types,
+ options::OPT_mexception_handing, false))
+ getDriver().Diag(diag::err_drv_argument_not_allowed_with)
+ << "-fwasm-exceptions"
+ << "-mno-reference-types";
// '-fwasm-exceptions' is not compatible with
// '-mllvm -enable-emscripten-cxx-exceptions'
for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) {
@@ -189,9 +237,11 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs,
<< "-fwasm-exceptions"
<< "-mllvm -enable-emscripten-cxx-exceptions";
}
- // '-fwasm-exceptions' implies exception-handling
+ // '-fwasm-exceptions' implies exception-handling and reference-types
CC1Args.push_back("-target-feature");
CC1Args.push_back("+exception-handling");
+ CC1Args.push_back("-target-feature");
+ CC1Args.push_back("+reference-types");
}
}
diff --git a/clang/lib/Driver/Types.cpp b/clang/lib/Driver/Types.cpp
index a30710645af3..7d83be2521e7 100644
--- a/clang/lib/Driver/Types.cpp
+++ b/clang/lib/Driver/Types.cpp
@@ -212,6 +212,16 @@ bool types::isHIP(ID Id) {
}
}
+bool types::isFortran(ID Id) {
+ switch (Id) {
+ default:
+ return false;
+
+ case TY_Fortran: case TY_PP_Fortran:
+ return true;
+ }
+}
+
bool types::isSrcFile(ID Id) {
return Id != TY_Object && getPreprocessedType(Id) != TY_INVALID;
}
@@ -320,22 +330,6 @@ void types::getCompilationPhases(const clang::driver::Driver &Driver,
llvm::copy_if(PhaseList, std::back_inserter(P),
[](phases::ID Phase) { return Phase <= phases::Precompile; });
- // Treat Interface Stubs like its own compilation mode.
- else if (DAL.getLastArg(options::OPT_emit_interface_stubs)) {
- llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> IfsModePhaseList;
- llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> &PL = PhaseList;
- phases::ID LastPhase = phases::IfsMerge;
- if (Id != types::TY_IFS) {
- if (DAL.hasArg(options::OPT_c))
- LastPhase = phases::Compile;
- PL = IfsModePhaseList;
- types::getCompilationPhases(types::TY_IFS_CPP, PL);
- }
- llvm::copy_if(PL, std::back_inserter(P), [&](phases::ID Phase) {
- return Phase <= LastPhase;
- });
- }
-
// -{fsyntax-only,-analyze,emit-ast} only run up to the compiler.
else if (DAL.getLastArg(options::OPT_fsyntax_only) ||
DAL.getLastArg(options::OPT_print_supported_cpus) ||
diff --git a/clang/lib/Driver/XRayArgs.cpp b/clang/lib/Driver/XRayArgs.cpp
index 16e7c7ecf36b..a2dd63f9eb77 100644
--- a/clang/lib/Driver/XRayArgs.cpp
+++ b/clang/lib/Driver/XRayArgs.cpp
@@ -70,6 +70,13 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) {
D.Diag(diag::err_drv_clang_unsupported)
<< (std::string(XRayInstrumentOption) + " on " + Triple.str());
}
+
+ // Both XRay and -fpatchable-function-entry use
+ // TargetOpcode::PATCHABLE_FUNCTION_ENTER.
+ if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ))
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << "-fxray-instrument" << A->getSpelling();
+
XRayInstrument = true;
if (const Arg *A =
Args.getLastArg(options::OPT_fxray_instruction_threshold_,
@@ -129,7 +136,7 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) {
// are treated as actual dependencies.
for (const auto &Filename :
Args.getAllArgValues(options::OPT_fxray_always_instrument)) {
- if (llvm::sys::fs::exists(Filename)) {
+ if (D.getVFS().exists(Filename)) {
AlwaysInstrumentFiles.push_back(Filename);
ExtraDeps.push_back(Filename);
} else
@@ -138,7 +145,7 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) {
for (const auto &Filename :
Args.getAllArgValues(options::OPT_fxray_never_instrument)) {
- if (llvm::sys::fs::exists(Filename)) {
+ if (D.getVFS().exists(Filename)) {
NeverInstrumentFiles.push_back(Filename);
ExtraDeps.push_back(Filename);
} else
@@ -147,7 +154,7 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) {
for (const auto &Filename :
Args.getAllArgValues(options::OPT_fxray_attr_list)) {
- if (llvm::sys::fs::exists(Filename)) {
+ if (D.getVFS().exists(Filename)) {
AttrListFiles.push_back(Filename);
ExtraDeps.push_back(Filename);
} else
diff --git a/clang/lib/Format/BreakableToken.cpp b/clang/lib/Format/BreakableToken.cpp
index 09ea5473c0c1..cd0eb0b4324a 100644
--- a/clang/lib/Format/BreakableToken.cpp
+++ b/clang/lib/Format/BreakableToken.cpp
@@ -88,11 +88,11 @@ getCommentSplit(StringRef Text, unsigned ContentStartColumn,
StringRef::size_type SpaceOffset = Text.find_last_of(Blanks, MaxSplitBytes);
- static auto *const kNumberedListRegexp = new llvm::Regex("^[1-9][0-9]?\\.");
+ static const auto kNumberedListRegexp = llvm::Regex("^[1-9][0-9]?\\.");
while (SpaceOffset != StringRef::npos) {
// Do not split before a number followed by a dot: this would be interpreted
// as a numbered list, which would prevent re-flowing in subsequent passes.
- if (kNumberedListRegexp->match(Text.substr(SpaceOffset).ltrim(Blanks)))
+ if (kNumberedListRegexp.match(Text.substr(SpaceOffset).ltrim(Blanks)))
SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
// In JavaScript, some @tags can be followed by {, and machinery that parses
// these comments will fail to understand the comment if followed by a line
@@ -245,7 +245,7 @@ BreakableStringLiteral::BreakableStringLiteral(
BreakableToken::Split BreakableStringLiteral::getSplit(
unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit,
- unsigned ContentStartColumn, llvm::Regex &CommentPragmasRegex) const {
+ unsigned ContentStartColumn, const llvm::Regex &CommentPragmasRegex) const {
return getStringSplit(Line.substr(TailOffset), ContentStartColumn,
ColumnLimit - Postfix.size(), Style.TabWidth, Encoding);
}
@@ -271,7 +271,7 @@ unsigned BreakableComment::getLineCount() const { return Lines.size(); }
BreakableToken::Split
BreakableComment::getSplit(unsigned LineIndex, unsigned TailOffset,
unsigned ColumnLimit, unsigned ContentStartColumn,
- llvm::Regex &CommentPragmasRegex) const {
+ const llvm::Regex &CommentPragmasRegex) const {
// Don't break lines matching the comment pragmas regex.
if (CommentPragmasRegex.match(Content[LineIndex]))
return Split(StringRef::npos, 0);
@@ -316,9 +316,9 @@ static bool mayReflowContent(StringRef Content) {
// Numbered lists may also start with a number followed by '.'
// To avoid issues if a line starts with a number which is actually the end
// of a previous line, we only consider numbers with up to 2 digits.
- static auto *const kNumberedListRegexp = new llvm::Regex("^[1-9][0-9]?\\. ");
+ static const auto kNumberedListRegexp = llvm::Regex("^[1-9][0-9]?\\. ");
hasSpecialMeaningPrefix =
- hasSpecialMeaningPrefix || kNumberedListRegexp->match(Content);
+ hasSpecialMeaningPrefix || kNumberedListRegexp.match(Content);
// Simple heuristic for what to reflow: content should contain at least two
// characters and either the first or second character must be
@@ -458,7 +458,7 @@ BreakableBlockComment::BreakableBlockComment(
BreakableToken::Split BreakableBlockComment::getSplit(
unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit,
- unsigned ContentStartColumn, llvm::Regex &CommentPragmasRegex) const {
+ unsigned ContentStartColumn, const llvm::Regex &CommentPragmasRegex) const {
// Don't break lines matching the comment pragmas regex.
if (CommentPragmasRegex.match(Content[LineIndex]))
return Split(StringRef::npos, 0);
@@ -597,9 +597,8 @@ void BreakableBlockComment::insertBreak(unsigned LineIndex, unsigned TailOffset,
PrefixWithTrailingIndent.size());
}
-BreakableToken::Split
-BreakableBlockComment::getReflowSplit(unsigned LineIndex,
- llvm::Regex &CommentPragmasRegex) const {
+BreakableToken::Split BreakableBlockComment::getReflowSplit(
+ unsigned LineIndex, const llvm::Regex &CommentPragmasRegex) const {
if (!mayReflow(LineIndex, CommentPragmasRegex))
return Split(StringRef::npos, 0);
@@ -706,8 +705,8 @@ BreakableBlockComment::getSplitAfterLastLine(unsigned TailOffset) const {
return Split(StringRef::npos, 0);
}
-bool BreakableBlockComment::mayReflow(unsigned LineIndex,
- llvm::Regex &CommentPragmasRegex) const {
+bool BreakableBlockComment::mayReflow(
+ unsigned LineIndex, const llvm::Regex &CommentPragmasRegex) const {
// Content[LineIndex] may exclude the indent after the '*' decoration. In that
// case, we compute the start of the comment pragma manually.
StringRef IndentContent = Content[LineIndex];
@@ -845,7 +844,7 @@ void BreakableLineCommentSection::insertBreak(
}
BreakableComment::Split BreakableLineCommentSection::getReflowSplit(
- unsigned LineIndex, llvm::Regex &CommentPragmasRegex) const {
+ unsigned LineIndex, const llvm::Regex &CommentPragmasRegex) const {
if (!mayReflow(LineIndex, CommentPragmasRegex))
return Split(StringRef::npos, 0);
@@ -955,7 +954,7 @@ void BreakableLineCommentSection::updateNextToken(LineState &State) const {
}
bool BreakableLineCommentSection::mayReflow(
- unsigned LineIndex, llvm::Regex &CommentPragmasRegex) const {
+ unsigned LineIndex, const llvm::Regex &CommentPragmasRegex) const {
// Line comments have the indent as part of the prefix, so we need to
// recompute the start of the line.
StringRef IndentContent = Content[LineIndex];
diff --git a/clang/lib/Format/BreakableToken.h b/clang/lib/Format/BreakableToken.h
index 72852d59f9c4..a6691300de3b 100644
--- a/clang/lib/Format/BreakableToken.h
+++ b/clang/lib/Format/BreakableToken.h
@@ -155,7 +155,7 @@ public:
/// file.
virtual Split getSplit(unsigned LineIndex, unsigned TailOffset,
unsigned ColumnLimit, unsigned ContentStartColumn,
- llvm::Regex &CommentPragmasRegex) const = 0;
+ const llvm::Regex &CommentPragmasRegex) const = 0;
/// Emits the previously retrieved \p Split via \p Whitespaces.
virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
@@ -190,7 +190,7 @@ public:
/// If the split is not contained within one token, for example when reflowing
/// line comments, returns (0, <length>).
virtual Split getReflowSplit(unsigned LineIndex,
- llvm::Regex &CommentPragmasRegex) const {
+ const llvm::Regex &CommentPragmasRegex) const {
return Split(StringRef::npos, 0);
}
@@ -255,7 +255,7 @@ public:
Split getSplit(unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit,
unsigned ContentStartColumn,
- llvm::Regex &CommentPragmasRegex) const override;
+ const llvm::Regex &CommentPragmasRegex) const override;
void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
unsigned ContentIndent,
WhitespaceManager &Whitespaces) const override;
@@ -298,7 +298,7 @@ public:
unsigned getLineCount() const override;
Split getSplit(unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit,
unsigned ContentStartColumn,
- llvm::Regex &CommentPragmasRegex) const override;
+ const llvm::Regex &CommentPragmasRegex) const override;
void compressWhitespace(unsigned LineIndex, unsigned TailOffset, Split Split,
WhitespaceManager &Whitespaces) const override;
@@ -309,7 +309,7 @@ protected:
// Checks if the content of line LineIndex may be reflown with the previous
// line.
virtual bool mayReflow(unsigned LineIndex,
- llvm::Regex &CommentPragmasRegex) const = 0;
+ const llvm::Regex &CommentPragmasRegex) const = 0;
// Contains the original text of the lines of the block comment.
//
@@ -363,7 +363,7 @@ public:
Split getSplit(unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit,
unsigned ContentStartColumn,
- llvm::Regex &CommentPragmasRegex) const override;
+ const llvm::Regex &CommentPragmasRegex) const override;
unsigned getRangeLength(unsigned LineIndex, unsigned Offset,
StringRef::size_type Length,
unsigned StartColumn) const override;
@@ -375,7 +375,7 @@ public:
unsigned ContentIndent,
WhitespaceManager &Whitespaces) const override;
Split getReflowSplit(unsigned LineIndex,
- llvm::Regex &CommentPragmasRegex) const override;
+ const llvm::Regex &CommentPragmasRegex) const override;
void reflow(unsigned LineIndex,
WhitespaceManager &Whitespaces) const override;
bool introducesBreakBeforeToken() const override;
@@ -384,7 +384,7 @@ public:
Split getSplitAfterLastLine(unsigned TailOffset) const override;
bool mayReflow(unsigned LineIndex,
- llvm::Regex &CommentPragmasRegex) const override;
+ const llvm::Regex &CommentPragmasRegex) const override;
// Contains Javadoc annotations that require additional indent when continued
// on multiple lines.
@@ -448,14 +448,14 @@ public:
unsigned ContentIndent,
WhitespaceManager &Whitespaces) const override;
Split getReflowSplit(unsigned LineIndex,
- llvm::Regex &CommentPragmasRegex) const override;
+ const llvm::Regex &CommentPragmasRegex) const override;
void reflow(unsigned LineIndex,
WhitespaceManager &Whitespaces) const override;
void adaptStartOfLine(unsigned LineIndex,
WhitespaceManager &Whitespaces) const override;
void updateNextToken(LineState &State) const override;
bool mayReflow(unsigned LineIndex,
- llvm::Regex &CommentPragmasRegex) const override;
+ const llvm::Regex &CommentPragmasRegex) const override;
private:
// OriginalPrefix[i] contains the original prefix of line i, including
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index cd44c0be85f0..f12bca48c630 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -467,6 +467,7 @@ template <> struct MappingTraits<FormatStyle> {
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("ExperimentalAutoDetectBinPacking",
@@ -476,6 +477,8 @@ template <> struct MappingTraits<FormatStyle> {
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("IndentCaseLabels", Style.IndentCaseLabels);
IO.mapOptional("IndentGotoLabels", Style.IndentGotoLabels);
IO.mapOptional("IndentPPDirectives", Style.IndentPPDirectives);
@@ -534,16 +537,21 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("SpacesBeforeTrailingComments",
Style.SpacesBeforeTrailingComments);
IO.mapOptional("SpacesInAngles", Style.SpacesInAngles);
+ IO.mapOptional("SpacesInConditionalStatement",
+ Style.SpacesInConditionalStatement);
IO.mapOptional("SpacesInContainerLiterals",
Style.SpacesInContainerLiterals);
IO.mapOptional("SpacesInCStyleCastParentheses",
Style.SpacesInCStyleCastParentheses);
IO.mapOptional("SpacesInParentheses", Style.SpacesInParentheses);
IO.mapOptional("SpacesInSquareBrackets", Style.SpacesInSquareBrackets);
+ IO.mapOptional("SpaceBeforeSquareBrackets",
+ Style.SpaceBeforeSquareBrackets);
IO.mapOptional("Standard", Style.Standard);
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);
}
};
@@ -760,6 +768,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.ConstructorInitializerIndentWidth = 4;
LLVMStyle.ContinuationIndentWidth = 4;
LLVMStyle.Cpp11BracedListStyle = true;
+ LLVMStyle.DeriveLineEnding = true;
LLVMStyle.DerivePointerAlignment = false;
LLVMStyle.ExperimentalAutoDetectBinPacking = false;
LLVMStyle.FixNamespaceComments = true;
@@ -790,6 +799,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.PointerAlignment = FormatStyle::PAS_Right;
LLVMStyle.SpacesBeforeTrailingComments = 1;
LLVMStyle.Standard = FormatStyle::LS_Latest;
+ LLVMStyle.UseCRLF = false;
LLVMStyle.UseTab = FormatStyle::UT_Never;
LLVMStyle.ReflowComments = true;
LLVMStyle.SpacesInParentheses = false;
@@ -807,7 +817,9 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.SpaceBeforeRangeBasedForLoopColon = true;
LLVMStyle.SpaceBeforeAssignmentOperators = true;
LLVMStyle.SpaceBeforeCpp11BracedList = false;
+ LLVMStyle.SpaceBeforeSquareBrackets = false;
LLVMStyle.SpacesInAngles = false;
+ LLVMStyle.SpacesInConditionalStatement = false;
LLVMStyle.PenaltyBreakAssignment = prec::Assignment;
LLVMStyle.PenaltyBreakComment = 300;
@@ -1348,7 +1360,11 @@ public:
WhitespaceManager Whitespaces(
Env.getSourceManager(), Style,
- inputUsesCRLF(Env.getSourceManager().getBufferData(Env.getFileID())));
+ Style.DeriveLineEnding
+ ? inputUsesCRLF(
+ Env.getSourceManager().getBufferData(Env.getFileID()),
+ Style.UseCRLF)
+ : Style.UseCRLF);
ContinuationIndenter Indenter(Style, Tokens.getKeywords(),
Env.getSourceManager(), Whitespaces, Encoding,
BinPackInconclusiveFunctions);
@@ -1369,8 +1385,10 @@ public:
}
private:
- static bool inputUsesCRLF(StringRef Text) {
- return Text.count('\r') * 2 > Text.count('\n');
+ static bool inputUsesCRLF(StringRef Text, bool DefaultToCRLF) {
+ size_t LF = Text.count('\n');
+ size_t CR = Text.count('\r') * 2;
+ return LF == CR ? DefaultToCRLF : CR > LF;
}
bool
@@ -2600,6 +2618,10 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
if (std::error_code EC = FS->makeAbsolute(Path))
return make_string_error(EC.message());
+ llvm::SmallVector<std::string, 2> FilesToLookFor;
+ FilesToLookFor.push_back(".clang-format");
+ FilesToLookFor.push_back("_clang-format");
+
for (StringRef Directory = Path; !Directory.empty();
Directory = llvm::sys::path::parent_path(Directory)) {
@@ -2609,43 +2631,35 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
continue;
}
- SmallString<128> ConfigFile(Directory);
-
- llvm::sys::path::append(ConfigFile, ".clang-format");
- LLVM_DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n");
+ for (const auto &F : FilesToLookFor) {
+ SmallString<128> ConfigFile(Directory);
- Status = FS->status(ConfigFile.str());
- bool FoundConfigFile =
- Status && (Status->getType() == llvm::sys::fs::file_type::regular_file);
- if (!FoundConfigFile) {
- // Try _clang-format too, since dotfiles are not commonly used on Windows.
- ConfigFile = Directory;
- llvm::sys::path::append(ConfigFile, "_clang-format");
+ llvm::sys::path::append(ConfigFile, F);
LLVM_DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n");
+
Status = FS->status(ConfigFile.str());
- FoundConfigFile = Status && (Status->getType() ==
- llvm::sys::fs::file_type::regular_file);
- }
- if (FoundConfigFile) {
- llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
- FS->getBufferForFile(ConfigFile.str());
- if (std::error_code EC = Text.getError())
- return make_string_error(EC.message());
- if (std::error_code ec =
- parseConfiguration(Text.get()->getBuffer(), &Style)) {
- if (ec == ParseError::Unsuitable) {
- if (!UnsuitableConfigFiles.empty())
- UnsuitableConfigFiles.append(", ");
- UnsuitableConfigFiles.append(ConfigFile);
- continue;
+ if (Status &&
+ (Status->getType() == llvm::sys::fs::file_type::regular_file)) {
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
+ FS->getBufferForFile(ConfigFile.str());
+ if (std::error_code EC = Text.getError())
+ return make_string_error(EC.message());
+ if (std::error_code ec =
+ parseConfiguration(Text.get()->getBuffer(), &Style)) {
+ if (ec == ParseError::Unsuitable) {
+ if (!UnsuitableConfigFiles.empty())
+ UnsuitableConfigFiles.append(", ");
+ UnsuitableConfigFiles.append(ConfigFile);
+ continue;
+ }
+ return make_string_error("Error reading " + ConfigFile + ": " +
+ ec.message());
}
- return make_string_error("Error reading " + ConfigFile + ": " +
- ec.message());
+ LLVM_DEBUG(llvm::dbgs()
+ << "Using configuration file " << ConfigFile << "\n");
+ return Style;
}
- LLVM_DEBUG(llvm::dbgs()
- << "Using configuration file " << ConfigFile << "\n");
- return Style;
}
}
if (!UnsuitableConfigFiles.empty())
diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h
index b11f36559a8b..e9cd327754ef 100644
--- a/clang/lib/Format/FormatToken.h
+++ b/clang/lib/Format/FormatToken.h
@@ -60,6 +60,8 @@ namespace format {
TYPE(JsExponentiationEqual) \
TYPE(JsFatArrow) \
TYPE(JsNonNullAssertion) \
+ TYPE(JsNullishCoalescingOperator) \
+ TYPE(JsNullPropagatingOperator) \
TYPE(JsPrivateIdentifier) \
TYPE(JsTypeColon) \
TYPE(JsTypeOperator) \
@@ -405,7 +407,7 @@ struct FormatToken {
bool isMemberAccess() const {
return isOneOf(tok::arrow, tok::period, tok::arrowstar) &&
!isOneOf(TT_DesignatedInitializerPeriod, TT_TrailingReturnArrow,
- TT_LambdaArrow);
+ TT_LambdaArrow, TT_LeadingJavaAnnotation);
}
bool isUnaryOperator() const {
diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp
index 5d8a77577c0b..ef20ba884fb3 100644
--- a/clang/lib/Format/FormatTokenLexer.cpp
+++ b/clang/lib/Format/FormatTokenLexer.cpp
@@ -100,6 +100,10 @@ void FormatTokenLexer::tryMergePreviousTokens() {
static const tok::TokenKind JSExponentiation[] = {tok::star, tok::star};
static const tok::TokenKind JSExponentiationEqual[] = {tok::star,
tok::starequal};
+ static const tok::TokenKind JSNullPropagatingOperator[] = {tok::question,
+ tok::period};
+ static const tok::TokenKind JSNullishOperator[] = {tok::question,
+ tok::question};
// FIXME: Investigate what token type gives the correct operator priority.
if (tryMergeTokens(JSIdentity, TT_BinaryOperator))
@@ -116,6 +120,14 @@ void FormatTokenLexer::tryMergePreviousTokens() {
Tokens.back()->Tok.setKind(tok::starequal);
return;
}
+ if (tryMergeTokens(JSNullishOperator, TT_JsNullishCoalescingOperator))
+ return;
+ if (tryMergeTokens(JSNullPropagatingOperator,
+ TT_JsNullPropagatingOperator)) {
+ // Treat like a regular "." access.
+ Tokens.back()->Tok.setKind(tok::period);
+ return;
+ }
if (tryMergeJSPrivateIdentifier())
return;
}
diff --git a/clang/lib/Format/NamespaceEndCommentsFixer.cpp b/clang/lib/Format/NamespaceEndCommentsFixer.cpp
index 98901cff2681..20b424f86077 100644
--- a/clang/lib/Format/NamespaceEndCommentsFixer.cpp
+++ b/clang/lib/Format/NamespaceEndCommentsFixer.cpp
@@ -92,24 +92,24 @@ bool validEndComment(const FormatToken *RBraceTok, StringRef NamespaceName,
// Matches a valid namespace end comment.
// Valid namespace end comments don't need to be edited.
- static llvm::Regex *const NamespaceCommentPattern =
- new llvm::Regex("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *"
- "namespace( +([a-zA-Z0-9:_]+))?\\.? *(\\*/)?$",
- llvm::Regex::IgnoreCase);
- static llvm::Regex *const NamespaceMacroCommentPattern =
- new llvm::Regex("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *"
- "([a-zA-Z0-9_]+)\\(([a-zA-Z0-9:_]*)\\)\\.? *(\\*/)?$",
- llvm::Regex::IgnoreCase);
+ static const llvm::Regex NamespaceCommentPattern =
+ llvm::Regex("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *"
+ "namespace( +([a-zA-Z0-9:_]+))?\\.? *(\\*/)?$",
+ llvm::Regex::IgnoreCase);
+ static const llvm::Regex NamespaceMacroCommentPattern =
+ llvm::Regex("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *"
+ "([a-zA-Z0-9_]+)\\(([a-zA-Z0-9:_]*)\\)\\.? *(\\*/)?$",
+ llvm::Regex::IgnoreCase);
SmallVector<StringRef, 8> Groups;
if (NamespaceTok->is(TT_NamespaceMacro) &&
- NamespaceMacroCommentPattern->match(Comment->TokenText, &Groups)) {
+ NamespaceMacroCommentPattern.match(Comment->TokenText, &Groups)) {
StringRef NamespaceTokenText = Groups.size() > 4 ? Groups[4] : "";
// The name of the macro must be used.
if (NamespaceTokenText != NamespaceTok->TokenText)
return false;
} else if (NamespaceTok->isNot(tok::kw_namespace) ||
- !NamespaceCommentPattern->match(Comment->TokenText, &Groups)) {
+ !NamespaceCommentPattern.match(Comment->TokenText, &Groups)) {
// Comment does not match regex.
return false;
}
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 1ed35597d075..d5d394e61926 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -950,9 +950,9 @@ private:
if (CurrentToken->isOneOf(tok::star, tok::amp))
CurrentToken->Type = TT_PointerOrReference;
consumeToken();
- if (CurrentToken &&
- CurrentToken->Previous->isOneOf(TT_BinaryOperator, TT_UnaryOperator,
- tok::comma))
+ if (CurrentToken && CurrentToken->Previous->isOneOf(
+ TT_BinaryOperator, TT_UnaryOperator, tok::comma,
+ tok::star, tok::arrow, tok::amp, tok::ampamp))
CurrentToken->Previous->Type = TT_OverloadedOperator;
}
if (CurrentToken) {
@@ -1344,12 +1344,80 @@ private:
Contexts.back().IsExpression = false;
} else if (Current.is(tok::kw_new)) {
Contexts.back().CanBeExpression = false;
- } else if (Current.isOneOf(tok::semi, tok::exclaim)) {
+ } else if (Current.is(tok::semi) ||
+ (Current.is(tok::exclaim) && Current.Previous &&
+ !Current.Previous->is(tok::kw_operator))) {
// This should be the condition or increment in a for-loop.
+ // But not operator !() (can't use TT_OverloadedOperator here as its not
+ // been annotated yet).
Contexts.back().IsExpression = true;
}
}
+ static FormatToken *untilMatchingParen(FormatToken *Current) {
+ // Used when `MatchingParen` is not yet established.
+ int ParenLevel = 0;
+ while (Current) {
+ if (Current->is(tok::l_paren))
+ ParenLevel++;
+ if (Current->is(tok::r_paren))
+ ParenLevel--;
+ if (ParenLevel < 1)
+ break;
+ Current = Current->Next;
+ }
+ return Current;
+ }
+
+ static bool isDeductionGuide(FormatToken &Current) {
+ // Look for a deduction guide template<T> A(...) -> A<...>;
+ if (Current.Previous && Current.Previous->is(tok::r_paren) &&
+ Current.startsSequence(tok::arrow, tok::identifier, tok::less)) {
+ // Find the TemplateCloser.
+ FormatToken *TemplateCloser = Current.Next->Next;
+ int NestingLevel = 0;
+ while (TemplateCloser) {
+ // Skip over an expressions in parens A<(3 < 2)>;
+ if (TemplateCloser->is(tok::l_paren)) {
+ // No Matching Paren yet so skip to matching paren
+ TemplateCloser = untilMatchingParen(TemplateCloser);
+ }
+ if (TemplateCloser->is(tok::less))
+ NestingLevel++;
+ if (TemplateCloser->is(tok::greater))
+ NestingLevel--;
+ if (NestingLevel < 1)
+ break;
+ TemplateCloser = TemplateCloser->Next;
+ }
+ // Assuming we have found the end of the template ensure its followed
+ // with a semi-colon.
+ if (TemplateCloser && TemplateCloser->Next &&
+ TemplateCloser->Next->is(tok::semi) &&
+ Current.Previous->MatchingParen) {
+ // Determine if the identifier `A` prior to the A<..>; is the same as
+ // prior to the A(..)
+ 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) &&
+ LeadingIdentifier->TokenText == Current.Next->TokenText);
+ }
+ }
+ }
+ return false;
+ }
+
void determineTokenType(FormatToken &Current) {
if (!Current.is(TT_Unknown))
// The token type is already known.
@@ -1397,6 +1465,10 @@ private:
!Current.Previous->is(tok::kw_operator)) {
// not auto operator->() -> xxx;
Current.Type = TT_TrailingReturnArrow;
+
+ } else if (isDeductionGuide(Current)) {
+ // Deduction guides trailing arrow " A(...) -> A<T>;".
+ Current.Type = TT_TrailingReturnArrow;
} else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) {
Current.Type = determineStarAmpUsage(Current,
Contexts.back().CanBeExpression &&
@@ -1757,7 +1829,8 @@ private:
// Use heuristics to recognize unary operators.
if (PrevToken->isOneOf(tok::equal, tok::l_paren, tok::comma, tok::l_square,
tok::question, tok::colon, tok::kw_return,
- tok::kw_case, tok::at, tok::l_brace, tok::kw_throw))
+ tok::kw_case, tok::at, tok::l_brace, tok::kw_throw,
+ tok::kw_co_return, tok::kw_co_yield))
return TT_UnaryOperator;
// There can't be two consecutive binary operators.
@@ -2087,11 +2160,22 @@ static bool isFunctionDeclarationName(const FormatToken &Current,
continue;
if (Next->isOneOf(tok::kw_new, tok::kw_delete)) {
// For 'new[]' and 'delete[]'.
- if (Next->Next && Next->Next->is(tok::l_square) && Next->Next->Next &&
- Next->Next->Next->is(tok::r_square))
+ if (Next->Next &&
+ Next->Next->startsSequence(tok::l_square, tok::r_square))
Next = Next->Next->Next;
continue;
}
+ if (Next->startsSequence(tok::l_square, tok::r_square)) {
+ // For operator[]().
+ Next = Next->Next;
+ continue;
+ }
+ if ((Next->isSimpleTypeSpecifier() || Next->is(tok::identifier)) &&
+ Next->Next && Next->Next->isOneOf(tok::star, tok::amp, tok::ampamp)) {
+ // For operator void*(), operator char*(), operator Foo*().
+ Next = Next->Next;
+ continue;
+ }
break;
}
@@ -2508,6 +2592,13 @@ bool TokenAnnotator::spaceRequiredBeforeParens(const FormatToken &Right) const {
Right.ParameterCount > 0);
}
+/// Returns \c true if the token is followed by a boolean condition, \c false
+/// otherwise.
+static bool isKeywordWithCondition(const FormatToken &Tok) {
+ return Tok.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch,
+ tok::kw_constexpr);
+}
+
bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
const FormatToken &Left,
const FormatToken &Right) {
@@ -2526,6 +2617,15 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
(Left.is(tok::l_brace) && Left.BlockKind != BK_Block &&
Right.is(tok::r_brace) && Right.BlockKind != BK_Block))
return Style.SpaceInEmptyParentheses;
+ if (Style.SpacesInConditionalStatement) {
+ if (Left.is(tok::l_paren) && Left.Previous &&
+ isKeywordWithCondition(*Left.Previous))
+ return true;
+ if (Right.is(tok::r_paren) && Right.MatchingParen &&
+ Right.MatchingParen->Previous &&
+ isKeywordWithCondition(*Right.MatchingParen->Previous))
+ return true;
+ }
if (Left.is(tok::l_paren) || Right.is(tok::r_paren))
return (Right.is(TT_CastRParen) ||
(Left.MatchingParen && Left.MatchingParen->is(TT_CastRParen)))
@@ -2567,7 +2667,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
return Left.Tok.isLiteral() || (Left.is(tok::identifier) && Left.Previous &&
Left.Previous->is(tok::kw_case));
if (Left.is(tok::l_square) && Right.is(tok::amp))
- return false;
+ return Style.SpacesInSquareBrackets;
if (Right.is(TT_PointerOrReference)) {
if (Left.is(tok::r_paren) && Line.MightBeFunctionDecl) {
if (!Left.MatchingParen)
@@ -2605,6 +2705,13 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
tok::l_square));
if (Right.is(tok::star) && Left.is(tok::l_paren))
return false;
+ if (Right.isOneOf(tok::star, tok::amp, tok::ampamp) &&
+ (Left.is(tok::identifier) || Left.isSimpleTypeSpecifier()) &&
+ Left.Previous && Left.Previous->is(tok::kw_operator))
+ // Space between the type and the *
+ // operator void*(), operator char*(), operator Foo*() dependant
+ // on PointerAlignment style.
+ return (Style.PointerAlignment != FormatStyle::PAS_Left);
const auto SpaceRequiredForArrayInitializerLSquare =
[](const FormatToken &LSquareTok, const FormatStyle &Style) {
return Style.SpacesInContainerLiterals ||
@@ -2634,7 +2741,9 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
!Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare,
TT_DesignatedInitializerLSquare,
TT_StructuredBindingLSquare, TT_AttributeSquare) &&
- !Left.isOneOf(tok::numeric_constant, TT_DictLiteral))
+ !Left.isOneOf(tok::numeric_constant, TT_DictLiteral) &&
+ !(!Left.is(tok::r_square) && Style.SpaceBeforeSquareBrackets &&
+ Right.is(TT_ArraySubscriptLSquare)))
return false;
if (Left.is(tok::l_brace) && Right.is(tok::r_brace))
return !Left.Children.empty(); // No spaces in "{}".
@@ -2906,14 +3015,18 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
return true;
}
if (Left.is(TT_UnaryOperator)) {
- // The alternative operators for ~ and ! are "compl" and "not".
- // If they are used instead, we do not want to combine them with
- // the token to the right, unless that is a left paren.
if (!Right.is(tok::l_paren)) {
+ // The alternative operators for ~ and ! are "compl" and "not".
+ // If they are used instead, we do not want to combine them with
+ // the token to the right, unless that is a left paren.
if (Left.is(tok::exclaim) && Left.TokenText == "not")
return true;
if (Left.is(tok::tilde) && Left.TokenText == "compl")
return true;
+ // Lambda captures allow for a lone &, so "&]" needs to be properly
+ // handled.
+ if (Left.is(tok::amp) && Right.is(tok::r_square))
+ return Style.SpacesInSquareBrackets;
}
return (Style.SpaceAfterLogicalNot && Left.is(tok::exclaim)) ||
Right.is(TT_BinaryOperator);
@@ -2947,7 +3060,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
// The identifier might actually be a macro name such as ALWAYS_INLINE. If
// this turns out to be too lenient, add analysis of the identifier itself.
return Right.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd();
- if (Right.is(tok::coloncolon) && !Left.isOneOf(tok::l_brace, tok::comment))
+ if (Right.is(tok::coloncolon) &&
+ !Left.isOneOf(tok::l_brace, tok::comment, tok::l_paren))
return (Left.is(TT_TemplateOpener) &&
Style.Standard < FormatStyle::LS_Cpp11) ||
!(Left.isOneOf(tok::l_paren, tok::r_paren, tok::l_square,
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 8b8d357d9cbe..fec85f1174da 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -326,6 +326,19 @@ private:
FormatStyle::BWACS_Always)
? tryMergeSimpleBlock(I, E, Limit)
: 0;
+ } else if (I[1]->First->is(tok::l_brace) &&
+ TheLine->First->isOneOf(tok::kw_else, tok::kw_catch) &&
+ Style.BraceWrapping.AfterControlStatement ==
+ FormatStyle::BWACS_MultiLine) {
+ // This case if different from the upper BWACS_MultiLine processing
+ // in that a preceding r_brace is not on the same line as else/catch
+ // most likely because of BeforeElse/BeforeCatch set to true.
+ // If the line length doesn't fit ColumnLimit, leave l_brace on the
+ // next line to respect the BWACS_MultiLine.
+ return (Style.ColumnLimit == 0 ||
+ TheLine->Last->TotalLength <= Style.ColumnLimit)
+ ? 1
+ : 0;
}
// Try to merge either empty or one-line block if is precedeed by control
// statement token
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index bbe05602f6da..ead6b4743207 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -466,7 +466,7 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
(NextTok->is(tok::semi) &&
(!ExpectClassBody || LBraceStack.size() != 1)) ||
(NextTok->isBinaryOperator() && !NextIsObjCMethod);
- if (NextTok->is(tok::l_square)) {
+ if (!Style.isCSharp() && NextTok->is(tok::l_square)) {
// We can have an array subscript after a braced init
// list, but C++11 attributes are expected after blocks.
NextTok = Tokens->getNextToken();
@@ -2498,9 +2498,10 @@ bool UnwrappedLineParser::isOnNewLine(const FormatToken &FormatTok) {
// Checks if \p FormatTok is a line comment that continues the line comment
// section on \p Line.
-static bool continuesLineCommentSection(const FormatToken &FormatTok,
- const UnwrappedLine &Line,
- llvm::Regex &CommentPragmasRegex) {
+static bool
+continuesLineCommentSection(const FormatToken &FormatTok,
+ const UnwrappedLine &Line,
+ const llvm::Regex &CommentPragmasRegex) {
if (Line.Tokens.empty())
return false;
diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp
index f5e291b7fe17..b3264952ff47 100644
--- a/clang/lib/Frontend/ASTUnit.cpp
+++ b/clang/lib/Frontend/ASTUnit.cpp
@@ -61,7 +61,7 @@
#include "clang/Serialization/ASTWriter.h"
#include "clang/Serialization/ContinuousRangeMap.h"
#include "clang/Serialization/InMemoryModuleCache.h"
-#include "clang/Serialization/Module.h"
+#include "clang/Serialization/ModuleFile.h"
#include "clang/Serialization/PCHContainerOperations.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
@@ -1457,7 +1457,7 @@ void ASTUnit::transferASTDataFromCompilerInstance(CompilerInstance &CI) {
CI.setFileManager(nullptr);
if (CI.hasTarget())
Target = &CI.getTarget();
- Reader = CI.getModuleManager();
+ Reader = CI.getASTReader();
HadModuleLoaderFatalFailure = CI.hadModuleLoaderFatalFailure();
}
diff --git a/clang/lib/Frontend/ChainedIncludesSource.cpp b/clang/lib/Frontend/ChainedIncludesSource.cpp
index 29fee7246d14..dec281529b9e 100644
--- a/clang/lib/Frontend/ChainedIncludesSource.cpp
+++ b/clang/lib/Frontend/ChainedIncludesSource.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/Builtins.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index c409c07ff133..688f21dd0908 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -75,7 +75,7 @@ void CompilerInstance::setInvocation(
bool CompilerInstance::shouldBuildGlobalModuleIndex() const {
return (BuildGlobalModuleIndex ||
- (ModuleManager && ModuleManager->isGlobalIndexUnavailable() &&
+ (TheASTReader && TheASTReader->isGlobalIndexUnavailable() &&
getFrontendOpts().GenerateGlobalModuleIndex)) &&
!ModuleBuildFailed;
}
@@ -135,13 +135,13 @@ std::unique_ptr<Sema> CompilerInstance::takeSema() {
return std::move(TheSema);
}
-IntrusiveRefCntPtr<ASTReader> CompilerInstance::getModuleManager() const {
- return ModuleManager;
+IntrusiveRefCntPtr<ASTReader> CompilerInstance::getASTReader() const {
+ return TheASTReader;
}
void CompilerInstance::setModuleManager(IntrusiveRefCntPtr<ASTReader> Reader) {
assert(ModuleCache.get() == &Reader->getModuleManager().getModuleCache() &&
"Expected ASTReader to use the same PCM cache");
- ModuleManager = std::move(Reader);
+ TheASTReader = std::move(Reader);
}
std::shared_ptr<ModuleDependencyCollector>
@@ -380,7 +380,7 @@ void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) {
const PreprocessorOptions &PPOpts = getPreprocessorOpts();
// The module manager holds a reference to the old preprocessor (if any).
- ModuleManager.reset();
+ TheASTReader.reset();
// Create the Preprocessor.
HeaderSearch *HeaderInfo =
@@ -494,7 +494,7 @@ void CompilerInstance::createPCHExternalASTSource(
StringRef Path, bool DisablePCHValidation, bool AllowPCHWithCompilerErrors,
void *DeserializationListener, bool OwnDeserializationListener) {
bool Preamble = getPreprocessorOpts().PrecompiledPreambleBytes.first != 0;
- ModuleManager = createPCHExternalASTSource(
+ TheASTReader = createPCHExternalASTSource(
Path, getHeaderSearchOpts().Sysroot, DisablePCHValidation,
AllowPCHWithCompilerErrors, getPreprocessor(), getModuleCache(),
getASTContext(), getPCHContainerReader(),
@@ -672,7 +672,7 @@ CompilerInstance::createDefaultOutputFile(bool Binary, StringRef InFile,
StringRef Extension) {
return createOutputFile(getFrontendOpts().OutputFile, Binary,
/*RemoveFileOnSignal=*/true, InFile, Extension,
- /*UseTemporary=*/true);
+ getFrontendOpts().UseTemporary);
}
std::unique_ptr<raw_pwrite_stream> CompilerInstance::createNullOutputFile() {
@@ -917,8 +917,9 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
if (!hasTarget())
return false;
- // Create TargetInfo for the other side of CUDA and OpenMP compilation.
- if ((getLangOpts().CUDA || getLangOpts().OpenMPIsDevice) &&
+ // Create TargetInfo for the other side of CUDA/OpenMP/SYCL compilation.
+ if ((getLangOpts().CUDA || getLangOpts().OpenMPIsDevice ||
+ getLangOpts().SYCLIsDevice) &&
!getFrontendOpts().AuxTriple.empty()) {
auto TO = std::make_shared<TargetOptions>();
TO->Triple = llvm::Triple::normalize(getFrontendOpts().AuxTriple);
@@ -1179,13 +1180,12 @@ static const FileEntry *getPublicModuleMap(const FileEntry *File,
return nullptr;
}
-/// Compile a module file for the given module, using the options
-/// provided by the importing compiler instance. Returns true if the module
-/// was built without errors.
-static bool compileModuleImpl(CompilerInstance &ImportingInstance,
- SourceLocation ImportLoc,
- Module *Module,
- StringRef ModuleFileName) {
+/// Compile a module file for the given module in a separate compiler instance,
+/// using the options provided by the importing compiler instance. Returns true
+/// if the module was built without errors.
+static bool compileModule(CompilerInstance &ImportingInstance,
+ SourceLocation ImportLoc, Module *Module,
+ StringRef ModuleFileName) {
InputKind IK(getLanguageFromOptions(ImportingInstance.getLangOpts()),
InputKind::ModuleMap);
@@ -1245,10 +1245,17 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance,
return Result;
}
-static bool compileAndLoadModule(CompilerInstance &ImportingInstance,
- SourceLocation ImportLoc,
- SourceLocation ModuleNameLoc, Module *Module,
- StringRef ModuleFileName) {
+/// Compile a module in a separate compiler instance and read the AST,
+/// returning true if the module compiles without errors.
+///
+/// Uses a lock file manager and exponential backoff to reduce the chances that
+/// multiple instances will compete to create the same module. On timeout,
+/// deletes the lock file in order to avoid deadlock from crashing processes or
+/// bugs in the lock file manager.
+static bool compileModuleAndReadAST(CompilerInstance &ImportingInstance,
+ SourceLocation ImportLoc,
+ SourceLocation ModuleNameLoc,
+ Module *Module, StringRef ModuleFileName) {
DiagnosticsEngine &Diags = ImportingInstance.getDiagnostics();
auto diagnoseBuildFailure = [&] {
@@ -1276,8 +1283,8 @@ static bool compileAndLoadModule(CompilerInstance &ImportingInstance,
LLVM_FALLTHROUGH;
case llvm::LockFileManager::LFS_Owned:
// We're responsible for building the module ourselves.
- if (!compileModuleImpl(ImportingInstance, ModuleNameLoc, Module,
- ModuleFileName)) {
+ if (!compileModule(ImportingInstance, ModuleNameLoc, Module,
+ ModuleFileName)) {
diagnoseBuildFailure();
return false;
}
@@ -1307,7 +1314,7 @@ static bool compileAndLoadModule(CompilerInstance &ImportingInstance,
// Try to read the module file, now that we've compiled it.
ASTReader::ASTReadResult ReadResult =
- ImportingInstance.getModuleManager()->ReadAST(
+ ImportingInstance.getASTReader()->ReadAST(
ModuleFileName, serialization::MK_ImplicitModule, ImportLoc,
ModuleLoadCapabilities);
@@ -1471,52 +1478,52 @@ static void pruneModuleCache(const HeaderSearchOptions &HSOpts) {
}
}
-void CompilerInstance::createModuleManager() {
- if (!ModuleManager) {
- if (!hasASTContext())
- createASTContext();
+void CompilerInstance::createASTReader() {
+ if (TheASTReader)
+ return;
- // If we're implicitly building modules but not currently recursively
- // building a module, check whether we need to prune the module cache.
- if (getSourceManager().getModuleBuildStack().empty() &&
- !getPreprocessor().getHeaderSearchInfo().getModuleCachePath().empty() &&
- getHeaderSearchOpts().ModuleCachePruneInterval > 0 &&
- getHeaderSearchOpts().ModuleCachePruneAfter > 0) {
- pruneModuleCache(getHeaderSearchOpts());
- }
+ if (!hasASTContext())
+ createASTContext();
- HeaderSearchOptions &HSOpts = getHeaderSearchOpts();
- std::string Sysroot = HSOpts.Sysroot;
- const PreprocessorOptions &PPOpts = getPreprocessorOpts();
- std::unique_ptr<llvm::Timer> ReadTimer;
- if (FrontendTimerGroup)
- ReadTimer = std::make_unique<llvm::Timer>("reading_modules",
- "Reading modules",
- *FrontendTimerGroup);
- ModuleManager = new ASTReader(
- getPreprocessor(), getModuleCache(), &getASTContext(),
- getPCHContainerReader(), getFrontendOpts().ModuleFileExtensions,
- Sysroot.empty() ? "" : Sysroot.c_str(), PPOpts.DisablePCHValidation,
- /*AllowASTWithCompilerErrors=*/false,
- /*AllowConfigurationMismatch=*/false,
- HSOpts.ModulesValidateSystemHeaders,
- HSOpts.ValidateASTInputFilesContent,
- getFrontendOpts().UseGlobalModuleIndex, std::move(ReadTimer));
- if (hasASTConsumer()) {
- ModuleManager->setDeserializationListener(
- getASTConsumer().GetASTDeserializationListener());
- getASTContext().setASTMutationListener(
- getASTConsumer().GetASTMutationListener());
- }
- getASTContext().setExternalSource(ModuleManager);
- if (hasSema())
- ModuleManager->InitializeSema(getSema());
- if (hasASTConsumer())
- ModuleManager->StartTranslationUnit(&getASTConsumer());
+ // If we're implicitly building modules but not currently recursively
+ // building a module, check whether we need to prune the module cache.
+ if (getSourceManager().getModuleBuildStack().empty() &&
+ !getPreprocessor().getHeaderSearchInfo().getModuleCachePath().empty() &&
+ getHeaderSearchOpts().ModuleCachePruneInterval > 0 &&
+ getHeaderSearchOpts().ModuleCachePruneAfter > 0) {
+ pruneModuleCache(getHeaderSearchOpts());
+ }
- for (auto &Listener : DependencyCollectors)
- Listener->attachToASTReader(*ModuleManager);
+ HeaderSearchOptions &HSOpts = getHeaderSearchOpts();
+ std::string Sysroot = HSOpts.Sysroot;
+ const PreprocessorOptions &PPOpts = getPreprocessorOpts();
+ std::unique_ptr<llvm::Timer> ReadTimer;
+ if (FrontendTimerGroup)
+ ReadTimer = std::make_unique<llvm::Timer>("reading_modules",
+ "Reading modules",
+ *FrontendTimerGroup);
+ TheASTReader = new ASTReader(
+ getPreprocessor(), getModuleCache(), &getASTContext(),
+ getPCHContainerReader(), getFrontendOpts().ModuleFileExtensions,
+ Sysroot.empty() ? "" : Sysroot.c_str(), PPOpts.DisablePCHValidation,
+ /*AllowASTWithCompilerErrors=*/false,
+ /*AllowConfigurationMismatch=*/false, HSOpts.ModulesValidateSystemHeaders,
+ HSOpts.ValidateASTInputFilesContent,
+ getFrontendOpts().UseGlobalModuleIndex, std::move(ReadTimer));
+ if (hasASTConsumer()) {
+ TheASTReader->setDeserializationListener(
+ getASTConsumer().GetASTDeserializationListener());
+ getASTContext().setASTMutationListener(
+ getASTConsumer().GetASTMutationListener());
}
+ getASTContext().setExternalSource(TheASTReader);
+ if (hasSema())
+ TheASTReader->InitializeSema(getSema());
+ if (hasASTConsumer())
+ TheASTReader->StartTranslationUnit(&getASTConsumer());
+
+ for (auto &Listener : DependencyCollectors)
+ Listener->attachToASTReader(*TheASTReader);
}
bool CompilerInstance::loadModuleFile(StringRef FileName) {
@@ -1541,12 +1548,9 @@ bool CompilerInstance::loadModuleFile(StringRef FileName) {
}
void registerAll() {
- for (auto *II : LoadedModules) {
- CI.KnownModules[II] = CI.getPreprocessor()
- .getHeaderSearchInfo()
- .getModuleMap()
- .findModule(II->getName());
- }
+ ModuleMap &MM = CI.getPreprocessor().getHeaderSearchInfo().getModuleMap();
+ for (auto *II : LoadedModules)
+ MM.cacheModuleLoad(*II, MM.findModule(II->getName()));
LoadedModules.clear();
}
@@ -1576,8 +1580,8 @@ bool CompilerInstance::loadModuleFile(StringRef FileName) {
};
// If we don't already have an ASTReader, create one now.
- if (!ModuleManager)
- createModuleManager();
+ if (!TheASTReader)
+ createASTReader();
// If -Wmodule-file-config-mismatch is mapped as an error or worse, allow the
// ASTReader to diagnose it, since it can produce better errors that we can.
@@ -1588,11 +1592,11 @@ bool CompilerInstance::loadModuleFile(StringRef FileName) {
auto Listener = std::make_unique<ReadModuleNames>(*this);
auto &ListenerRef = *Listener;
- ASTReader::ListenerScope ReadModuleNamesListener(*ModuleManager,
+ ASTReader::ListenerScope ReadModuleNamesListener(*TheASTReader,
std::move(Listener));
// Try to load the module file.
- switch (ModuleManager->ReadAST(
+ switch (TheASTReader->ReadAST(
FileName, serialization::MK_ExplicitModule, SourceLocation(),
ConfigMismatchIsRecoverable ? ASTReader::ARR_ConfigurationMismatch : 0)) {
case ASTReader::Success:
@@ -1615,6 +1619,220 @@ bool CompilerInstance::loadModuleFile(StringRef FileName) {
}
}
+namespace {
+enum ModuleSource {
+ MS_ModuleNotFound,
+ MS_ModuleCache,
+ MS_PrebuiltModulePath,
+ MS_ModuleBuildPragma
+};
+} // end namespace
+
+/// Select a source for loading the named module and compute the filename to
+/// load it from.
+static ModuleSource
+selectModuleSource(Module *M, StringRef ModuleName, std::string &ModuleFilename,
+ const std::map<std::string, std::string> &BuiltModules,
+ HeaderSearch &HS) {
+ assert(ModuleFilename.empty() && "Already has a module source?");
+
+ // Check to see if the module has been built as part of this compilation
+ // via a module build pragma.
+ auto BuiltModuleIt = BuiltModules.find(ModuleName);
+ if (BuiltModuleIt != BuiltModules.end()) {
+ ModuleFilename = BuiltModuleIt->second;
+ return MS_ModuleBuildPragma;
+ }
+
+ // Try to load the module from the prebuilt module path.
+ const HeaderSearchOptions &HSOpts = HS.getHeaderSearchOpts();
+ if (!HSOpts.PrebuiltModuleFiles.empty() ||
+ !HSOpts.PrebuiltModulePaths.empty()) {
+ ModuleFilename = HS.getPrebuiltModuleFileName(ModuleName);
+ if (!ModuleFilename.empty())
+ return MS_PrebuiltModulePath;
+ }
+
+ // Try to load the module from the module cache.
+ if (M) {
+ ModuleFilename = HS.getCachedModuleFileName(M);
+ return MS_ModuleCache;
+ }
+
+ return MS_ModuleNotFound;
+}
+
+ModuleLoadResult CompilerInstance::findOrCompileModuleAndReadAST(
+ StringRef ModuleName, SourceLocation ImportLoc,
+ SourceLocation ModuleNameLoc, bool IsInclusionDirective) {
+ // Search for a module with the given name.
+ HeaderSearch &HS = PP->getHeaderSearchInfo();
+ Module *M = HS.lookupModule(ModuleName, true, !IsInclusionDirective);
+
+ // Select the source and filename for loading the named module.
+ std::string ModuleFilename;
+ ModuleSource Source =
+ selectModuleSource(M, ModuleName, ModuleFilename, BuiltModules, HS);
+ if (Source == MS_ModuleNotFound) {
+ // We can't find a module, error out here.
+ getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found)
+ << ModuleName << SourceRange(ImportLoc, ModuleNameLoc);
+ ModuleBuildFailed = true;
+ // FIXME: Why is this not cached?
+ return ModuleLoadResult::OtherUncachedFailure;
+ }
+ if (ModuleFilename.empty()) {
+ if (M && M->HasIncompatibleModuleFile) {
+ // We tried and failed to load a module file for this module. Fall
+ // back to textual inclusion for its headers.
+ return ModuleLoadResult::ConfigMismatch;
+ }
+
+ getDiagnostics().Report(ModuleNameLoc, diag::err_module_build_disabled)
+ << ModuleName;
+ ModuleBuildFailed = true;
+ // FIXME: Why is this not cached?
+ return ModuleLoadResult::OtherUncachedFailure;
+ }
+
+ // Create an ASTReader on demand.
+ if (!getASTReader())
+ createASTReader();
+
+ // Time how long it takes to load the module.
+ llvm::Timer Timer;
+ if (FrontendTimerGroup)
+ Timer.init("loading." + ModuleFilename, "Loading " + ModuleFilename,
+ *FrontendTimerGroup);
+ llvm::TimeRegion TimeLoading(FrontendTimerGroup ? &Timer : nullptr);
+ llvm::TimeTraceScope TimeScope("Module Load", ModuleName);
+
+ // Try to load the module file. If we are not trying to load from the
+ // module cache, we don't know how to rebuild modules.
+ unsigned ARRFlags = Source == MS_ModuleCache
+ ? ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing
+ : Source == MS_PrebuiltModulePath
+ ? 0
+ : ASTReader::ARR_ConfigurationMismatch;
+ switch (getASTReader()->ReadAST(ModuleFilename,
+ Source == MS_PrebuiltModulePath
+ ? serialization::MK_PrebuiltModule
+ : Source == MS_ModuleBuildPragma
+ ? serialization::MK_ExplicitModule
+ : serialization::MK_ImplicitModule,
+ ImportLoc, ARRFlags)) {
+ case ASTReader::Success: {
+ if (M)
+ return M;
+ assert(Source != MS_ModuleCache &&
+ "missing module, but file loaded from cache");
+
+ // A prebuilt module is indexed as a ModuleFile; the Module does not exist
+ // until the first call to ReadAST. Look it up now.
+ M = HS.lookupModule(ModuleName, true, !IsInclusionDirective);
+
+ // Check whether M refers to the file in the prebuilt module path.
+ if (M && M->getASTFile())
+ if (auto ModuleFile = FileMgr->getFile(ModuleFilename))
+ if (*ModuleFile == M->getASTFile())
+ return M;
+
+ ModuleBuildFailed = true;
+ getDiagnostics().Report(ModuleNameLoc, diag::err_module_prebuilt)
+ << ModuleName;
+ return ModuleLoadResult();
+ }
+
+ case ASTReader::OutOfDate:
+ case ASTReader::Missing:
+ // The most interesting case.
+ break;
+
+ case ASTReader::ConfigurationMismatch:
+ if (Source == MS_PrebuiltModulePath)
+ // FIXME: We shouldn't be setting HadFatalFailure below if we only
+ // produce a warning here!
+ getDiagnostics().Report(SourceLocation(),
+ diag::warn_module_config_mismatch)
+ << ModuleFilename;
+ // Fall through to error out.
+ LLVM_FALLTHROUGH;
+ case ASTReader::VersionMismatch:
+ case ASTReader::HadErrors:
+ // FIXME: Should this set ModuleBuildFailed = true?
+ ModuleLoader::HadFatalFailure = true;
+ // FIXME: The ASTReader will already have complained, but can we shoehorn
+ // that diagnostic information into a more useful form?
+ return ModuleLoadResult();
+
+ case ASTReader::Failure:
+ // FIXME: Should this set ModuleBuildFailed = true?
+ ModuleLoader::HadFatalFailure = true;
+ return ModuleLoadResult();
+ }
+
+ // ReadAST returned Missing or OutOfDate.
+ if (Source != MS_ModuleCache) {
+ // We don't know the desired configuration for this module and don't
+ // necessarily even have a module map. Since ReadAST already produces
+ // diagnostics for these two cases, we simply error out here.
+ ModuleBuildFailed = true;
+ return ModuleLoadResult();
+ }
+
+ // The module file is missing or out-of-date. Build it.
+ assert(M && "missing module, but trying to compile for cache");
+
+ // Check whether there is a cycle in the module graph.
+ ModuleBuildStack ModPath = getSourceManager().getModuleBuildStack();
+ ModuleBuildStack::iterator Pos = ModPath.begin(), PosEnd = ModPath.end();
+ for (; Pos != PosEnd; ++Pos) {
+ if (Pos->first == ModuleName)
+ break;
+ }
+
+ if (Pos != PosEnd) {
+ SmallString<256> CyclePath;
+ for (; Pos != PosEnd; ++Pos) {
+ CyclePath += Pos->first;
+ CyclePath += " -> ";
+ }
+ CyclePath += ModuleName;
+
+ getDiagnostics().Report(ModuleNameLoc, diag::err_module_cycle)
+ << ModuleName << CyclePath;
+ // FIXME: Should this set ModuleBuildFailed = true?
+ // FIXME: Why is this not cached?
+ return ModuleLoadResult::OtherUncachedFailure;
+ }
+
+ // Check whether we have already attempted to build this module (but
+ // failed).
+ if (getPreprocessorOpts().FailedModules &&
+ getPreprocessorOpts().FailedModules->hasAlreadyFailed(ModuleName)) {
+ getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_built)
+ << ModuleName << SourceRange(ImportLoc, ModuleNameLoc);
+ ModuleBuildFailed = true;
+ // FIXME: Why is this not cached?
+ return ModuleLoadResult::OtherUncachedFailure;
+ }
+
+ // Try to compile and then read the AST.
+ if (!compileModuleAndReadAST(*this, ImportLoc, ModuleNameLoc, M,
+ ModuleFilename)) {
+ assert(getDiagnostics().hasErrorOccurred() &&
+ "undiagnosed error in compileModuleAndReadAST");
+ if (getPreprocessorOpts().FailedModules)
+ getPreprocessorOpts().FailedModules->addFailed(ModuleName);
+ ModuleBuildFailed = true;
+ // FIXME: Why is this not cached?
+ return ModuleLoadResult::OtherUncachedFailure;
+ }
+
+ // Okay, we've rebuilt and now loaded the module.
+ return M;
+}
+
ModuleLoadResult
CompilerInstance::loadModule(SourceLocation ImportLoc,
ModuleIdPath Path,
@@ -1630,19 +1848,17 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
if (ImportLoc.isValid() && LastModuleImportLoc == ImportLoc) {
// Make the named module visible.
if (LastModuleImportResult && ModuleName != getLangOpts().CurrentModule)
- ModuleManager->makeModuleVisible(LastModuleImportResult, Visibility,
- ImportLoc);
+ TheASTReader->makeModuleVisible(LastModuleImportResult, Visibility,
+ ImportLoc);
return LastModuleImportResult;
}
- clang::Module *Module = nullptr;
-
// If we don't already have information on this module, load the module now.
- llvm::DenseMap<const IdentifierInfo *, clang::Module *>::iterator Known
- = KnownModules.find(Path[0].first);
- if (Known != KnownModules.end()) {
- // Retrieve the cached top-level module.
- Module = Known->second;
+ Module *Module = nullptr;
+ ModuleMap &MM = getPreprocessor().getHeaderSearchInfo().getModuleMap();
+ if (auto MaybeModule = MM.getCachedModuleLoad(*Path[0].first)) {
+ // Use the cached result, which may be nullptr.
+ Module = *MaybeModule;
} else if (ModuleName == getLangOpts().CurrentModule) {
// This is the module we're building.
Module = PP->getHeaderSearchInfo().lookupModule(
@@ -1656,198 +1872,23 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
// ModuleBuildFailed = true;
// return ModuleLoadResult();
//}
- Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first;
+ MM.cacheModuleLoad(*Path[0].first, Module);
} else {
- // Search for a module with the given name.
- Module = PP->getHeaderSearchInfo().lookupModule(ModuleName, true,
- !IsInclusionDirective);
- HeaderSearchOptions &HSOpts =
- PP->getHeaderSearchInfo().getHeaderSearchOpts();
-
- std::string ModuleFileName;
- enum ModuleSource {
- ModuleNotFound, ModuleCache, PrebuiltModulePath, ModuleBuildPragma
- } Source = ModuleNotFound;
-
- // Check to see if the module has been built as part of this compilation
- // via a module build pragma.
- auto BuiltModuleIt = BuiltModules.find(ModuleName);
- if (BuiltModuleIt != BuiltModules.end()) {
- ModuleFileName = BuiltModuleIt->second;
- Source = ModuleBuildPragma;
- }
-
- // Try to load the module from the prebuilt module path.
- if (Source == ModuleNotFound && (!HSOpts.PrebuiltModuleFiles.empty() ||
- !HSOpts.PrebuiltModulePaths.empty())) {
- ModuleFileName =
- PP->getHeaderSearchInfo().getPrebuiltModuleFileName(ModuleName);
- if (!ModuleFileName.empty())
- Source = PrebuiltModulePath;
- }
-
- // Try to load the module from the module cache.
- if (Source == ModuleNotFound && Module) {
- ModuleFileName = PP->getHeaderSearchInfo().getCachedModuleFileName(Module);
- Source = ModuleCache;
- }
-
- if (Source == ModuleNotFound) {
- // We can't find a module, error out here.
- getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found)
- << ModuleName << SourceRange(ImportLoc, ModuleNameLoc);
- ModuleBuildFailed = true;
- return ModuleLoadResult();
- }
-
- if (ModuleFileName.empty()) {
- if (Module && Module->HasIncompatibleModuleFile) {
- // We tried and failed to load a module file for this module. Fall
- // back to textual inclusion for its headers.
- return ModuleLoadResult::ConfigMismatch;
- }
-
- getDiagnostics().Report(ModuleNameLoc, diag::err_module_build_disabled)
- << ModuleName;
- ModuleBuildFailed = true;
- return ModuleLoadResult();
- }
-
- // If we don't already have an ASTReader, create one now.
- if (!ModuleManager)
- createModuleManager();
-
- llvm::Timer Timer;
- if (FrontendTimerGroup)
- Timer.init("loading." + ModuleFileName, "Loading " + ModuleFileName,
- *FrontendTimerGroup);
- llvm::TimeRegion TimeLoading(FrontendTimerGroup ? &Timer : nullptr);
- llvm::TimeTraceScope TimeScope("Module Load", ModuleName);
-
- // Try to load the module file. If we are not trying to load from the
- // module cache, we don't know how to rebuild modules.
- unsigned ARRFlags = Source == ModuleCache ?
- ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing :
- Source == PrebuiltModulePath ?
- 0 :
- ASTReader::ARR_ConfigurationMismatch;
- switch (ModuleManager->ReadAST(ModuleFileName,
- Source == PrebuiltModulePath
- ? serialization::MK_PrebuiltModule
- : Source == ModuleBuildPragma
- ? serialization::MK_ExplicitModule
- : serialization::MK_ImplicitModule,
- ImportLoc, ARRFlags)) {
- case ASTReader::Success: {
- if (Source != ModuleCache && !Module) {
- Module = PP->getHeaderSearchInfo().lookupModule(ModuleName, true,
- !IsInclusionDirective);
- auto ModuleFile = FileMgr->getFile(ModuleFileName);
- if (!Module || !Module->getASTFile() ||
- !ModuleFile || (*ModuleFile != Module->getASTFile())) {
- // Error out if Module does not refer to the file in the prebuilt
- // module path.
- getDiagnostics().Report(ModuleNameLoc, diag::err_module_prebuilt)
- << ModuleName;
- ModuleBuildFailed = true;
- KnownModules[Path[0].first] = nullptr;
- return ModuleLoadResult();
- }
- }
- break;
- }
-
- case ASTReader::OutOfDate:
- case ASTReader::Missing: {
- if (Source != ModuleCache) {
- // We don't know the desired configuration for this module and don't
- // necessarily even have a module map. Since ReadAST already produces
- // diagnostics for these two cases, we simply error out here.
- ModuleBuildFailed = true;
- KnownModules[Path[0].first] = nullptr;
- return ModuleLoadResult();
- }
-
- // The module file is missing or out-of-date. Build it.
- assert(Module && "missing module file");
- // Check whether there is a cycle in the module graph.
- ModuleBuildStack ModPath = getSourceManager().getModuleBuildStack();
- ModuleBuildStack::iterator Pos = ModPath.begin(), PosEnd = ModPath.end();
- for (; Pos != PosEnd; ++Pos) {
- if (Pos->first == ModuleName)
- break;
- }
-
- if (Pos != PosEnd) {
- SmallString<256> CyclePath;
- for (; Pos != PosEnd; ++Pos) {
- CyclePath += Pos->first;
- CyclePath += " -> ";
- }
- CyclePath += ModuleName;
-
- getDiagnostics().Report(ModuleNameLoc, diag::err_module_cycle)
- << ModuleName << CyclePath;
- return ModuleLoadResult();
- }
-
- // Check whether we have already attempted to build this module (but
- // failed).
- if (getPreprocessorOpts().FailedModules &&
- getPreprocessorOpts().FailedModules->hasAlreadyFailed(ModuleName)) {
- getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_built)
- << ModuleName
- << SourceRange(ImportLoc, ModuleNameLoc);
- ModuleBuildFailed = true;
- return ModuleLoadResult();
- }
-
- // Try to compile and then load the module.
- if (!compileAndLoadModule(*this, ImportLoc, ModuleNameLoc, Module,
- ModuleFileName)) {
- assert(getDiagnostics().hasErrorOccurred() &&
- "undiagnosed error in compileAndLoadModule");
- if (getPreprocessorOpts().FailedModules)
- getPreprocessorOpts().FailedModules->addFailed(ModuleName);
- KnownModules[Path[0].first] = nullptr;
- ModuleBuildFailed = true;
- return ModuleLoadResult();
- }
-
- // Okay, we've rebuilt and now loaded the module.
- break;
- }
-
- case ASTReader::ConfigurationMismatch:
- if (Source == PrebuiltModulePath)
- // FIXME: We shouldn't be setting HadFatalFailure below if we only
- // produce a warning here!
- getDiagnostics().Report(SourceLocation(),
- diag::warn_module_config_mismatch)
- << ModuleFileName;
- // Fall through to error out.
- LLVM_FALLTHROUGH;
- case ASTReader::VersionMismatch:
- case ASTReader::HadErrors:
- ModuleLoader::HadFatalFailure = true;
- // FIXME: The ASTReader will already have complained, but can we shoehorn
- // that diagnostic information into a more useful form?
- KnownModules[Path[0].first] = nullptr;
- return ModuleLoadResult();
-
- case ASTReader::Failure:
- ModuleLoader::HadFatalFailure = true;
- // Already complained, but note now that we failed.
- KnownModules[Path[0].first] = nullptr;
- ModuleBuildFailed = true;
- return ModuleLoadResult();
- }
-
- // Cache the result of this top-level module lookup for later.
- Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first;
+ ModuleLoadResult Result = findOrCompileModuleAndReadAST(
+ ModuleName, ImportLoc, ModuleNameLoc, IsInclusionDirective);
+ // FIXME: Can we pull 'ModuleBuildFailed = true' out of the return
+ // sequences for findOrCompileModuleAndReadAST and do it here (as long as
+ // the result is not a config mismatch)? See FIXMEs there.
+ if (!Result.isNormal())
+ return Result;
+ Module = Result;
+ MM.cacheModuleLoad(*Path[0].first, Module);
+ if (!Module)
+ return Module;
}
- // If we never found the module, fail.
+ // If we never found the module, fail. Otherwise, verify the module and link
+ // it up.
if (!Module)
return ModuleLoadResult();
@@ -1967,7 +2008,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
return ModuleLoadResult();
}
- ModuleManager->makeModuleVisible(Module, Visibility, ImportLoc);
+ TheASTReader->makeModuleVisible(Module, Visibility, ImportLoc);
}
// Check for any configuration macros that have changed.
@@ -1988,9 +2029,9 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
return LastModuleImportResult;
}
-void CompilerInstance::loadModuleFromSource(SourceLocation ImportLoc,
- StringRef ModuleName,
- StringRef Source) {
+void CompilerInstance::createModuleFromSource(SourceLocation ImportLoc,
+ StringRef ModuleName,
+ StringRef Source) {
// Avoid creating filenames with special characters.
SmallString<128> CleanModuleName(ModuleName);
for (auto &C : CleanModuleName)
@@ -2044,27 +2085,27 @@ void CompilerInstance::loadModuleFromSource(SourceLocation ImportLoc,
void CompilerInstance::makeModuleVisible(Module *Mod,
Module::NameVisibilityKind Visibility,
SourceLocation ImportLoc) {
- if (!ModuleManager)
- createModuleManager();
- if (!ModuleManager)
+ if (!TheASTReader)
+ createASTReader();
+ if (!TheASTReader)
return;
- ModuleManager->makeModuleVisible(Mod, Visibility, ImportLoc);
+ TheASTReader->makeModuleVisible(Mod, Visibility, ImportLoc);
}
GlobalModuleIndex *CompilerInstance::loadGlobalModuleIndex(
SourceLocation TriggerLoc) {
if (getPreprocessor().getHeaderSearchInfo().getModuleCachePath().empty())
return nullptr;
- if (!ModuleManager)
- createModuleManager();
+ if (!TheASTReader)
+ createASTReader();
// Can't do anything if we don't have the module manager.
- if (!ModuleManager)
+ if (!TheASTReader)
return nullptr;
// Get an existing global index. This loads it if not already
// loaded.
- ModuleManager->loadGlobalIndex();
- GlobalModuleIndex *GlobalIndex = ModuleManager->getGlobalIndex();
+ TheASTReader->loadGlobalIndex();
+ GlobalModuleIndex *GlobalIndex = TheASTReader->getGlobalIndex();
// If the global index doesn't exist, create it.
if (!GlobalIndex && shouldBuildGlobalModuleIndex() && hasFileManager() &&
hasPreprocessor()) {
@@ -2080,9 +2121,9 @@ GlobalModuleIndex *CompilerInstance::loadGlobalModuleIndex(
consumeError(std::move(Err));
return nullptr;
}
- ModuleManager->resetForReload();
- ModuleManager->loadGlobalIndex();
- GlobalIndex = ModuleManager->getGlobalIndex();
+ TheASTReader->resetForReload();
+ TheASTReader->loadGlobalIndex();
+ GlobalIndex = TheASTReader->getGlobalIndex();
}
// For finding modules needing to be imported for fixit messages,
// we need to make the global index cover all modules, so we do that here.
@@ -2111,9 +2152,9 @@ GlobalModuleIndex *CompilerInstance::loadGlobalModuleIndex(
consumeError(std::move(Err));
return nullptr;
}
- ModuleManager->resetForReload();
- ModuleManager->loadGlobalIndex();
- GlobalIndex = ModuleManager->getGlobalIndex();
+ TheASTReader->resetForReload();
+ TheASTReader->loadGlobalIndex();
+ GlobalIndex = TheASTReader->getGlobalIndex();
}
HaveFullGlobalModuleIndex = true;
}
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 665695ec3b18..e1e59565083b 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -334,7 +334,7 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
StringRef CheckerAndPackageList = A->getValue();
SmallVector<StringRef, 16> CheckersAndPackages;
CheckerAndPackageList.split(CheckersAndPackages, ",");
- for (const StringRef CheckerOrPackage : CheckersAndPackages)
+ for (const StringRef &CheckerOrPackage : CheckersAndPackages)
Opts.CheckersAndPackages.emplace_back(CheckerOrPackage, IsEnabled);
}
@@ -476,7 +476,7 @@ static void parseAnalyzerConfigs(AnalyzerOptions &AnOpts,
SmallVector<StringRef, 16> CheckersAndPackages;
AnOpts.RawSilencedCheckersAndPackages.split(CheckersAndPackages, ";");
- for (const StringRef CheckerOrPackage : CheckersAndPackages) {
+ for (const StringRef &CheckerOrPackage : CheckersAndPackages) {
if (Diags) {
bool IsChecker = CheckerOrPackage.contains('.');
bool IsValidName =
@@ -607,7 +607,7 @@ static void parseXRayInstrumentationBundle(StringRef FlagName, StringRef Bundle,
XRayInstrSet &S) {
llvm::SmallVector<StringRef, 2> BundleParts;
llvm::SplitString(Bundle, BundleParts, ",");
- for (const auto B : BundleParts) {
+ for (const auto &B : BundleParts) {
auto Mask = parseXRayInstrValue(B);
if (Mask == XRayInstrKind::None)
if (B != "none")
@@ -731,6 +731,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
llvm::StringSwitch<unsigned>(A->getValue())
.Case("line-tables-only", codegenoptions::DebugLineTablesOnly)
.Case("line-directives-only", codegenoptions::DebugDirectivesOnly)
+ .Case("constructor", codegenoptions::DebugInfoConstructor)
.Case("limited", codegenoptions::LimitedDebugInfo)
.Case("standalone", codegenoptions::FullDebugInfo)
.Default(~0U);
@@ -769,6 +770,9 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.DebugFwdTemplateParams = Args.hasArg(OPT_debug_forward_template_params);
Opts.EmbedSource = Args.hasArg(OPT_gembed_source);
+ Opts.ForceDwarfFrameSection =
+ Args.hasFlag(OPT_fforce_dwarf_frame, OPT_fno_force_dwarf_frame, false);
+
for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ))
Opts.DebugPrefixMap.insert(StringRef(Arg).split('='));
@@ -784,8 +788,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
llvm::Triple::arm, llvm::Triple::armeb};
llvm::Triple T(TargetOpts.Triple);
- if (Opts.OptimizationLevel > 0 &&
- Opts.getDebugInfo() >= codegenoptions::LimitedDebugInfo &&
+ if (Opts.OptimizationLevel > 0 && Opts.hasReducedDebugInfo() &&
llvm::is_contained(DebugEntryValueArchs, T.getArch()))
Opts.EnableDebugEntryValues = Args.hasArg(OPT_femit_debug_entry_values);
@@ -806,6 +809,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.RecordCommandLine = Args.getLastArgValue(OPT_record_command_line);
Opts.MergeAllConstants = Args.hasArg(OPT_fmerge_all_constants);
Opts.NoCommon = Args.hasArg(OPT_fno_common);
+ Opts.NoInlineLineTables = Args.hasArg(OPT_gno_inline_line_tables);
Opts.NoImplicitFloat = Args.hasArg(OPT_no_implicit_float);
Opts.OptimizeSize = getOptimizationLevelSize(Args);
Opts.SimplifyLibCalls = !(Args.hasArg(OPT_fno_builtin) ||
@@ -949,7 +953,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
<< Args.getLastArg(OPT_mthread_model)->getAsString(Args)
<< Opts.ThreadModel;
Opts.TrapFuncName = Args.getLastArgValue(OPT_ftrap_function_EQ);
- Opts.UseInitArray = Args.hasArg(OPT_fuse_init_array);
+ Opts.UseInitArray = !Args.hasArg(OPT_fno_use_init_array);
Opts.FunctionSections = Args.hasFlag(OPT_ffunction_sections,
OPT_fno_function_sections, false);
@@ -1003,6 +1007,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name);
Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier);
+ Opts.ControlFlowGuardNoChecks = Args.hasArg(OPT_cfguard_no_checks);
Opts.ControlFlowGuard = Args.hasArg(OPT_cfguard);
Opts.DisableGCov = Args.hasArg(OPT_test_coverage);
@@ -1096,8 +1101,13 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
parseXRayInstrumentationBundle("-fxray-instrumentation-bundle=", A, Args,
Diags, Opts.XRayInstrumentationBundle);
+ Opts.PatchableFunctionEntryCount =
+ getLastArgIntValue(Args, OPT_fpatchable_function_entry_EQ, 0, Diags);
Opts.InstrumentForProfiling = Args.hasArg(OPT_pg);
Opts.CallFEntry = Args.hasArg(OPT_mfentry);
+ Opts.MNopMCount = Args.hasArg(OPT_mnop_mcount);
+ Opts.RecordMCount = Args.hasArg(OPT_mrecord_mcount);
+ Opts.PackedStack = Args.hasArg(OPT_mpacked_stack);
Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info);
if (const Arg *A = Args.getLastArg(OPT_fcf_protection_EQ)) {
@@ -1258,15 +1268,12 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
}
}
+ Opts.TLSSize = getLastArgIntValue(Args, OPT_mtls_size_EQ, 0, Diags);
+
if (Arg *A = Args.getLastArg(OPT_fdenormal_fp_math_EQ)) {
StringRef Val = A->getValue();
- if (Val == "ieee")
- Opts.FPDenormalMode = "ieee";
- else if (Val == "preserve-sign")
- Opts.FPDenormalMode = "preserve-sign";
- else if (Val == "positive-zero")
- Opts.FPDenormalMode = "positive-zero";
- else
+ Opts.FPDenormalMode = llvm::parseDenormalFPAttribute(Val);
+ if (Opts.FPDenormalMode == llvm::DenormalMode::Invalid)
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
}
@@ -1441,7 +1448,26 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
// Add sanitizer blacklists as extra dependencies.
// They won't be discovered by the regular preprocessor, so
// we let make / ninja to know about this implicit dependency.
- Opts.ExtraDeps = Args.getAllArgValues(OPT_fdepfile_entry);
+ if (!Args.hasArg(OPT_fno_sanitize_blacklist)) {
+ for (const auto *A : Args.filtered(OPT_fsanitize_blacklist)) {
+ StringRef Val = A->getValue();
+ if (Val.find('=') == StringRef::npos)
+ Opts.ExtraDeps.push_back(Val);
+ }
+ if (Opts.IncludeSystemHeaders) {
+ for (const auto *A : Args.filtered(OPT_fsanitize_system_blacklist)) {
+ StringRef Val = A->getValue();
+ if (Val.find('=') == StringRef::npos)
+ Opts.ExtraDeps.push_back(Val);
+ }
+ }
+ }
+
+ // Propagate the extra dependencies.
+ for (const auto *A : Args.filtered(OPT_fdepfile_entry)) {
+ Opts.ExtraDeps.push_back(A->getValue());
+ }
+
// Only the -fmodule-file=<file> form.
for (const auto *A : Args.filtered(OPT_fmodule_file)) {
StringRef Val = A->getValue();
@@ -1866,6 +1892,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.ModulesEmbedFiles = Args.getAllArgValues(OPT_fmodules_embed_file_EQ);
Opts.ModulesEmbedAllFiles = Args.hasArg(OPT_fmodules_embed_all_files);
Opts.IncludeTimestamps = !Args.hasArg(OPT_fno_pch_timestamp);
+ Opts.UseTemporary = !Args.hasArg(OPT_fno_temp_file);
Opts.CodeCompleteOpts.IncludeMacros
= Args.hasArg(OPT_code_completion_macros);
@@ -2528,7 +2555,20 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.CUDADeviceApproxTranscendentals = 1;
Opts.GPURelocatableDeviceCode = Args.hasArg(OPT_fgpu_rdc);
+ if (Args.hasArg(OPT_fgpu_allow_device_init)) {
+ if (Opts.HIP)
+ Opts.GPUAllowDeviceInit = 1;
+ else
+ Diags.Report(diag::warn_ignored_hip_only_option)
+ << Args.getLastArg(OPT_fgpu_allow_device_init)->getAsString(Args);
+ }
Opts.HIPUseNewLaunchAPI = Args.hasArg(OPT_fhip_new_launch_api);
+ if (Opts.HIP)
+ Opts.GPUMaxThreadsPerBlock = getLastArgIntValue(
+ Args, OPT_gpu_max_threads_per_block_EQ, Opts.GPUMaxThreadsPerBlock);
+ else if (Args.hasArg(OPT_gpu_max_threads_per_block_EQ))
+ Diags.Report(diag::warn_ignored_hip_only_option)
+ << Args.getLastArg(OPT_gpu_max_threads_per_block_EQ)->getAsString(Args);
if (Opts.ObjC) {
if (Arg *arg = Args.getLastArg(OPT_fobjc_runtime_EQ)) {
@@ -2689,7 +2729,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
OPT_fno_dollars_in_identifiers,
Opts.DollarIdents);
Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings);
- Opts.VtorDispMode = getLastArgIntValue(Args, OPT_vtordisp_mode_EQ, 1, Diags);
+ Opts.setVtorDispMode(
+ MSVtorDispMode(getLastArgIntValue(Args, OPT_vtordisp_mode_EQ, 1, Diags)));
Opts.Borland = Args.hasArg(OPT_fborland_extensions);
Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings);
Opts.ConstStrings = Args.hasFlag(OPT_fconst_strings, OPT_fno_const_strings,
@@ -2749,6 +2790,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional);
Opts.Coroutines = Opts.CPlusPlus2a || Args.hasArg(OPT_fcoroutines_ts);
+ Opts.ConvergentFunctions = Opts.OpenCL || (Opts.CUDA && Opts.CUDAIsDevice) ||
+ Args.hasArg(OPT_fconvergent_functions);
+
Opts.DoubleSquareBracketAttributes =
Args.hasFlag(OPT_fdouble_square_bracket_attributes,
OPT_fno_double_square_bracket_attributes,
@@ -2823,8 +2867,6 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
getLastArgIntValue(Args, OPT_fconstexpr_steps, 1048576, Diags);
Opts.EnableNewConstInterp =
Args.hasArg(OPT_fexperimental_new_constant_interpreter);
- Opts.ForceNewConstInterp =
- Args.hasArg(OPT_fforce_experimental_new_constant_interpreter);
Opts.BracketDepth = getLastArgIntValue(Args, OPT_fbracket_depth, 256, Diags);
Opts.DelayedTemplateParsing = Args.hasArg(OPT_fdelayed_template_parsing);
Opts.NumLargeByValueCopy =
@@ -2951,7 +2993,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Arch != llvm::Triple::x86;
emitError |= (DefaultCC == LangOptions::DCC_VectorCall ||
DefaultCC == LangOptions::DCC_RegCall) &&
- !(Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64);
+ !T.isX86();
if (emitError)
Diags.Report(diag::err_drv_argument_not_allowed_with)
<< A->getSpelling() << T.getTriple();
@@ -2985,6 +3027,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.OpenMP && !Args.hasArg(options::OPT_fnoopenmp_use_tls);
Opts.OpenMPIsDevice =
Opts.OpenMP && Args.hasArg(options::OPT_fopenmp_is_device);
+ Opts.OpenMPIRBuilder =
+ Opts.OpenMP && Args.hasArg(options::OPT_fopenmp_enable_irbuilder);
bool IsTargetSpecified =
Opts.OpenMPIsDevice || Args.hasArg(options::OPT_fopenmp_targets_EQ);
@@ -3041,7 +3085,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
llvm::Triple TT(A->getValue(i));
if (TT.getArch() == llvm::Triple::UnknownArch ||
- !(TT.getArch() == llvm::Triple::ppc ||
+ !(TT.getArch() == llvm::Triple::aarch64 ||
+ TT.getArch() == llvm::Triple::ppc ||
TT.getArch() == llvm::Triple::ppc64 ||
TT.getArch() == llvm::Triple::ppc64le ||
TT.getArch() == llvm::Triple::nvptx ||
@@ -3116,6 +3161,34 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
}
+ LangOptions::FPRoundingModeKind FPRM = LangOptions::FPR_ToNearest;
+ if (Args.hasArg(OPT_frounding_math)) {
+ FPRM = LangOptions::FPR_Dynamic;
+ }
+ Opts.setFPRoundingMode(FPRM);
+
+ if (Args.hasArg(OPT_ftrapping_math)) {
+ Opts.setFPExceptionMode(LangOptions::FPE_Strict);
+ }
+
+ if (Args.hasArg(OPT_fno_trapping_math)) {
+ Opts.setFPExceptionMode(LangOptions::FPE_Ignore);
+ }
+
+ LangOptions::FPExceptionModeKind FPEB = LangOptions::FPE_Ignore;
+ if (Arg *A = Args.getLastArg(OPT_ffp_exception_behavior_EQ)) {
+ StringRef Val = A->getValue();
+ if (Val.equals("ignore"))
+ FPEB = LangOptions::FPE_Ignore;
+ else if (Val.equals("maytrap"))
+ FPEB = LangOptions::FPE_MayTrap;
+ else if (Val.equals("strict"))
+ FPEB = LangOptions::FPE_Strict;
+ else
+ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
+ }
+ Opts.setFPExceptionMode(FPEB);
+
Opts.RetainCommentsFromSystemHeaders =
Args.hasArg(OPT_fretain_comments_from_system_headers);
@@ -3151,6 +3224,11 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.SanitizeAddressFieldPadding =
getLastArgIntValue(Args, OPT_fsanitize_address_field_padding, 0, Diags);
Opts.SanitizerBlacklistFiles = Args.getAllArgValues(OPT_fsanitize_blacklist);
+ std::vector<std::string> systemBlacklists =
+ Args.getAllArgValues(OPT_fsanitize_system_blacklist);
+ Opts.SanitizerBlacklistFiles.insert(Opts.SanitizerBlacklistFiles.end(),
+ systemBlacklists.begin(),
+ systemBlacklists.end());
// -fxray-instrument
Opts.XRayInstrument =
@@ -3279,6 +3357,9 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
for (const auto *A : Args.filtered(OPT_error_on_deserialized_pch_decl))
Opts.DeserializedPCHDeclsToErrorOn.insert(A->getValue());
+ for (const auto &A : Args.getAllArgValues(OPT_fmacro_prefix_map_EQ))
+ Opts.MacroPrefixMap.insert(StringRef(A).split('='));
+
if (const Arg *A = Args.getLastArg(OPT_preamble_bytes_EQ)) {
StringRef Value(A->getValue());
size_t Comma = Value.find(',');
@@ -3645,35 +3726,8 @@ std::string CompilerInvocation::getModuleHash() const {
return llvm::APInt(64, code).toString(36, /*Signed=*/false);
}
-template<typename IntTy>
-static IntTy getLastArgIntValueImpl(const ArgList &Args, OptSpecifier Id,
- IntTy Default,
- DiagnosticsEngine *Diags) {
- IntTy Res = Default;
- if (Arg *A = Args.getLastArg(Id)) {
- if (StringRef(A->getValue()).getAsInteger(10, Res)) {
- if (Diags)
- Diags->Report(diag::err_drv_invalid_int_value) << A->getAsString(Args)
- << A->getValue();
- }
- }
- return Res;
-}
-
namespace clang {
-// Declared in clang/Frontend/Utils.h.
-int getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default,
- DiagnosticsEngine *Diags) {
- return getLastArgIntValueImpl<int>(Args, Id, Default, Diags);
-}
-
-uint64_t getLastArgUInt64Value(const ArgList &Args, OptSpecifier Id,
- uint64_t Default,
- DiagnosticsEngine *Diags) {
- return getLastArgIntValueImpl<uint64_t>(Args, Id, Default, Diags);
-}
-
IntrusiveRefCntPtr<llvm::vfs::FileSystem>
createVFSFromCompilerInvocation(const CompilerInvocation &CI,
DiagnosticsEngine &Diags) {
diff --git a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp b/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
index ab62b633cda3..18c4814bbd5c 100644
--- a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
+++ b/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
@@ -26,7 +26,8 @@ using namespace llvm::opt;
std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine(
ArrayRef<const char *> ArgList, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
- IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, bool ShouldRecoverOnErorrs) {
+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, bool ShouldRecoverOnErorrs,
+ std::vector<std::string> *CC1Args) {
if (!Diags.get()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
@@ -89,6 +90,8 @@ std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine(
}
const ArgStringList &CCArgs = Cmd.getArguments();
+ if (CC1Args)
+ *CC1Args = {CCArgs.begin(), CCArgs.end()};
auto CI = std::make_unique<CompilerInvocation>();
if (!CompilerInvocation::CreateFromArgs(*CI, CCArgs, *Diags) &&
!ShouldRecoverOnErorrs)
diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
index b3b7976f8f3e..934d17b3c925 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -10,6 +10,7 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclGroup.h"
+#include "clang/Basic/Builtins.h"
#include "clang/Basic/LangStandard.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
@@ -870,9 +871,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// extended by an external source.
if (CI.getLangOpts().Modules || !CI.hasASTContext() ||
!CI.getASTContext().getExternalSource()) {
- CI.createModuleManager();
- CI.getModuleManager()->setDeserializationListener(DeserialListener,
- DeleteDeserialListener);
+ CI.createASTReader();
+ CI.getASTReader()->setDeserializationListener(DeserialListener,
+ DeleteDeserialListener);
}
}
@@ -891,7 +892,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
} else {
// FIXME: If this is a problem, recover from it by creating a multiplex
// source.
- assert((!CI.getLangOpts().Modules || CI.getModuleManager()) &&
+ assert((!CI.getLangOpts().Modules || CI.getASTReader()) &&
"modules enabled but created an external source that "
"doesn't support modules");
}
diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp
index 4d47c768ad3c..8574d0a7e813 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -140,7 +140,7 @@ GeneratePCHAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile,
std::unique_ptr<raw_pwrite_stream> OS =
CI.createOutputFile(CI.getFrontendOpts().OutputFile, /*Binary=*/true,
/*RemoveFileOnSignal=*/false, InFile,
- /*Extension=*/"", /*UseTemporary=*/true);
+ /*Extension=*/"", CI.getFrontendOpts().UseTemporary);
if (!OS)
return nullptr;
@@ -413,6 +413,8 @@ private:
return "ExceptionSpecInstantiation";
case CodeSynthesisContext::DeclaringSpecialMember:
return "DeclaringSpecialMember";
+ case CodeSynthesisContext::DeclaringImplicitEqualityComparison:
+ return "DeclaringImplicitEqualityComparison";
case CodeSynthesisContext::DefiningSynthesizedFunction:
return "DefiningSynthesizedFunction";
case CodeSynthesisContext::RewritingOperatorAsSpaceship:
@@ -423,6 +425,10 @@ private:
return "ConstraintsCheck";
case CodeSynthesisContext::ConstraintSubstitution:
return "ConstraintSubstitution";
+ case CodeSynthesisContext::ConstraintNormalization:
+ return "ConstraintNormalization";
+ case CodeSynthesisContext::ParameterMappingSubstitution:
+ return "ParameterMappingSubstitution";
}
return "";
}
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index c27c33c530f6..2c7e3a56c043 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -484,6 +484,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
LangOpts.CPlusPlus2a ? "201907L" :
LangOpts.CPlusPlus17 ? "201603L" :
LangOpts.CPlusPlus14 ? "201304L" : "200704");
+ Builder.defineMacro("__cpp_constexpr_in_decltype", "201711L");
Builder.defineMacro("__cpp_range_based_for",
LangOpts.CPlusPlus17 ? "201603L" : "200907");
Builder.defineMacro("__cpp_static_assert",
@@ -506,8 +507,10 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
if (LangOpts.CPlusPlus14) {
Builder.defineMacro("__cpp_binary_literals", "201304L");
Builder.defineMacro("__cpp_digit_separators", "201309L");
- Builder.defineMacro("__cpp_init_captures", "201304L");
- Builder.defineMacro("__cpp_generic_lambdas", "201304L");
+ Builder.defineMacro("__cpp_init_captures",
+ LangOpts.CPlusPlus2a ? "201803L" : "201304L");
+ Builder.defineMacro("__cpp_generic_lambdas",
+ LangOpts.CPlusPlus2a ? "201707L" : "201304L");
Builder.defineMacro("__cpp_decltype_auto", "201304L");
Builder.defineMacro("__cpp_return_type_deduction", "201304L");
Builder.defineMacro("__cpp_aggregate_nsdmi", "201304L");
@@ -523,7 +526,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_noexcept_function_type", "201510L");
Builder.defineMacro("__cpp_capture_star_this", "201603L");
Builder.defineMacro("__cpp_if_constexpr", "201606L");
- Builder.defineMacro("__cpp_deduction_guides", "201703L");
+ Builder.defineMacro("__cpp_deduction_guides", "201703L"); // (not latest)
Builder.defineMacro("__cpp_template_auto", "201606L"); // (old name)
Builder.defineMacro("__cpp_namespace_attributes", "201411L");
Builder.defineMacro("__cpp_enumerator_attributes", "201411L");
@@ -531,7 +534,8 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_variadic_using", "201611L");
Builder.defineMacro("__cpp_aggregate_bases", "201603L");
Builder.defineMacro("__cpp_structured_bindings", "201606L");
- Builder.defineMacro("__cpp_nontype_template_args", "201411L");
+ Builder.defineMacro("__cpp_nontype_template_args",
+ "201411L"); // (not latest)
Builder.defineMacro("__cpp_fold_expressions", "201603L");
Builder.defineMacro("__cpp_guaranteed_copy_elision", "201606L");
Builder.defineMacro("__cpp_nontype_template_parameter_auto", "201606L");
@@ -543,9 +547,17 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
// C++20 features.
if (LangOpts.CPlusPlus2a) {
+ //Builder.defineMacro("__cpp_aggregate_paren_init", "201902L");
+ //Builder.defineMacro("__cpp_concepts", "201907L");
Builder.defineMacro("__cpp_conditional_explicit", "201806L");
+ //Builder.defineMacro("__cpp_consteval", "201811L");
Builder.defineMacro("__cpp_constexpr_dynamic_alloc", "201907L");
Builder.defineMacro("__cpp_constinit", "201907L");
+ //Builder.defineMacro("__cpp_coroutines", "201902L");
+ Builder.defineMacro("__cpp_designated_initializers", "201707L");
+ Builder.defineMacro("__cpp_impl_three_way_comparison", "201907L");
+ //Builder.defineMacro("__cpp_modules", "201907L");
+ //Builder.defineMacro("__cpp_using_enum", "201907L");
}
if (LangOpts.Char8)
Builder.defineMacro("__cpp_char8_t", "201811L");
@@ -1124,7 +1136,8 @@ void clang::InitializePreprocessor(
if (InitOpts.UsePredefines) {
// FIXME: This will create multiple definitions for most of the predefined
// macros. This is not the right way to handle this.
- if ((LangOpts.CUDA || LangOpts.OpenMPIsDevice) && PP.getAuxTargetInfo())
+ if ((LangOpts.CUDA || LangOpts.OpenMPIsDevice || LangOpts.SYCLIsDevice) &&
+ PP.getAuxTargetInfo())
InitializePredefinedMacros(*PP.getAuxTargetInfo(), LangOpts, FEOpts,
PP.getPreprocessorOpts(), Builder);
diff --git a/clang/lib/Frontend/InterfaceStubFunctionsConsumer.cpp b/clang/lib/Frontend/InterfaceStubFunctionsConsumer.cpp
index 0b28b78de3b1..7241081d6cc0 100644
--- a/clang/lib/Frontend/InterfaceStubFunctionsConsumer.cpp
+++ b/clang/lib/Frontend/InterfaceStubFunctionsConsumer.cpp
@@ -52,11 +52,16 @@ class InterfaceStubFunctionsConsumer : public ASTConsumer {
if (!isVisible(ND))
return true;
- if (const VarDecl *VD = dyn_cast<VarDecl>(ND))
+ if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
+ if (const auto *Parent = VD->getParentFunctionOrMethod())
+ if (isa<BlockDecl>(Parent) || isa<CXXMethodDecl>(Parent))
+ return true;
+
if ((VD->getStorageClass() == StorageClass::SC_Extern) ||
(VD->getStorageClass() == StorageClass::SC_Static &&
VD->getParentFunctionOrMethod() == nullptr))
return true;
+ }
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
if (FD->isInlined() && !isa<CXXMethodDecl>(FD) &&
@@ -182,8 +187,36 @@ class InterfaceStubFunctionsConsumer : public ASTConsumer {
case Decl::Kind::Enum:
case Decl::Kind::EnumConstant:
case Decl::Kind::TemplateTypeParm:
+ case Decl::Kind::NonTypeTemplateParm:
+ case Decl::Kind::CXXConversion:
+ case Decl::Kind::UnresolvedUsingValue:
+ case Decl::Kind::Using:
+ case Decl::Kind::UsingShadow:
+ case Decl::Kind::TypeAliasTemplate:
+ case Decl::Kind::TypeAlias:
+ case Decl::Kind::VarTemplate:
+ case Decl::Kind::VarTemplateSpecialization:
+ case Decl::Kind::UsingDirective:
+ case Decl::Kind::TemplateTemplateParm:
+ case Decl::Kind::ClassTemplatePartialSpecialization:
+ case Decl::Kind::IndirectField:
+ case Decl::Kind::ConstructorUsingShadow:
+ case Decl::Kind::CXXDeductionGuide:
+ case Decl::Kind::NamespaceAlias:
+ case Decl::Kind::UnresolvedUsingTypename:
return true;
- case Decl::Kind::Var:
+ case Decl::Kind::Var: {
+ // Bail on any VarDecl that either has no named symbol.
+ if (!ND->getIdentifier())
+ return true;
+ const auto *VD = cast<VarDecl>(ND);
+ // Bail on any VarDecl that is a dependent or templated type.
+ if (VD->isTemplated() || VD->getType()->isDependentType())
+ return true;
+ if (WriteNamedDecl(ND, Symbols, RDO))
+ return true;
+ break;
+ }
case Decl::Kind::ParmVar:
case Decl::Kind::CXXMethod:
case Decl::Kind::CXXConstructor:
@@ -251,14 +284,16 @@ public:
for (const NamedDecl *ND : v.NamedDecls)
HandleNamedDecl(ND, Symbols, FromTU);
- auto writeIfsV1 =
- [this](const llvm::Triple &T, const MangledSymbols &Symbols,
- const ASTContext &context, StringRef Format,
- raw_ostream &OS) -> void {
+ auto writeIfsV1 = [this](const llvm::Triple &T,
+ const MangledSymbols &Symbols,
+ const ASTContext &context, StringRef Format,
+ raw_ostream &OS) -> void {
OS << "--- !" << Format << "\n";
OS << "IfsVersion: 1.0\n";
OS << "Triple: " << T.str() << "\n";
- OS << "ObjectFileFormat: " << "ELF" << "\n"; // TODO: For now, just ELF.
+ OS << "ObjectFileFormat: "
+ << "ELF"
+ << "\n"; // TODO: For now, just ELF.
OS << "Symbols:\n";
for (const auto &E : Symbols) {
const MangledSymbol &Symbol = E.second;
diff --git a/clang/lib/Frontend/MultiplexConsumer.cpp b/clang/lib/Frontend/MultiplexConsumer.cpp
index 04e896296c95..5abbb3a235b4 100644
--- a/clang/lib/Frontend/MultiplexConsumer.cpp
+++ b/clang/lib/Frontend/MultiplexConsumer.cpp
@@ -322,6 +322,11 @@ void MultiplexConsumer::CompleteTentativeDefinition(VarDecl *D) {
Consumer->CompleteTentativeDefinition(D);
}
+void MultiplexConsumer::CompleteExternalDeclaration(VarDecl *D) {
+ for (auto &Consumer : Consumers)
+ Consumer->CompleteExternalDeclaration(D);
+}
+
void MultiplexConsumer::AssignInheritanceModel(CXXRecordDecl *RD) {
for (auto &Consumer : Consumers)
Consumer->AssignInheritanceModel(RD);
diff --git a/clang/lib/Frontend/PrecompiledPreamble.cpp b/clang/lib/Frontend/PrecompiledPreamble.cpp
index ced32c670288..0e5a8e504dc5 100644
--- a/clang/lib/Frontend/PrecompiledPreamble.cpp
+++ b/clang/lib/Frontend/PrecompiledPreamble.cpp
@@ -535,21 +535,15 @@ PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile() {
// FIXME: This is a hack so that we can override the preamble file during
// crash-recovery testing, which is the only case where the preamble files
// are not necessarily cleaned up.
- const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE");
- if (TmpFile)
- return TempPCHFile::createFromCustomPath(TmpFile);
- return TempPCHFile::createInSystemTempDir("preamble", "pch");
-}
+ if (const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE"))
+ return TempPCHFile(TmpFile);
-llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
-PrecompiledPreamble::TempPCHFile::createInSystemTempDir(const Twine &Prefix,
- StringRef Suffix) {
llvm::SmallString<64> File;
// Using a version of createTemporaryFile with a file descriptor guarantees
// that we would never get a race condition in a multi-threaded setting
// (i.e., multiple threads getting the same temporary path).
int FD;
- auto EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, FD, File);
+ auto EC = llvm::sys::fs::createTemporaryFile("preamble", "pch", FD, File);
if (EC)
return EC;
// We only needed to make sure the file exists, close the file right away.
@@ -557,11 +551,6 @@ PrecompiledPreamble::TempPCHFile::createInSystemTempDir(const Twine &Prefix,
return TempPCHFile(std::move(File).str());
}
-llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
-PrecompiledPreamble::TempPCHFile::createFromCustomPath(const Twine &Path) {
- return TempPCHFile(Path.str());
-}
-
PrecompiledPreamble::TempPCHFile::TempPCHFile(std::string FilePath)
: FilePath(std::move(FilePath)) {
TemporaryFiles::getInstance().addFile(*this->FilePath);
diff --git a/clang/lib/Frontend/Rewrite/FrontendActions.cpp b/clang/lib/Frontend/Rewrite/FrontendActions.cpp
index 549b86edebcd..aaffbde3309b 100644
--- a/clang/lib/Frontend/Rewrite/FrontendActions.cpp
+++ b/clang/lib/Frontend/Rewrite/FrontendActions.cpp
@@ -21,7 +21,7 @@
#include "clang/Rewrite/Frontend/FixItRewriter.h"
#include "clang/Rewrite/Frontend/Rewriters.h"
#include "clang/Serialization/ASTReader.h"
-#include "clang/Serialization/Module.h"
+#include "clang/Serialization/ModuleFile.h"
#include "clang/Serialization/ModuleManager.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/CrashRecoveryContext.h"
@@ -220,7 +220,7 @@ public:
return;
serialization::ModuleFile *MF =
- CI.getModuleManager()->getModuleManager().lookup(*File);
+ CI.getASTReader()->getModuleManager().lookup(*File);
assert(MF && "missing module file for loaded module?");
// Not interested in PCH / preambles.
@@ -293,8 +293,8 @@ bool RewriteIncludesAction::BeginSourceFileAction(CompilerInstance &CI) {
// If we're rewriting imports, set up a listener to track when we import
// module files.
if (CI.getPreprocessorOutputOpts().RewriteImports) {
- CI.createModuleManager();
- CI.getModuleManager()->addListener(
+ CI.createASTReader();
+ CI.getASTReader()->addListener(
std::make_unique<RewriteImportsListener>(CI, OutputStream));
}
diff --git a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
index 45495065ada6..831f95e8c6be 100644
--- a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
+++ b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
@@ -908,9 +908,9 @@ RewriteModernObjC::getIvarAccessString(ObjCIvarDecl *D) {
static bool mustSynthesizeSetterGetterMethod(ObjCImplementationDecl *IMP,
ObjCPropertyDecl *PD,
bool getter) {
- return getter ? !IMP->getInstanceMethod(PD->getGetterName())
- : !IMP->getInstanceMethod(PD->getSetterName());
-
+ auto *OMD = IMP->getInstanceMethod(getter ? PD->getGetterName()
+ : PD->getSetterName());
+ return !OMD || OMD->isSynthesizedAccessorStub();
}
void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
@@ -952,7 +952,7 @@ void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
"id objc_getProperty(id, SEL, long, bool);\n";
}
RewriteObjCMethodDecl(OID->getContainingInterface(),
- PD->getGetterMethodDecl(), Getr);
+ PID->getGetterMethodDecl(), Getr);
Getr += "{ ";
// Synthesize an explicit cast to gain access to the ivar.
// See objc-act.c:objc_synthesize_new_getter() for details.
@@ -960,7 +960,7 @@ void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
// return objc_getProperty(self, _cmd, offsetof(ClassDecl, OID), 1)
Getr += "typedef ";
const FunctionType *FPRetType = nullptr;
- RewriteTypeIntoString(PD->getGetterMethodDecl()->getReturnType(), Getr,
+ RewriteTypeIntoString(PID->getGetterMethodDecl()->getReturnType(), Getr,
FPRetType);
Getr += " _TYPE";
if (FPRetType) {
@@ -1012,7 +1012,7 @@ void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
}
RewriteObjCMethodDecl(OID->getContainingInterface(),
- PD->getSetterMethodDecl(), Setr);
+ PID->getSetterMethodDecl(), Setr);
Setr += "{ ";
// Synthesize an explicit cast to initialize the ivar.
// See objc-act.c:objc_synthesize_new_setter() for details.
@@ -1346,6 +1346,8 @@ void RewriteModernObjC::RewriteImplementationDecl(Decl *OID) {
InsertText(CID->getBeginLoc(), "// ");
for (auto *OMD : IMD ? IMD->instance_methods() : CID->instance_methods()) {
+ if (!OMD->getBody())
+ continue;
std::string ResultStr;
RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr);
SourceLocation LocStart = OMD->getBeginLoc();
@@ -1357,6 +1359,8 @@ void RewriteModernObjC::RewriteImplementationDecl(Decl *OID) {
}
for (auto *OMD : IMD ? IMD->class_methods() : CID->class_methods()) {
+ if (!OMD->getBody())
+ continue;
std::string ResultStr;
RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr);
SourceLocation LocStart = OMD->getBeginLoc();
@@ -7031,12 +7035,12 @@ void RewriteModernObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
ObjCPropertyDecl *PD = Prop->getPropertyDecl();
if (!PD)
continue;
- if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
+ if (ObjCMethodDecl *Getter = Prop->getGetterMethodDecl())
if (mustSynthesizeSetterGetterMethod(IDecl, PD, true /*getter*/))
InstanceMethods.push_back(Getter);
if (PD->isReadOnly())
continue;
- if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl())
+ if (ObjCMethodDecl *Setter = Prop->getSetterMethodDecl())
if (mustSynthesizeSetterGetterMethod(IDecl, PD, false /*setter*/))
InstanceMethods.push_back(Setter);
}
@@ -7281,11 +7285,11 @@ void RewriteModernObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
ObjCPropertyDecl *PD = Prop->getPropertyDecl();
if (!PD)
continue;
- if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
+ if (ObjCMethodDecl *Getter = Prop->getGetterMethodDecl())
InstanceMethods.push_back(Getter);
if (PD->isReadOnly())
continue;
- if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl())
+ if (ObjCMethodDecl *Setter = Prop->getSetterMethodDecl())
InstanceMethods.push_back(Setter);
}
diff --git a/clang/lib/Frontend/Rewrite/RewriteObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteObjC.cpp
index 6a22da178fbc..0cb7592b9982 100644
--- a/clang/lib/Frontend/Rewrite/RewriteObjC.cpp
+++ b/clang/lib/Frontend/Rewrite/RewriteObjC.cpp
@@ -786,8 +786,9 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
if (!OID)
return;
+
unsigned Attributes = PD->getPropertyAttributes();
- if (!PD->getGetterMethodDecl()->isDefined()) {
+ if (PID->getGetterMethodDecl() && !PID->getGetterMethodDecl()->isDefined()) {
bool GenGetProperty = !(Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) &&
(Attributes & (ObjCPropertyDecl::OBJC_PR_retain |
ObjCPropertyDecl::OBJC_PR_copy));
@@ -799,7 +800,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
"id objc_getProperty(id, SEL, long, bool);\n";
}
RewriteObjCMethodDecl(OID->getContainingInterface(),
- PD->getGetterMethodDecl(), Getr);
+ PID->getGetterMethodDecl(), Getr);
Getr += "{ ";
// Synthesize an explicit cast to gain access to the ivar.
// See objc-act.c:objc_synthesize_new_getter() for details.
@@ -807,7 +808,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
// return objc_getProperty(self, _cmd, offsetof(ClassDecl, OID), 1)
Getr += "typedef ";
const FunctionType *FPRetType = nullptr;
- RewriteTypeIntoString(PD->getGetterMethodDecl()->getReturnType(), Getr,
+ RewriteTypeIntoString(PID->getGetterMethodDecl()->getReturnType(), Getr,
FPRetType);
Getr += " _TYPE";
if (FPRetType) {
@@ -843,7 +844,8 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
InsertText(onePastSemiLoc, Getr);
}
- if (PD->isReadOnly() || PD->getSetterMethodDecl()->isDefined())
+ if (PD->isReadOnly() || !PID->getSetterMethodDecl() ||
+ PID->getSetterMethodDecl()->isDefined())
return;
// Generate the 'setter' function.
@@ -858,7 +860,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
}
RewriteObjCMethodDecl(OID->getContainingInterface(),
- PD->getSetterMethodDecl(), Setr);
+ PID->getSetterMethodDecl(), Setr);
Setr += "{ ";
// Synthesize an explicit cast to initialize the ivar.
// See objc-act.c:objc_synthesize_new_setter() for details.
@@ -1168,6 +1170,8 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) {
InsertText(IMD ? IMD->getBeginLoc() : CID->getBeginLoc(), "// ");
for (auto *OMD : IMD ? IMD->instance_methods() : CID->instance_methods()) {
+ if (!OMD->getBody())
+ continue;
std::string ResultStr;
RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr);
SourceLocation LocStart = OMD->getBeginLoc();
@@ -1179,6 +1183,8 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) {
}
for (auto *OMD : IMD ? IMD->class_methods() : CID->class_methods()) {
+ if (!OMD->getBody())
+ continue;
std::string ResultStr;
RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr);
SourceLocation LocStart = OMD->getBeginLoc();
@@ -5355,12 +5361,12 @@ void RewriteObjCFragileABI::RewriteObjCClassMetaData(ObjCImplementationDecl *IDe
ObjCPropertyDecl *PD = Prop->getPropertyDecl();
if (!PD)
continue;
- if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
+ if (ObjCMethodDecl *Getter = Prop->getGetterMethodDecl())
if (!Getter->isDefined())
InstanceMethods.push_back(Getter);
if (PD->isReadOnly())
continue;
- if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl())
+ if (ObjCMethodDecl *Setter = Prop->getSetterMethodDecl())
if (!Setter->isDefined())
InstanceMethods.push_back(Setter);
}
@@ -5633,11 +5639,11 @@ void RewriteObjCFragileABI::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *ID
ObjCPropertyDecl *PD = Prop->getPropertyDecl();
if (!PD)
continue;
- if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
+ if (ObjCMethodDecl *Getter = Prop->getGetterMethodDecl())
InstanceMethods.push_back(Getter);
if (PD->isReadOnly())
continue;
- if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl())
+ if (ObjCMethodDecl *Setter = Prop->getSetterMethodDecl())
InstanceMethods.push_back(Setter);
}
RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(),
diff --git a/clang/lib/Frontend/TextDiagnostic.cpp b/clang/lib/Frontend/TextDiagnostic.cpp
index 7bb6c5b74d5f..78acaaf9f96e 100644
--- a/clang/lib/Frontend/TextDiagnostic.cpp
+++ b/clang/lib/Frontend/TextDiagnostic.cpp
@@ -761,11 +761,12 @@ void TextDiagnostic::printDiagnosticMessage(raw_ostream &OS,
}
void TextDiagnostic::emitFilename(StringRef Filename, const SourceManager &SM) {
- SmallVector<char, 128> AbsoluteFilename;
+#ifdef _WIN32
+ SmallString<4096> TmpFilename;
+#endif
if (DiagOpts->AbsolutePath) {
- auto Dir = SM.getFileManager().getDirectory(
- llvm::sys::path::parent_path(Filename));
- if (Dir) {
+ auto 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>".
@@ -781,16 +782,14 @@ void TextDiagnostic::emitFilename(StringRef Filename, const SourceManager &SM) {
// on Windows we can just use llvm::sys::path::remove_dots(), because,
// on that system, both aforementioned paths point to the same place.
#ifdef _WIN32
- SmallString<4096> DirName = (*Dir)->getName();
- llvm::sys::fs::make_absolute(DirName);
- llvm::sys::path::native(DirName);
- llvm::sys::path::remove_dots(DirName, /* remove_dot_dot */ true);
+ 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
- StringRef DirName = SM.getFileManager().getCanonicalName(*Dir);
+ Filename = SM.getFileManager().getCanonicalName(*File);
#endif
- llvm::sys::path::append(AbsoluteFilename, DirName,
- llvm::sys::path::filename(Filename));
- Filename = StringRef(AbsoluteFilename.data(), AbsoluteFilename.size());
}
}
diff --git a/clang/lib/Headers/altivec.h b/clang/lib/Headers/altivec.h
index 8352f8f740c2..7e231a2a428e 100644
--- a/clang/lib/Headers/altivec.h
+++ b/clang/lib/Headers/altivec.h
@@ -14784,7 +14784,7 @@ static __inline__ int __ATTRS_o_ai vec_all_ne(vector bool long long __a,
static __inline__ int __ATTRS_o_ai vec_all_ne(vector float __a,
vector float __b) {
#ifdef __VSX__
- return __builtin_vsx_xvcmpeqdp_p(__CR6_EQ, (vector double)__a, (vector double)__b);
+ return __builtin_vsx_xvcmpeqsp_p(__CR6_EQ, __a, __b);
#else
return __builtin_altivec_vcmpeqfp_p(__CR6_EQ, __a, __b);
#endif
@@ -16364,27 +16364,32 @@ vec_xl(signed long long __offset, unsigned char *__ptr) {
static inline __ATTRS_o_ai vector signed short vec_xl(signed long long __offset,
signed short *__ptr) {
- return *(unaligned_vec_sshort *)(__ptr + __offset);
+ signed char *__addr = (signed char *)__ptr + __offset;
+ return *(unaligned_vec_sshort *)__addr;
}
static inline __ATTRS_o_ai vector unsigned short
vec_xl(signed long long __offset, unsigned short *__ptr) {
- return *(unaligned_vec_ushort *)(__ptr + __offset);
+ signed char *__addr = (signed char *)__ptr + __offset;
+ return *(unaligned_vec_ushort *)__addr;
}
static inline __ATTRS_o_ai vector signed int vec_xl(signed long long __offset,
signed int *__ptr) {
- return *(unaligned_vec_sint *)(__ptr + __offset);
+ signed char *__addr = (signed char *)__ptr + __offset;
+ return *(unaligned_vec_sint *)__addr;
}
static inline __ATTRS_o_ai vector unsigned int vec_xl(signed long long __offset,
unsigned int *__ptr) {
- return *(unaligned_vec_uint *)(__ptr + __offset);
+ signed char *__addr = (signed char *)__ptr + __offset;
+ return *(unaligned_vec_uint *)__addr;
}
static inline __ATTRS_o_ai vector float vec_xl(signed long long __offset,
float *__ptr) {
- return *(unaligned_vec_float *)(__ptr + __offset);
+ signed char *__addr = (signed char *)__ptr + __offset;
+ return *(unaligned_vec_float *)__addr;
}
#ifdef __VSX__
@@ -16394,17 +16399,20 @@ typedef vector double unaligned_vec_double __attribute__((aligned(1)));
static inline __ATTRS_o_ai vector signed long long
vec_xl(signed long long __offset, signed long long *__ptr) {
- return *(unaligned_vec_sll *)(__ptr + __offset);
+ signed char *__addr = (signed char *)__ptr + __offset;
+ return *(unaligned_vec_sll *)__addr;
}
static inline __ATTRS_o_ai vector unsigned long long
vec_xl(signed long long __offset, unsigned long long *__ptr) {
- return *(unaligned_vec_ull *)(__ptr + __offset);
+ signed char *__addr = (signed char *)__ptr + __offset;
+ return *(unaligned_vec_ull *)__addr;
}
static inline __ATTRS_o_ai vector double vec_xl(signed long long __offset,
double *__ptr) {
- return *(unaligned_vec_double *)(__ptr + __offset);
+ signed char *__addr = (signed char *)__ptr + __offset;
+ return *(unaligned_vec_double *)__addr;
}
#endif
@@ -16414,12 +16422,14 @@ typedef vector unsigned __int128 unaligned_vec_ui128
__attribute__((aligned(1)));
static inline __ATTRS_o_ai vector signed __int128
vec_xl(signed long long __offset, signed __int128 *__ptr) {
- return *(unaligned_vec_si128 *)(__ptr + __offset);
+ signed char *__addr = (signed char *)__ptr + __offset;
+ return *(unaligned_vec_si128 *)__addr;
}
static inline __ATTRS_o_ai vector unsigned __int128
vec_xl(signed long long __offset, unsigned __int128 *__ptr) {
- return *(unaligned_vec_ui128 *)(__ptr + __offset);
+ signed char *__addr = (signed char *)__ptr + __offset;
+ return *(unaligned_vec_ui128 *)__addr;
}
#endif
@@ -16516,50 +16526,58 @@ static inline __ATTRS_o_ai void vec_xst(vector unsigned char __vec,
static inline __ATTRS_o_ai void vec_xst(vector signed short __vec,
signed long long __offset,
signed short *__ptr) {
- *(unaligned_vec_sshort *)(__ptr + __offset) = __vec;
+ signed char *__addr = (signed char *)__ptr + __offset;
+ *(unaligned_vec_sshort *)__addr = __vec;
}
static inline __ATTRS_o_ai void vec_xst(vector unsigned short __vec,
signed long long __offset,
unsigned short *__ptr) {
- *(unaligned_vec_ushort *)(__ptr + __offset) = __vec;
+ signed char *__addr = (signed char *)__ptr + __offset;
+ *(unaligned_vec_ushort *)__addr = __vec;
}
static inline __ATTRS_o_ai void vec_xst(vector signed int __vec,
signed long long __offset,
signed int *__ptr) {
- *(unaligned_vec_sint *)(__ptr + __offset) = __vec;
+ signed char *__addr = (signed char *)__ptr + __offset;
+ *(unaligned_vec_sint *)__addr = __vec;
}
static inline __ATTRS_o_ai void vec_xst(vector unsigned int __vec,
signed long long __offset,
unsigned int *__ptr) {
- *(unaligned_vec_uint *)(__ptr + __offset) = __vec;
+ signed char *__addr = (signed char *)__ptr + __offset;
+ *(unaligned_vec_uint *)__addr = __vec;
}
static inline __ATTRS_o_ai void vec_xst(vector float __vec,
signed long long __offset,
float *__ptr) {
- *(unaligned_vec_float *)(__ptr + __offset) = __vec;
+ signed char *__addr = (signed char *)__ptr + __offset;
+ *(unaligned_vec_float *)__addr = __vec;
}
#ifdef __VSX__
static inline __ATTRS_o_ai void vec_xst(vector signed long long __vec,
signed long long __offset,
signed long long *__ptr) {
- *(unaligned_vec_sll *)(__ptr + __offset) = __vec;
+ signed char *__addr = (signed char *)__ptr + __offset;
+ *(unaligned_vec_sll *)__addr = __vec;
}
static inline __ATTRS_o_ai void vec_xst(vector unsigned long long __vec,
signed long long __offset,
unsigned long long *__ptr) {
- *(unaligned_vec_ull *)(__ptr + __offset) = __vec;
+ signed char *__addr = (signed char *)__ptr + __offset;
+ *(unaligned_vec_ull *)__addr = __vec;
}
static inline __ATTRS_o_ai void vec_xst(vector double __vec,
signed long long __offset,
double *__ptr) {
- *(unaligned_vec_double *)(__ptr + __offset) = __vec;
+ signed char *__addr = (signed char *)__ptr + __offset;
+ *(unaligned_vec_double *)__addr = __vec;
}
#endif
@@ -16567,13 +16585,15 @@ static inline __ATTRS_o_ai void vec_xst(vector double __vec,
static inline __ATTRS_o_ai void vec_xst(vector signed __int128 __vec,
signed long long __offset,
signed __int128 *__ptr) {
- *(unaligned_vec_si128 *)(__ptr + __offset) = __vec;
+ signed char *__addr = (signed char *)__ptr + __offset;
+ *(unaligned_vec_si128 *)__addr = __vec;
}
static inline __ATTRS_o_ai void vec_xst(vector unsigned __int128 __vec,
signed long long __offset,
unsigned __int128 *__ptr) {
- *(unaligned_vec_ui128 *)(__ptr + __offset) = __vec;
+ signed char *__addr = (signed char *)__ptr + __offset;
+ *(unaligned_vec_ui128 *)__addr = __vec;
}
#endif
diff --git a/clang/lib/Headers/arm_acle.h b/clang/lib/Headers/arm_acle.h
index 0510e6fd809f..596ea03cff2f 100644
--- a/clang/lib/Headers/arm_acle.h
+++ b/clang/lib/Headers/arm_acle.h
@@ -90,9 +90,11 @@ __swp(uint32_t __x, volatile uint32_t *__p) {
#endif
/* 8.7 NOP */
+#if !defined(_MSC_VER) || !defined(__aarch64__)
static __inline__ void __attribute__((__always_inline__, __nodebug__)) __nop(void) {
__builtin_arm_nop();
}
+#endif
/* 9 DATA-PROCESSING INTRINSICS */
/* 9.2 Miscellaneous data-processing intrinsics */
@@ -139,6 +141,26 @@ __clzll(uint64_t __t) {
return __builtin_clzll(__t);
}
+/* CLS */
+static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__))
+__cls(uint32_t __t) {
+ return __builtin_arm_cls(__t);
+}
+
+static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__))
+__clsl(unsigned long __t) {
+#if __SIZEOF_LONG__ == 4
+ return __builtin_arm_cls(__t);
+#else
+ return __builtin_arm_cls64(__t);
+#endif
+}
+
+static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__))
+__clsll(uint64_t __t) {
+ return __builtin_arm_cls64(__t);
+}
+
/* REV */
static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__))
__rev(uint32_t __t) {
@@ -609,9 +631,13 @@ __jcvt(double __a) {
#define __arm_rsr(sysreg) __builtin_arm_rsr(sysreg)
#define __arm_rsr64(sysreg) __builtin_arm_rsr64(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_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
diff --git a/clang/lib/Headers/arm_cmse.h b/clang/lib/Headers/arm_cmse.h
new file mode 100644
index 000000000000..ecf50ecc5c8e
--- /dev/null
+++ b/clang/lib/Headers/arm_cmse.h
@@ -0,0 +1,217 @@
+//===---- arm_cmse.h - Arm CMSE 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 __ARM_CMSE_H
+#define __ARM_CMSE_H
+
+#if (__ARM_FEATURE_CMSE & 0x1)
+#include <stddef.h>
+#include <stdint.h>
+
+#define __ARM_CMSE_SECURE_MODE (__ARM_FEATURE_CMSE & 0x2)
+#define CMSE_MPU_READWRITE 1 /* checks if readwrite_ok field is set */
+#define CMSE_AU_NONSECURE 2 /* checks if permissions have secure field unset */
+#define CMSE_MPU_UNPRIV 4 /* sets T flag on TT insrtuction */
+#define CMSE_MPU_READ 8 /* checks if read_ok field is set */
+#define CMSE_MPU_NONSECURE 16 /* sets A flag, checks if secure field unset */
+#define CMSE_NONSECURE (CMSE_AU_NONSECURE | CMSE_MPU_NONSECURE)
+
+#define cmse_check_pointed_object(p, f) \
+ cmse_check_address_range((p), sizeof(*(p)), (f))
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+typedef union {
+ struct cmse_address_info {
+#ifdef __ARM_BIG_ENDIAN
+ /* __ARM_BIG_ENDIAN */
+#if (__ARM_CMSE_SECURE_MODE)
+ unsigned idau_region : 8;
+ unsigned idau_region_valid : 1;
+ unsigned secure : 1;
+ unsigned nonsecure_readwrite_ok : 1;
+ unsigned nonsecure_read_ok : 1;
+#else
+ unsigned : 12;
+#endif
+ unsigned readwrite_ok : 1;
+ unsigned read_ok : 1;
+#if (__ARM_CMSE_SECURE_MODE)
+ unsigned sau_region_valid : 1;
+#else
+ unsigned : 1;
+#endif
+ unsigned mpu_region_valid : 1;
+#if (__ARM_CMSE_SECURE_MODE)
+ unsigned sau_region : 8;
+#else
+ unsigned : 8;
+#endif
+ unsigned mpu_region : 8;
+
+#else /* __ARM_LITTLE_ENDIAN */
+ unsigned mpu_region : 8;
+#if (__ARM_CMSE_SECURE_MODE)
+ unsigned sau_region : 8;
+#else
+ unsigned : 8;
+#endif
+ unsigned mpu_region_valid : 1;
+#if (__ARM_CMSE_SECURE_MODE)
+ unsigned sau_region_valid : 1;
+#else
+ unsigned : 1;
+#endif
+ unsigned read_ok : 1;
+ unsigned readwrite_ok : 1;
+#if (__ARM_CMSE_SECURE_MODE)
+ unsigned nonsecure_read_ok : 1;
+ unsigned nonsecure_readwrite_ok : 1;
+ unsigned secure : 1;
+ unsigned idau_region_valid : 1;
+ unsigned idau_region : 8;
+#else
+ unsigned : 12;
+#endif
+#endif /*__ARM_LITTLE_ENDIAN */
+ } flags;
+ unsigned value;
+} cmse_address_info_t;
+
+static cmse_address_info_t __attribute__((__always_inline__, __nodebug__))
+cmse_TT(void *__p) {
+ cmse_address_info_t __u;
+ __u.value = __builtin_arm_cmse_TT(__p);
+ return __u;
+}
+static cmse_address_info_t __attribute__((__always_inline__, __nodebug__))
+cmse_TTT(void *__p) {
+ cmse_address_info_t __u;
+ __u.value = __builtin_arm_cmse_TTT(__p);
+ return __u;
+}
+
+#if __ARM_CMSE_SECURE_MODE
+static cmse_address_info_t __attribute__((__always_inline__, __nodebug__))
+cmse_TTA(void *__p) {
+ cmse_address_info_t __u;
+ __u.value = __builtin_arm_cmse_TTA(__p);
+ return __u;
+}
+static cmse_address_info_t __attribute__((__always_inline__, __nodebug__))
+cmse_TTAT(void *__p) {
+ cmse_address_info_t __u;
+ __u.value = __builtin_arm_cmse_TTAT(__p);
+ return __u;
+}
+#endif
+
+#define cmse_TT_fptr(p) cmse_TT(__builtin_bit_cast(void *, (p)))
+#define cmse_TTT_fptr(p) cmse_TTT(__builtin_bit_cast(void *, (p)))
+
+#if __ARM_CMSE_SECURE_MODE
+#define cmse_TTA_fptr(p) cmse_TTA(__builtin_bit_cast(void *, (p)))
+#define cmse_TTAT_fptr(p) cmse_TTAT(__builtin_bit_cast(void *, (p)))
+#endif
+
+static void *__attribute__((__always_inline__))
+cmse_check_address_range(void *__pb, size_t __s, int __flags) {
+ uintptr_t __begin = (uintptr_t)__pb;
+ uintptr_t __end = __begin + __s - 1;
+
+ if (__end < __begin)
+ return NULL; /* wrap around check */
+
+ /* Check whether the range crosses a 32-bytes aligned address */
+ const int __single_check = (__begin ^ __end) < 0x20u;
+
+ /* execute the right variant of the TT instructions */
+ void *__pe = (void *)__end;
+ cmse_address_info_t __permb, __perme;
+ switch (__flags & (CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE)) {
+ case 0:
+ __permb = cmse_TT(__pb);
+ __perme = __single_check ? __permb : cmse_TT(__pe);
+ break;
+ case CMSE_MPU_UNPRIV:
+ __permb = cmse_TTT(__pb);
+ __perme = __single_check ? __permb : cmse_TTT(__pe);
+ break;
+#if __ARM_CMSE_SECURE_MODE
+ case CMSE_MPU_NONSECURE:
+ __permb = cmse_TTA(__pb);
+ __perme = __single_check ? __permb : cmse_TTA(__pe);
+ break;
+ case CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE:
+ __permb = cmse_TTAT(__pb);
+ __perme = __single_check ? __permb : cmse_TTAT(__pe);
+ break;
+#endif
+ /* if CMSE_NONSECURE is specified w/o __ARM_CMSE_SECURE_MODE */
+ default:
+ return NULL;
+ }
+
+ /* check that the range does not cross MPU, SAU, or IDAU region boundaries */
+ if (__permb.value != __perme.value)
+ return NULL;
+#if !(__ARM_CMSE_SECURE_MODE)
+ /* CMSE_AU_NONSECURE is only supported when __ARM_FEATURE_CMSE & 0x2 */
+ if (__flags & CMSE_AU_NONSECURE)
+ return NULL;
+#endif
+
+ /* check the permission on the range */
+ switch (__flags & ~(CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE)) {
+#if (__ARM_CMSE_SECURE_MODE)
+ case CMSE_MPU_READ | CMSE_MPU_READWRITE | CMSE_AU_NONSECURE:
+ case CMSE_MPU_READWRITE | CMSE_AU_NONSECURE:
+ return __permb.flags.nonsecure_readwrite_ok ? __pb : NULL;
+
+ case CMSE_MPU_READ | CMSE_AU_NONSECURE:
+ return __permb.flags.nonsecure_read_ok ? __pb : NULL;
+
+ case CMSE_AU_NONSECURE:
+ return __permb.flags.secure ? NULL : __pb;
+#endif
+ case CMSE_MPU_READ | CMSE_MPU_READWRITE:
+ case CMSE_MPU_READWRITE:
+ return __permb.flags.readwrite_ok ? __pb : NULL;
+
+ case CMSE_MPU_READ:
+ return __permb.flags.read_ok ? __pb : NULL;
+
+ default:
+ return NULL;
+ }
+}
+
+#if __ARM_CMSE_SECURE_MODE
+static int __attribute__((__always_inline__, __nodebug__))
+cmse_nonsecure_caller(void) {
+ return !((uintptr_t)__builtin_return_address(0) & 1);
+}
+
+#define cmse_nsfptr_create(p) \
+ __builtin_bit_cast(__typeof__(p), \
+ (__builtin_bit_cast(uintptr_t, p) & ~(uintptr_t)1))
+
+#define cmse_is_nsfptr(p) ((__builtin_bit_cast(uintptr_t, p) & 1) == 0)
+
+#endif /* __ARM_CMSE_SECURE_MODE */
+
+void __attribute__((__noreturn__)) cmse_abort(void);
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* (__ARM_FEATURE_CMSE & 0x1) */
+
+#endif /* __ARM_CMSE_H */
diff --git a/clang/lib/Headers/avx512bwintrin.h b/clang/lib/Headers/avx512bwintrin.h
index cb2e07619cb7..376558407683 100644
--- a/clang/lib/Headers/avx512bwintrin.h
+++ b/clang/lib/Headers/avx512bwintrin.h
@@ -1731,13 +1731,13 @@ _mm512_loadu_epi16 (void const *__P)
struct __loadu_epi16 {
__m512i_u __v;
} __attribute__((__packed__, __may_alias__));
- return ((struct __loadu_epi16*)__P)->__v;
+ return ((const struct __loadu_epi16*)__P)->__v;
}
static __inline__ __m512i __DEFAULT_FN_ATTRS512
_mm512_mask_loadu_epi16 (__m512i __W, __mmask32 __U, void const *__P)
{
- return (__m512i) __builtin_ia32_loaddquhi512_mask ((__v32hi *) __P,
+ return (__m512i) __builtin_ia32_loaddquhi512_mask ((const __v32hi *) __P,
(__v32hi) __W,
(__mmask32) __U);
}
@@ -1745,7 +1745,7 @@ _mm512_mask_loadu_epi16 (__m512i __W, __mmask32 __U, void const *__P)
static __inline__ __m512i __DEFAULT_FN_ATTRS512
_mm512_maskz_loadu_epi16 (__mmask32 __U, void const *__P)
{
- return (__m512i) __builtin_ia32_loaddquhi512_mask ((__v32hi *) __P,
+ return (__m512i) __builtin_ia32_loaddquhi512_mask ((const __v32hi *) __P,
(__v32hi)
_mm512_setzero_si512 (),
(__mmask32) __U);
@@ -1757,13 +1757,13 @@ _mm512_loadu_epi8 (void const *__P)
struct __loadu_epi8 {
__m512i_u __v;
} __attribute__((__packed__, __may_alias__));
- return ((struct __loadu_epi8*)__P)->__v;
+ return ((const struct __loadu_epi8*)__P)->__v;
}
static __inline__ __m512i __DEFAULT_FN_ATTRS512
_mm512_mask_loadu_epi8 (__m512i __W, __mmask64 __U, void const *__P)
{
- return (__m512i) __builtin_ia32_loaddquqi512_mask ((__v64qi *) __P,
+ return (__m512i) __builtin_ia32_loaddquqi512_mask ((const __v64qi *) __P,
(__v64qi) __W,
(__mmask64) __U);
}
@@ -1771,7 +1771,7 @@ _mm512_mask_loadu_epi8 (__m512i __W, __mmask64 __U, void const *__P)
static __inline__ __m512i __DEFAULT_FN_ATTRS512
_mm512_maskz_loadu_epi8 (__mmask64 __U, void const *__P)
{
- return (__m512i) __builtin_ia32_loaddquqi512_mask ((__v64qi *) __P,
+ return (__m512i) __builtin_ia32_loaddquqi512_mask ((const __v64qi *) __P,
(__v64qi)
_mm512_setzero_si512 (),
(__mmask64) __U);
diff --git a/clang/lib/Headers/avx512fintrin.h b/clang/lib/Headers/avx512fintrin.h
index 698e477fe5f3..7465da379bdd 100644
--- a/clang/lib/Headers/avx512fintrin.h
+++ b/clang/lib/Headers/avx512fintrin.h
@@ -4305,7 +4305,7 @@ _mm512_loadu_si512 (void const *__P)
struct __loadu_si512 {
__m512i_u __v;
} __attribute__((__packed__, __may_alias__));
- return ((struct __loadu_si512*)__P)->__v;
+ return ((const struct __loadu_si512*)__P)->__v;
}
static __inline __m512i __DEFAULT_FN_ATTRS512
@@ -4314,7 +4314,7 @@ _mm512_loadu_epi32 (void const *__P)
struct __loadu_epi32 {
__m512i_u __v;
} __attribute__((__packed__, __may_alias__));
- return ((struct __loadu_epi32*)__P)->__v;
+ return ((const struct __loadu_epi32*)__P)->__v;
}
static __inline __m512i __DEFAULT_FN_ATTRS512
@@ -4341,7 +4341,7 @@ _mm512_loadu_epi64 (void const *__P)
struct __loadu_epi64 {
__m512i_u __v;
} __attribute__((__packed__, __may_alias__));
- return ((struct __loadu_epi64*)__P)->__v;
+ return ((const struct __loadu_epi64*)__P)->__v;
}
static __inline __m512i __DEFAULT_FN_ATTRS512
@@ -4401,7 +4401,7 @@ _mm512_loadu_pd(void const *__p)
struct __loadu_pd {
__m512d_u __v;
} __attribute__((__packed__, __may_alias__));
- return ((struct __loadu_pd*)__p)->__v;
+ return ((const struct __loadu_pd*)__p)->__v;
}
static __inline __m512 __DEFAULT_FN_ATTRS512
@@ -4410,13 +4410,13 @@ _mm512_loadu_ps(void const *__p)
struct __loadu_ps {
__m512_u __v;
} __attribute__((__packed__, __may_alias__));
- return ((struct __loadu_ps*)__p)->__v;
+ return ((const struct __loadu_ps*)__p)->__v;
}
static __inline __m512 __DEFAULT_FN_ATTRS512
_mm512_load_ps(void const *__p)
{
- return *(__m512*)__p;
+ return *(const __m512*)__p;
}
static __inline __m512 __DEFAULT_FN_ATTRS512
@@ -4439,7 +4439,7 @@ _mm512_maskz_load_ps(__mmask16 __U, void const *__P)
static __inline __m512d __DEFAULT_FN_ATTRS512
_mm512_load_pd(void const *__p)
{
- return *(__m512d*)__p;
+ return *(const __m512d*)__p;
}
static __inline __m512d __DEFAULT_FN_ATTRS512
@@ -4462,19 +4462,19 @@ _mm512_maskz_load_pd(__mmask8 __U, void const *__P)
static __inline __m512i __DEFAULT_FN_ATTRS512
_mm512_load_si512 (void const *__P)
{
- return *(__m512i *) __P;
+ return *(const __m512i *) __P;
}
static __inline __m512i __DEFAULT_FN_ATTRS512
_mm512_load_epi32 (void const *__P)
{
- return *(__m512i *) __P;
+ return *(const __m512i *) __P;
}
static __inline __m512i __DEFAULT_FN_ATTRS512
_mm512_load_epi64 (void const *__P)
{
- return *(__m512i *) __P;
+ return *(const __m512i *) __P;
}
/* SIMD store ops */
@@ -8724,13 +8724,13 @@ _mm_mask_load_ss (__m128 __W, __mmask8 __U, const float* __A)
(__v4sf)_mm_setzero_ps(),
0, 4, 4, 4);
- return (__m128) __builtin_ia32_loadss128_mask ((__v4sf *) __A, src, __U & 1);
+ return (__m128) __builtin_ia32_loadss128_mask ((const __v4sf *) __A, src, __U & 1);
}
static __inline__ __m128 __DEFAULT_FN_ATTRS128
_mm_maskz_load_ss (__mmask8 __U, const float* __A)
{
- return (__m128)__builtin_ia32_loadss128_mask ((__v4sf *) __A,
+ return (__m128)__builtin_ia32_loadss128_mask ((const __v4sf *) __A,
(__v4sf) _mm_setzero_ps(),
__U & 1);
}
@@ -8742,13 +8742,13 @@ _mm_mask_load_sd (__m128d __W, __mmask8 __U, const double* __A)
(__v2df)_mm_setzero_pd(),
0, 2);
- return (__m128d) __builtin_ia32_loadsd128_mask ((__v2df *) __A, src, __U & 1);
+ return (__m128d) __builtin_ia32_loadsd128_mask ((const __v2df *) __A, src, __U & 1);
}
static __inline__ __m128d __DEFAULT_FN_ATTRS128
_mm_maskz_load_sd (__mmask8 __U, const double* __A)
{
- return (__m128d) __builtin_ia32_loadsd128_mask ((__v2df *) __A,
+ return (__m128d) __builtin_ia32_loadsd128_mask ((const __v2df *) __A,
(__v2df) _mm_setzero_pd(),
__U & 1);
}
diff --git a/clang/lib/Headers/avx512vlbwintrin.h b/clang/lib/Headers/avx512vlbwintrin.h
index ead09466bc2c..cd9f2400daa0 100644
--- a/clang/lib/Headers/avx512vlbwintrin.h
+++ b/clang/lib/Headers/avx512vlbwintrin.h
@@ -2289,13 +2289,13 @@ _mm_loadu_epi16 (void const *__P)
struct __loadu_epi16 {
__m128i_u __v;
} __attribute__((__packed__, __may_alias__));
- return ((struct __loadu_epi16*)__P)->__v;
+ return ((const struct __loadu_epi16*)__P)->__v;
}
static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_mask_loadu_epi16 (__m128i __W, __mmask8 __U, void const *__P)
{
- return (__m128i) __builtin_ia32_loaddquhi128_mask ((__v8hi *) __P,
+ return (__m128i) __builtin_ia32_loaddquhi128_mask ((const __v8hi *) __P,
(__v8hi) __W,
(__mmask8) __U);
}
@@ -2303,7 +2303,7 @@ _mm_mask_loadu_epi16 (__m128i __W, __mmask8 __U, void const *__P)
static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_maskz_loadu_epi16 (__mmask8 __U, void const *__P)
{
- return (__m128i) __builtin_ia32_loaddquhi128_mask ((__v8hi *) __P,
+ return (__m128i) __builtin_ia32_loaddquhi128_mask ((const __v8hi *) __P,
(__v8hi)
_mm_setzero_si128 (),
(__mmask8) __U);
@@ -2315,13 +2315,13 @@ _mm256_loadu_epi16 (void const *__P)
struct __loadu_epi16 {
__m256i_u __v;
} __attribute__((__packed__, __may_alias__));
- return ((struct __loadu_epi16*)__P)->__v;
+ return ((const struct __loadu_epi16*)__P)->__v;
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_mask_loadu_epi16 (__m256i __W, __mmask16 __U, void const *__P)
{
- return (__m256i) __builtin_ia32_loaddquhi256_mask ((__v16hi *) __P,
+ return (__m256i) __builtin_ia32_loaddquhi256_mask ((const __v16hi *) __P,
(__v16hi) __W,
(__mmask16) __U);
}
@@ -2329,7 +2329,7 @@ _mm256_mask_loadu_epi16 (__m256i __W, __mmask16 __U, void const *__P)
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_maskz_loadu_epi16 (__mmask16 __U, void const *__P)
{
- return (__m256i) __builtin_ia32_loaddquhi256_mask ((__v16hi *) __P,
+ return (__m256i) __builtin_ia32_loaddquhi256_mask ((const __v16hi *) __P,
(__v16hi)
_mm256_setzero_si256 (),
(__mmask16) __U);
@@ -2341,13 +2341,13 @@ _mm_loadu_epi8 (void const *__P)
struct __loadu_epi8 {
__m128i_u __v;
} __attribute__((__packed__, __may_alias__));
- return ((struct __loadu_epi8*)__P)->__v;
+ return ((const struct __loadu_epi8*)__P)->__v;
}
static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_mask_loadu_epi8 (__m128i __W, __mmask16 __U, void const *__P)
{
- return (__m128i) __builtin_ia32_loaddquqi128_mask ((__v16qi *) __P,
+ return (__m128i) __builtin_ia32_loaddquqi128_mask ((const __v16qi *) __P,
(__v16qi) __W,
(__mmask16) __U);
}
@@ -2355,7 +2355,7 @@ _mm_mask_loadu_epi8 (__m128i __W, __mmask16 __U, void const *__P)
static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_maskz_loadu_epi8 (__mmask16 __U, void const *__P)
{
- return (__m128i) __builtin_ia32_loaddquqi128_mask ((__v16qi *) __P,
+ return (__m128i) __builtin_ia32_loaddquqi128_mask ((const __v16qi *) __P,
(__v16qi)
_mm_setzero_si128 (),
(__mmask16) __U);
@@ -2367,13 +2367,13 @@ _mm256_loadu_epi8 (void const *__P)
struct __loadu_epi8 {
__m256i_u __v;
} __attribute__((__packed__, __may_alias__));
- return ((struct __loadu_epi8*)__P)->__v;
+ return ((const struct __loadu_epi8*)__P)->__v;
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_mask_loadu_epi8 (__m256i __W, __mmask32 __U, void const *__P)
{
- return (__m256i) __builtin_ia32_loaddquqi256_mask ((__v32qi *) __P,
+ return (__m256i) __builtin_ia32_loaddquqi256_mask ((const __v32qi *) __P,
(__v32qi) __W,
(__mmask32) __U);
}
@@ -2381,7 +2381,7 @@ _mm256_mask_loadu_epi8 (__m256i __W, __mmask32 __U, void const *__P)
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_maskz_loadu_epi8 (__mmask32 __U, void const *__P)
{
- return (__m256i) __builtin_ia32_loaddquqi256_mask ((__v32qi *) __P,
+ return (__m256i) __builtin_ia32_loaddquqi256_mask ((const __v32qi *) __P,
(__v32qi)
_mm256_setzero_si256 (),
(__mmask32) __U);
diff --git a/clang/lib/Headers/avx512vlintrin.h b/clang/lib/Headers/avx512vlintrin.h
index 9494fc8a6e59..9d1d791bb248 100644
--- a/clang/lib/Headers/avx512vlintrin.h
+++ b/clang/lib/Headers/avx512vlintrin.h
@@ -2505,7 +2505,7 @@ _mm256_maskz_expand_epi64 (__mmask8 __U, __m256i __A) {
static __inline__ __m128d __DEFAULT_FN_ATTRS128
_mm_mask_expandloadu_pd (__m128d __W, __mmask8 __U, void const *__P) {
- return (__m128d) __builtin_ia32_expandloaddf128_mask ((__v2df *) __P,
+ return (__m128d) __builtin_ia32_expandloaddf128_mask ((const __v2df *) __P,
(__v2df) __W,
(__mmask8)
__U);
@@ -2513,7 +2513,7 @@ _mm_mask_expandloadu_pd (__m128d __W, __mmask8 __U, void const *__P) {
static __inline__ __m128d __DEFAULT_FN_ATTRS128
_mm_maskz_expandloadu_pd (__mmask8 __U, void const *__P) {
- return (__m128d) __builtin_ia32_expandloaddf128_mask ((__v2df *) __P,
+ return (__m128d) __builtin_ia32_expandloaddf128_mask ((const __v2df *) __P,
(__v2df)
_mm_setzero_pd (),
(__mmask8)
@@ -2522,7 +2522,7 @@ _mm_maskz_expandloadu_pd (__mmask8 __U, void const *__P) {
static __inline__ __m256d __DEFAULT_FN_ATTRS256
_mm256_mask_expandloadu_pd (__m256d __W, __mmask8 __U, void const *__P) {
- return (__m256d) __builtin_ia32_expandloaddf256_mask ((__v4df *) __P,
+ return (__m256d) __builtin_ia32_expandloaddf256_mask ((const __v4df *) __P,
(__v4df) __W,
(__mmask8)
__U);
@@ -2530,7 +2530,7 @@ _mm256_mask_expandloadu_pd (__m256d __W, __mmask8 __U, void const *__P) {
static __inline__ __m256d __DEFAULT_FN_ATTRS256
_mm256_maskz_expandloadu_pd (__mmask8 __U, void const *__P) {
- return (__m256d) __builtin_ia32_expandloaddf256_mask ((__v4df *) __P,
+ return (__m256d) __builtin_ia32_expandloaddf256_mask ((const __v4df *) __P,
(__v4df)
_mm256_setzero_pd (),
(__mmask8)
@@ -2539,7 +2539,7 @@ _mm256_maskz_expandloadu_pd (__mmask8 __U, void const *__P) {
static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_mask_expandloadu_epi64 (__m128i __W, __mmask8 __U, void const *__P) {
- return (__m128i) __builtin_ia32_expandloaddi128_mask ((__v2di *) __P,
+ return (__m128i) __builtin_ia32_expandloaddi128_mask ((const __v2di *) __P,
(__v2di) __W,
(__mmask8)
__U);
@@ -2547,7 +2547,7 @@ _mm_mask_expandloadu_epi64 (__m128i __W, __mmask8 __U, void const *__P) {
static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_maskz_expandloadu_epi64 (__mmask8 __U, void const *__P) {
- return (__m128i) __builtin_ia32_expandloaddi128_mask ((__v2di *) __P,
+ return (__m128i) __builtin_ia32_expandloaddi128_mask ((const __v2di *) __P,
(__v2di)
_mm_setzero_si128 (),
(__mmask8)
@@ -2557,7 +2557,7 @@ _mm_maskz_expandloadu_epi64 (__mmask8 __U, void const *__P) {
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_mask_expandloadu_epi64 (__m256i __W, __mmask8 __U,
void const *__P) {
- return (__m256i) __builtin_ia32_expandloaddi256_mask ((__v4di *) __P,
+ return (__m256i) __builtin_ia32_expandloaddi256_mask ((const __v4di *) __P,
(__v4di) __W,
(__mmask8)
__U);
@@ -2565,7 +2565,7 @@ _mm256_mask_expandloadu_epi64 (__m256i __W, __mmask8 __U,
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_maskz_expandloadu_epi64 (__mmask8 __U, void const *__P) {
- return (__m256i) __builtin_ia32_expandloaddi256_mask ((__v4di *) __P,
+ return (__m256i) __builtin_ia32_expandloaddi256_mask ((const __v4di *) __P,
(__v4di)
_mm256_setzero_si256 (),
(__mmask8)
@@ -2574,14 +2574,14 @@ _mm256_maskz_expandloadu_epi64 (__mmask8 __U, void const *__P) {
static __inline__ __m128 __DEFAULT_FN_ATTRS128
_mm_mask_expandloadu_ps (__m128 __W, __mmask8 __U, void const *__P) {
- return (__m128) __builtin_ia32_expandloadsf128_mask ((__v4sf *) __P,
+ return (__m128) __builtin_ia32_expandloadsf128_mask ((const __v4sf *) __P,
(__v4sf) __W,
(__mmask8) __U);
}
static __inline__ __m128 __DEFAULT_FN_ATTRS128
_mm_maskz_expandloadu_ps (__mmask8 __U, void const *__P) {
- return (__m128) __builtin_ia32_expandloadsf128_mask ((__v4sf *) __P,
+ return (__m128) __builtin_ia32_expandloadsf128_mask ((const __v4sf *) __P,
(__v4sf)
_mm_setzero_ps (),
(__mmask8)
@@ -2590,14 +2590,14 @@ _mm_maskz_expandloadu_ps (__mmask8 __U, void const *__P) {
static __inline__ __m256 __DEFAULT_FN_ATTRS256
_mm256_mask_expandloadu_ps (__m256 __W, __mmask8 __U, void const *__P) {
- return (__m256) __builtin_ia32_expandloadsf256_mask ((__v8sf *) __P,
+ return (__m256) __builtin_ia32_expandloadsf256_mask ((const __v8sf *) __P,
(__v8sf) __W,
(__mmask8) __U);
}
static __inline__ __m256 __DEFAULT_FN_ATTRS256
_mm256_maskz_expandloadu_ps (__mmask8 __U, void const *__P) {
- return (__m256) __builtin_ia32_expandloadsf256_mask ((__v8sf *) __P,
+ return (__m256) __builtin_ia32_expandloadsf256_mask ((const __v8sf *) __P,
(__v8sf)
_mm256_setzero_ps (),
(__mmask8)
@@ -2606,7 +2606,7 @@ _mm256_maskz_expandloadu_ps (__mmask8 __U, void const *__P) {
static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_mask_expandloadu_epi32 (__m128i __W, __mmask8 __U, void const *__P) {
- return (__m128i) __builtin_ia32_expandloadsi128_mask ((__v4si *) __P,
+ return (__m128i) __builtin_ia32_expandloadsi128_mask ((const __v4si *) __P,
(__v4si) __W,
(__mmask8)
__U);
@@ -2614,7 +2614,7 @@ _mm_mask_expandloadu_epi32 (__m128i __W, __mmask8 __U, void const *__P) {
static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_maskz_expandloadu_epi32 (__mmask8 __U, void const *__P) {
- return (__m128i) __builtin_ia32_expandloadsi128_mask ((__v4si *) __P,
+ return (__m128i) __builtin_ia32_expandloadsi128_mask ((const __v4si *) __P,
(__v4si)
_mm_setzero_si128 (),
(__mmask8) __U);
@@ -2623,7 +2623,7 @@ _mm_maskz_expandloadu_epi32 (__mmask8 __U, void const *__P) {
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_mask_expandloadu_epi32 (__m256i __W, __mmask8 __U,
void const *__P) {
- return (__m256i) __builtin_ia32_expandloadsi256_mask ((__v8si *) __P,
+ return (__m256i) __builtin_ia32_expandloadsi256_mask ((const __v8si *) __P,
(__v8si) __W,
(__mmask8)
__U);
@@ -2631,7 +2631,7 @@ _mm256_mask_expandloadu_epi32 (__m256i __W, __mmask8 __U,
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_maskz_expandloadu_epi32 (__mmask8 __U, void const *__P) {
- return (__m256i) __builtin_ia32_expandloadsi256_mask ((__v8si *) __P,
+ return (__m256i) __builtin_ia32_expandloadsi256_mask ((const __v8si *) __P,
(__v8si)
_mm256_setzero_si256 (),
(__mmask8)
@@ -5073,13 +5073,13 @@ _mm256_maskz_mov_epi32 (__mmask8 __U, __m256i __A)
static __inline __m128i __DEFAULT_FN_ATTRS128
_mm_load_epi32 (void const *__P)
{
- return *(__m128i *) __P;
+ return *(const __m128i *) __P;
}
static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_mask_load_epi32 (__m128i __W, __mmask8 __U, void const *__P)
{
- return (__m128i) __builtin_ia32_movdqa32load128_mask ((__v4si *) __P,
+ return (__m128i) __builtin_ia32_movdqa32load128_mask ((const __v4si *) __P,
(__v4si) __W,
(__mmask8)
__U);
@@ -5088,7 +5088,7 @@ _mm_mask_load_epi32 (__m128i __W, __mmask8 __U, void const *__P)
static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_maskz_load_epi32 (__mmask8 __U, void const *__P)
{
- return (__m128i) __builtin_ia32_movdqa32load128_mask ((__v4si *) __P,
+ return (__m128i) __builtin_ia32_movdqa32load128_mask ((const __v4si *) __P,
(__v4si)
_mm_setzero_si128 (),
(__mmask8)
@@ -5098,13 +5098,13 @@ _mm_maskz_load_epi32 (__mmask8 __U, void const *__P)
static __inline __m256i __DEFAULT_FN_ATTRS256
_mm256_load_epi32 (void const *__P)
{
- return *(__m256i *) __P;
+ return *(const __m256i *) __P;
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_mask_load_epi32 (__m256i __W, __mmask8 __U, void const *__P)
{
- return (__m256i) __builtin_ia32_movdqa32load256_mask ((__v8si *) __P,
+ return (__m256i) __builtin_ia32_movdqa32load256_mask ((const __v8si *) __P,
(__v8si) __W,
(__mmask8)
__U);
@@ -5113,7 +5113,7 @@ _mm256_mask_load_epi32 (__m256i __W, __mmask8 __U, void const *__P)
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_maskz_load_epi32 (__mmask8 __U, void const *__P)
{
- return (__m256i) __builtin_ia32_movdqa32load256_mask ((__v8si *) __P,
+ return (__m256i) __builtin_ia32_movdqa32load256_mask ((const __v8si *) __P,
(__v8si)
_mm256_setzero_si256 (),
(__mmask8)
@@ -5183,13 +5183,13 @@ _mm256_maskz_mov_epi64 (__mmask8 __U, __m256i __A)
static __inline __m128i __DEFAULT_FN_ATTRS128
_mm_load_epi64 (void const *__P)
{
- return *(__m128i *) __P;
+ return *(const __m128i *) __P;
}
static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_mask_load_epi64 (__m128i __W, __mmask8 __U, void const *__P)
{
- return (__m128i) __builtin_ia32_movdqa64load128_mask ((__v2di *) __P,
+ return (__m128i) __builtin_ia32_movdqa64load128_mask ((const __v2di *) __P,
(__v2di) __W,
(__mmask8)
__U);
@@ -5198,7 +5198,7 @@ _mm_mask_load_epi64 (__m128i __W, __mmask8 __U, void const *__P)
static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_maskz_load_epi64 (__mmask8 __U, void const *__P)
{
- return (__m128i) __builtin_ia32_movdqa64load128_mask ((__v2di *) __P,
+ return (__m128i) __builtin_ia32_movdqa64load128_mask ((const __v2di *) __P,
(__v2di)
_mm_setzero_si128 (),
(__mmask8)
@@ -5208,13 +5208,13 @@ _mm_maskz_load_epi64 (__mmask8 __U, void const *__P)
static __inline __m256i __DEFAULT_FN_ATTRS256
_mm256_load_epi64 (void const *__P)
{
- return *(__m256i *) __P;
+ return *(const __m256i *) __P;
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_mask_load_epi64 (__m256i __W, __mmask8 __U, void const *__P)
{
- return (__m256i) __builtin_ia32_movdqa64load256_mask ((__v4di *) __P,
+ return (__m256i) __builtin_ia32_movdqa64load256_mask ((const __v4di *) __P,
(__v4di) __W,
(__mmask8)
__U);
@@ -5223,7 +5223,7 @@ _mm256_mask_load_epi64 (__m256i __W, __mmask8 __U, void const *__P)
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_maskz_load_epi64 (__mmask8 __U, void const *__P)
{
- return (__m256i) __builtin_ia32_movdqa64load256_mask ((__v4di *) __P,
+ return (__m256i) __builtin_ia32_movdqa64load256_mask ((const __v4di *) __P,
(__v4di)
_mm256_setzero_si256 (),
(__mmask8)
@@ -5430,7 +5430,7 @@ _mm256_maskz_set1_epi64 (__mmask8 __M, long long __A)
static __inline__ __m128d __DEFAULT_FN_ATTRS128
_mm_mask_load_pd (__m128d __W, __mmask8 __U, void const *__P)
{
- return (__m128d) __builtin_ia32_loadapd128_mask ((__v2df *) __P,
+ return (__m128d) __builtin_ia32_loadapd128_mask ((const __v2df *) __P,
(__v2df) __W,
(__mmask8) __U);
}
@@ -5438,7 +5438,7 @@ _mm_mask_load_pd (__m128d __W, __mmask8 __U, void const *__P)
static __inline__ __m128d __DEFAULT_FN_ATTRS128
_mm_maskz_load_pd (__mmask8 __U, void const *__P)
{
- return (__m128d) __builtin_ia32_loadapd128_mask ((__v2df *) __P,
+ return (__m128d) __builtin_ia32_loadapd128_mask ((const __v2df *) __P,
(__v2df)
_mm_setzero_pd (),
(__mmask8) __U);
@@ -5447,7 +5447,7 @@ _mm_maskz_load_pd (__mmask8 __U, void const *__P)
static __inline__ __m256d __DEFAULT_FN_ATTRS256
_mm256_mask_load_pd (__m256d __W, __mmask8 __U, void const *__P)
{
- return (__m256d) __builtin_ia32_loadapd256_mask ((__v4df *) __P,
+ return (__m256d) __builtin_ia32_loadapd256_mask ((const __v4df *) __P,
(__v4df) __W,
(__mmask8) __U);
}
@@ -5455,7 +5455,7 @@ _mm256_mask_load_pd (__m256d __W, __mmask8 __U, void const *__P)
static __inline__ __m256d __DEFAULT_FN_ATTRS256
_mm256_maskz_load_pd (__mmask8 __U, void const *__P)
{
- return (__m256d) __builtin_ia32_loadapd256_mask ((__v4df *) __P,
+ return (__m256d) __builtin_ia32_loadapd256_mask ((const __v4df *) __P,
(__v4df)
_mm256_setzero_pd (),
(__mmask8) __U);
@@ -5464,7 +5464,7 @@ _mm256_maskz_load_pd (__mmask8 __U, void const *__P)
static __inline__ __m128 __DEFAULT_FN_ATTRS128
_mm_mask_load_ps (__m128 __W, __mmask8 __U, void const *__P)
{
- return (__m128) __builtin_ia32_loadaps128_mask ((__v4sf *) __P,
+ return (__m128) __builtin_ia32_loadaps128_mask ((const __v4sf *) __P,
(__v4sf) __W,
(__mmask8) __U);
}
@@ -5472,7 +5472,7 @@ _mm_mask_load_ps (__m128 __W, __mmask8 __U, void const *__P)
static __inline__ __m128 __DEFAULT_FN_ATTRS128
_mm_maskz_load_ps (__mmask8 __U, void const *__P)
{
- return (__m128) __builtin_ia32_loadaps128_mask ((__v4sf *) __P,
+ return (__m128) __builtin_ia32_loadaps128_mask ((const __v4sf *) __P,
(__v4sf)
_mm_setzero_ps (),
(__mmask8) __U);
@@ -5481,7 +5481,7 @@ _mm_maskz_load_ps (__mmask8 __U, void const *__P)
static __inline__ __m256 __DEFAULT_FN_ATTRS256
_mm256_mask_load_ps (__m256 __W, __mmask8 __U, void const *__P)
{
- return (__m256) __builtin_ia32_loadaps256_mask ((__v8sf *) __P,
+ return (__m256) __builtin_ia32_loadaps256_mask ((const __v8sf *) __P,
(__v8sf) __W,
(__mmask8) __U);
}
@@ -5489,7 +5489,7 @@ _mm256_mask_load_ps (__m256 __W, __mmask8 __U, void const *__P)
static __inline__ __m256 __DEFAULT_FN_ATTRS256
_mm256_maskz_load_ps (__mmask8 __U, void const *__P)
{
- return (__m256) __builtin_ia32_loadaps256_mask ((__v8sf *) __P,
+ return (__m256) __builtin_ia32_loadaps256_mask ((const __v8sf *) __P,
(__v8sf)
_mm256_setzero_ps (),
(__mmask8) __U);
@@ -5501,13 +5501,13 @@ _mm_loadu_epi64 (void const *__P)
struct __loadu_epi64 {
__m128i_u __v;
} __attribute__((__packed__, __may_alias__));
- return ((struct __loadu_epi64*)__P)->__v;
+ return ((const struct __loadu_epi64*)__P)->__v;
}
static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_mask_loadu_epi64 (__m128i __W, __mmask8 __U, void const *__P)
{
- return (__m128i) __builtin_ia32_loaddqudi128_mask ((__v2di *) __P,
+ return (__m128i) __builtin_ia32_loaddqudi128_mask ((const __v2di *) __P,
(__v2di) __W,
(__mmask8) __U);
}
@@ -5515,7 +5515,7 @@ _mm_mask_loadu_epi64 (__m128i __W, __mmask8 __U, void const *__P)
static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_maskz_loadu_epi64 (__mmask8 __U, void const *__P)
{
- return (__m128i) __builtin_ia32_loaddqudi128_mask ((__v2di *) __P,
+ return (__m128i) __builtin_ia32_loaddqudi128_mask ((const __v2di *) __P,
(__v2di)
_mm_setzero_si128 (),
(__mmask8) __U);
@@ -5527,13 +5527,13 @@ _mm256_loadu_epi64 (void const *__P)
struct __loadu_epi64 {
__m256i_u __v;
} __attribute__((__packed__, __may_alias__));
- return ((struct __loadu_epi64*)__P)->__v;
+ return ((const struct __loadu_epi64*)__P)->__v;
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_mask_loadu_epi64 (__m256i __W, __mmask8 __U, void const *__P)
{
- return (__m256i) __builtin_ia32_loaddqudi256_mask ((__v4di *) __P,
+ return (__m256i) __builtin_ia32_loaddqudi256_mask ((const __v4di *) __P,
(__v4di) __W,
(__mmask8) __U);
}
@@ -5541,7 +5541,7 @@ _mm256_mask_loadu_epi64 (__m256i __W, __mmask8 __U, void const *__P)
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_maskz_loadu_epi64 (__mmask8 __U, void const *__P)
{
- return (__m256i) __builtin_ia32_loaddqudi256_mask ((__v4di *) __P,
+ return (__m256i) __builtin_ia32_loaddqudi256_mask ((const __v4di *) __P,
(__v4di)
_mm256_setzero_si256 (),
(__mmask8) __U);
@@ -5553,13 +5553,13 @@ _mm_loadu_epi32 (void const *__P)
struct __loadu_epi32 {
__m128i_u __v;
} __attribute__((__packed__, __may_alias__));
- return ((struct __loadu_epi32*)__P)->__v;
+ return ((const struct __loadu_epi32*)__P)->__v;
}
static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_mask_loadu_epi32 (__m128i __W, __mmask8 __U, void const *__P)
{
- return (__m128i) __builtin_ia32_loaddqusi128_mask ((__v4si *) __P,
+ return (__m128i) __builtin_ia32_loaddqusi128_mask ((const __v4si *) __P,
(__v4si) __W,
(__mmask8) __U);
}
@@ -5567,7 +5567,7 @@ _mm_mask_loadu_epi32 (__m128i __W, __mmask8 __U, void const *__P)
static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_maskz_loadu_epi32 (__mmask8 __U, void const *__P)
{
- return (__m128i) __builtin_ia32_loaddqusi128_mask ((__v4si *) __P,
+ return (__m128i) __builtin_ia32_loaddqusi128_mask ((const __v4si *) __P,
(__v4si)
_mm_setzero_si128 (),
(__mmask8) __U);
@@ -5579,13 +5579,13 @@ _mm256_loadu_epi32 (void const *__P)
struct __loadu_epi32 {
__m256i_u __v;
} __attribute__((__packed__, __may_alias__));
- return ((struct __loadu_epi32*)__P)->__v;
+ return ((const struct __loadu_epi32*)__P)->__v;
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_mask_loadu_epi32 (__m256i __W, __mmask8 __U, void const *__P)
{
- return (__m256i) __builtin_ia32_loaddqusi256_mask ((__v8si *) __P,
+ return (__m256i) __builtin_ia32_loaddqusi256_mask ((const __v8si *) __P,
(__v8si) __W,
(__mmask8) __U);
}
@@ -5593,7 +5593,7 @@ _mm256_mask_loadu_epi32 (__m256i __W, __mmask8 __U, void const *__P)
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_maskz_loadu_epi32 (__mmask8 __U, void const *__P)
{
- return (__m256i) __builtin_ia32_loaddqusi256_mask ((__v8si *) __P,
+ return (__m256i) __builtin_ia32_loaddqusi256_mask ((const __v8si *) __P,
(__v8si)
_mm256_setzero_si256 (),
(__mmask8) __U);
@@ -5602,7 +5602,7 @@ _mm256_maskz_loadu_epi32 (__mmask8 __U, void const *__P)
static __inline__ __m128d __DEFAULT_FN_ATTRS128
_mm_mask_loadu_pd (__m128d __W, __mmask8 __U, void const *__P)
{
- return (__m128d) __builtin_ia32_loadupd128_mask ((__v2df *) __P,
+ return (__m128d) __builtin_ia32_loadupd128_mask ((const __v2df *) __P,
(__v2df) __W,
(__mmask8) __U);
}
@@ -5610,7 +5610,7 @@ _mm_mask_loadu_pd (__m128d __W, __mmask8 __U, void const *__P)
static __inline__ __m128d __DEFAULT_FN_ATTRS128
_mm_maskz_loadu_pd (__mmask8 __U, void const *__P)
{
- return (__m128d) __builtin_ia32_loadupd128_mask ((__v2df *) __P,
+ return (__m128d) __builtin_ia32_loadupd128_mask ((const __v2df *) __P,
(__v2df)
_mm_setzero_pd (),
(__mmask8) __U);
@@ -5619,7 +5619,7 @@ _mm_maskz_loadu_pd (__mmask8 __U, void const *__P)
static __inline__ __m256d __DEFAULT_FN_ATTRS256
_mm256_mask_loadu_pd (__m256d __W, __mmask8 __U, void const *__P)
{
- return (__m256d) __builtin_ia32_loadupd256_mask ((__v4df *) __P,
+ return (__m256d) __builtin_ia32_loadupd256_mask ((const __v4df *) __P,
(__v4df) __W,
(__mmask8) __U);
}
@@ -5627,7 +5627,7 @@ _mm256_mask_loadu_pd (__m256d __W, __mmask8 __U, void const *__P)
static __inline__ __m256d __DEFAULT_FN_ATTRS256
_mm256_maskz_loadu_pd (__mmask8 __U, void const *__P)
{
- return (__m256d) __builtin_ia32_loadupd256_mask ((__v4df *) __P,
+ return (__m256d) __builtin_ia32_loadupd256_mask ((const __v4df *) __P,
(__v4df)
_mm256_setzero_pd (),
(__mmask8) __U);
@@ -5636,7 +5636,7 @@ _mm256_maskz_loadu_pd (__mmask8 __U, void const *__P)
static __inline__ __m128 __DEFAULT_FN_ATTRS128
_mm_mask_loadu_ps (__m128 __W, __mmask8 __U, void const *__P)
{
- return (__m128) __builtin_ia32_loadups128_mask ((__v4sf *) __P,
+ return (__m128) __builtin_ia32_loadups128_mask ((const __v4sf *) __P,
(__v4sf) __W,
(__mmask8) __U);
}
@@ -5644,7 +5644,7 @@ _mm_mask_loadu_ps (__m128 __W, __mmask8 __U, void const *__P)
static __inline__ __m128 __DEFAULT_FN_ATTRS128
_mm_maskz_loadu_ps (__mmask8 __U, void const *__P)
{
- return (__m128) __builtin_ia32_loadups128_mask ((__v4sf *) __P,
+ return (__m128) __builtin_ia32_loadups128_mask ((const __v4sf *) __P,
(__v4sf)
_mm_setzero_ps (),
(__mmask8) __U);
@@ -5653,7 +5653,7 @@ _mm_maskz_loadu_ps (__mmask8 __U, void const *__P)
static __inline__ __m256 __DEFAULT_FN_ATTRS256
_mm256_mask_loadu_ps (__m256 __W, __mmask8 __U, void const *__P)
{
- return (__m256) __builtin_ia32_loadups256_mask ((__v8sf *) __P,
+ return (__m256) __builtin_ia32_loadups256_mask ((const __v8sf *) __P,
(__v8sf) __W,
(__mmask8) __U);
}
@@ -5661,7 +5661,7 @@ _mm256_mask_loadu_ps (__m256 __W, __mmask8 __U, void const *__P)
static __inline__ __m256 __DEFAULT_FN_ATTRS256
_mm256_maskz_loadu_ps (__mmask8 __U, void const *__P)
{
- return (__m256) __builtin_ia32_loadups256_mask ((__v8sf *) __P,
+ return (__m256) __builtin_ia32_loadups256_mask ((const __v8sf *) __P,
(__v8sf)
_mm256_setzero_ps (),
(__mmask8) __U);
diff --git a/clang/lib/Headers/avxintrin.h b/clang/lib/Headers/avxintrin.h
index a01240b9d157..84421bf1b9d5 100644
--- a/clang/lib/Headers/avxintrin.h
+++ b/clang/lib/Headers/avxintrin.h
@@ -3069,7 +3069,7 @@ _mm256_broadcast_ps(__m128 const *__a)
static __inline __m256d __DEFAULT_FN_ATTRS
_mm256_load_pd(double const *__p)
{
- return *(__m256d *)__p;
+ return *(const __m256d *)__p;
}
/// Loads 8 single-precision floating point values from a 32-byte aligned
@@ -3085,7 +3085,7 @@ _mm256_load_pd(double const *__p)
static __inline __m256 __DEFAULT_FN_ATTRS
_mm256_load_ps(float const *__p)
{
- return *(__m256 *)__p;
+ return *(const __m256 *)__p;
}
/// Loads 4 double-precision floating point values from an unaligned
@@ -3105,7 +3105,7 @@ _mm256_loadu_pd(double const *__p)
struct __loadu_pd {
__m256d_u __v;
} __attribute__((__packed__, __may_alias__));
- return ((struct __loadu_pd*)__p)->__v;
+ return ((const struct __loadu_pd*)__p)->__v;
}
/// Loads 8 single-precision floating point values from an unaligned
@@ -3125,7 +3125,7 @@ _mm256_loadu_ps(float const *__p)
struct __loadu_ps {
__m256_u __v;
} __attribute__((__packed__, __may_alias__));
- return ((struct __loadu_ps*)__p)->__v;
+ return ((const struct __loadu_ps*)__p)->__v;
}
/// Loads 256 bits of integer data from a 32-byte aligned memory
@@ -3161,7 +3161,7 @@ _mm256_loadu_si256(__m256i_u const *__p)
struct __loadu_si256 {
__m256i_u __v;
} __attribute__((__packed__, __may_alias__));
- return ((struct __loadu_si256*)__p)->__v;
+ return ((const struct __loadu_si256*)__p)->__v;
}
/// Loads 256 bits of integer data from an unaligned memory location
diff --git a/clang/lib/Headers/emmintrin.h b/clang/lib/Headers/emmintrin.h
index c8fefdfc792a..993c688ce818 100644
--- a/clang/lib/Headers/emmintrin.h
+++ b/clang/lib/Headers/emmintrin.h
@@ -1578,7 +1578,7 @@ _mm_cvtsd_f64(__m128d __a)
static __inline__ __m128d __DEFAULT_FN_ATTRS
_mm_load_pd(double const *__dp)
{
- return *(__m128d*)__dp;
+ return *(const __m128d*)__dp;
}
/// Loads a double-precision floating-point value from a specified memory
@@ -1599,7 +1599,7 @@ _mm_load1_pd(double const *__dp)
struct __mm_load1_pd_struct {
double __u;
} __attribute__((__packed__, __may_alias__));
- double __u = ((struct __mm_load1_pd_struct*)__dp)->__u;
+ double __u = ((const struct __mm_load1_pd_struct*)__dp)->__u;
return __extension__ (__m128d){ __u, __u };
}
@@ -1622,7 +1622,7 @@ _mm_load1_pd(double const *__dp)
static __inline__ __m128d __DEFAULT_FN_ATTRS
_mm_loadr_pd(double const *__dp)
{
- __m128d __u = *(__m128d*)__dp;
+ __m128d __u = *(const __m128d*)__dp;
return __builtin_shufflevector((__v2df)__u, (__v2df)__u, 1, 0);
}
@@ -1643,7 +1643,7 @@ _mm_loadu_pd(double const *__dp)
struct __loadu_pd {
__m128d_u __v;
} __attribute__((__packed__, __may_alias__));
- return ((struct __loadu_pd*)__dp)->__v;
+ return ((const struct __loadu_pd*)__dp)->__v;
}
/// Loads a 64-bit integer value to the low element of a 128-bit integer
@@ -1663,7 +1663,7 @@ _mm_loadu_si64(void const *__a)
struct __loadu_si64 {
long long __v;
} __attribute__((__packed__, __may_alias__));
- long long __u = ((struct __loadu_si64*)__a)->__v;
+ long long __u = ((const struct __loadu_si64*)__a)->__v;
return __extension__ (__m128i)(__v2di){__u, 0LL};
}
@@ -1684,7 +1684,7 @@ _mm_loadu_si32(void const *__a)
struct __loadu_si32 {
int __v;
} __attribute__((__packed__, __may_alias__));
- int __u = ((struct __loadu_si32*)__a)->__v;
+ int __u = ((const struct __loadu_si32*)__a)->__v;
return __extension__ (__m128i)(__v4si){__u, 0, 0, 0};
}
@@ -1705,7 +1705,7 @@ _mm_loadu_si16(void const *__a)
struct __loadu_si16 {
short __v;
} __attribute__((__packed__, __may_alias__));
- short __u = ((struct __loadu_si16*)__a)->__v;
+ short __u = ((const struct __loadu_si16*)__a)->__v;
return __extension__ (__m128i)(__v8hi){__u, 0, 0, 0, 0, 0, 0, 0};
}
@@ -1726,7 +1726,7 @@ _mm_load_sd(double const *__dp)
struct __mm_load_sd_struct {
double __u;
} __attribute__((__packed__, __may_alias__));
- double __u = ((struct __mm_load_sd_struct*)__dp)->__u;
+ double __u = ((const struct __mm_load_sd_struct*)__dp)->__u;
return __extension__ (__m128d){ __u, 0 };
}
@@ -1753,7 +1753,7 @@ _mm_loadh_pd(__m128d __a, double const *__dp)
struct __mm_loadh_pd_struct {
double __u;
} __attribute__((__packed__, __may_alias__));
- double __u = ((struct __mm_loadh_pd_struct*)__dp)->__u;
+ double __u = ((const struct __mm_loadh_pd_struct*)__dp)->__u;
return __extension__ (__m128d){ __a[0], __u };
}
@@ -1780,7 +1780,7 @@ _mm_loadl_pd(__m128d __a, double const *__dp)
struct __mm_loadl_pd_struct {
double __u;
} __attribute__((__packed__, __may_alias__));
- double __u = ((struct __mm_loadl_pd_struct*)__dp)->__u;
+ double __u = ((const struct __mm_loadl_pd_struct*)__dp)->__u;
return __extension__ (__m128d){ __u, __a[1] };
}
@@ -2288,7 +2288,7 @@ _mm_adds_epu16(__m128i __a, __m128i __b)
return (__m128i)__builtin_ia32_paddusw128((__v8hi)__a, (__v8hi)__b);
}
-/// Computes the rounded avarages of corresponding elements of two
+/// Computes the rounded averages of corresponding elements of two
/// 128-bit unsigned [16 x i8] vectors, saving each result in the
/// corresponding element of a 128-bit result vector of [16 x i8].
///
@@ -2308,7 +2308,7 @@ _mm_avg_epu8(__m128i __a, __m128i __b)
return (__m128i)__builtin_ia32_pavgb128((__v16qi)__a, (__v16qi)__b);
}
-/// Computes the rounded avarages of corresponding elements of two
+/// Computes the rounded averages of corresponding elements of two
/// 128-bit unsigned [8 x i16] vectors, saving each result in the
/// corresponding element of a 128-bit result vector of [8 x i16].
///
@@ -3550,7 +3550,7 @@ _mm_loadu_si128(__m128i_u const *__p)
struct __loadu_si128 {
__m128i_u __v;
} __attribute__((__packed__, __may_alias__));
- return ((struct __loadu_si128*)__p)->__v;
+ return ((const struct __loadu_si128*)__p)->__v;
}
/// Returns a vector of [2 x i64] where the lower element is taken from
@@ -3571,7 +3571,7 @@ _mm_loadl_epi64(__m128i_u const *__p)
struct __mm_loadl_epi64_struct {
long long __u;
} __attribute__((__packed__, __may_alias__));
- return __extension__ (__m128i) { ((struct __mm_loadl_epi64_struct*)__p)->__u, 0};
+ return __extension__ (__m128i) { ((const struct __mm_loadl_epi64_struct*)__p)->__u, 0};
}
/// Generates a 128-bit vector of [4 x i32] with unspecified content.
diff --git a/clang/lib/Headers/immintrin.h b/clang/lib/Headers/immintrin.h
index ae900ee85b76..edf8c42ec491 100644
--- a/clang/lib/Headers/immintrin.h
+++ b/clang/lib/Headers/immintrin.h
@@ -301,7 +301,7 @@ _loadbe_i16(void const * __P) {
struct __loadu_i16 {
short __v;
} __attribute__((__packed__, __may_alias__));
- return __builtin_bswap16(((struct __loadu_i16*)__P)->__v);
+ return __builtin_bswap16(((const struct __loadu_i16*)__P)->__v);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__, __target__("movbe")))
@@ -317,7 +317,7 @@ _loadbe_i32(void const * __P) {
struct __loadu_i32 {
int __v;
} __attribute__((__packed__, __may_alias__));
- return __builtin_bswap32(((struct __loadu_i32*)__P)->__v);
+ return __builtin_bswap32(((const struct __loadu_i32*)__P)->__v);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__, __target__("movbe")))
@@ -334,7 +334,7 @@ _loadbe_i64(void const * __P) {
struct __loadu_i64 {
long long __v;
} __attribute__((__packed__, __may_alias__));
- return __builtin_bswap64(((struct __loadu_i64*)__P)->__v);
+ return __builtin_bswap64(((const struct __loadu_i64*)__P)->__v);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__, __target__("movbe")))
diff --git a/clang/lib/Headers/intrin.h b/clang/lib/Headers/intrin.h
index 9786ba147fca..f85f7a2beb49 100644
--- a/clang/lib/Headers/intrin.h
+++ b/clang/lib/Headers/intrin.h
@@ -36,6 +36,12 @@
/* Define the default attributes for the functions in this file. */
#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__))
+#if __x86_64__
+#define __LPTRINT_TYPE__ __int64
+#else
+#define __LPTRINT_TYPE__ long
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -94,8 +100,7 @@ void __outword(unsigned short, unsigned short);
void __outwordstring(unsigned short, unsigned short *, unsigned long);
unsigned long __readcr0(void);
unsigned long __readcr2(void);
-static __inline__
-unsigned long __readcr3(void);
+unsigned __LPTRINT_TYPE__ __readcr3(void);
unsigned long __readcr4(void);
unsigned long __readcr8(void);
unsigned int __readdr(unsigned int);
@@ -132,7 +137,7 @@ void __vmx_vmptrst(unsigned __int64 *);
void __wbinvd(void);
void __writecr0(unsigned int);
static __inline__
-void __writecr3(unsigned int);
+void __writecr3(unsigned __INTPTR_TYPE__);
void __writecr4(unsigned int);
void __writecr8(unsigned int);
void __writedr(unsigned int, unsigned int);
@@ -164,7 +169,6 @@ long _InterlockedExchangeAdd_HLEAcquire(long volatile *, long);
long _InterlockedExchangeAdd_HLERelease(long volatile *, long);
__int64 _InterlockedExchangeAdd64_HLEAcquire(__int64 volatile *, __int64);
__int64 _InterlockedExchangeAdd64_HLERelease(__int64 volatile *, __int64);
-void __cdecl _invpcid(unsigned int, void *);
static __inline__ void
__attribute__((__deprecated__("use other intrinsics or C++11 atomics instead")))
_ReadBarrier(void);
@@ -565,24 +569,26 @@ __readmsr(unsigned long __register) {
__asm__ ("rdmsr" : "=d"(__edx), "=a"(__eax) : "c"(__register));
return (((unsigned __int64)__edx) << 32) | (unsigned __int64)__eax;
}
+#endif
-static __inline__ unsigned long __DEFAULT_FN_ATTRS
+static __inline__ unsigned __LPTRINT_TYPE__ __DEFAULT_FN_ATTRS
__readcr3(void) {
- unsigned long __cr3_val;
- __asm__ __volatile__ ("mov %%cr3, %0" : "=q"(__cr3_val) : : "memory");
+ unsigned __LPTRINT_TYPE__ __cr3_val;
+ __asm__ __volatile__ ("mov %%cr3, %0" : "=r"(__cr3_val) : : "memory");
return __cr3_val;
}
static __inline__ void __DEFAULT_FN_ATTRS
-__writecr3(unsigned int __cr3_val) {
- __asm__ ("mov %0, %%cr3" : : "q"(__cr3_val) : "memory");
+__writecr3(unsigned __INTPTR_TYPE__ __cr3_val) {
+ __asm__ ("mov %0, %%cr3" : : "r"(__cr3_val) : "memory");
}
-#endif
#ifdef __cplusplus
}
#endif
+#undef __LPTRINT_TYPE__
+
#undef __DEFAULT_FN_ATTRS
#endif /* __INTRIN_H */
diff --git a/clang/lib/Headers/mwaitxintrin.h b/clang/lib/Headers/mwaitxintrin.h
index bca395b0e0d1..ed485380af79 100644
--- a/clang/lib/Headers/mwaitxintrin.h
+++ b/clang/lib/Headers/mwaitxintrin.h
@@ -17,9 +17,9 @@
/* Define the default attributes for the functions in this file. */
#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("mwaitx")))
static __inline__ void __DEFAULT_FN_ATTRS
-_mm_monitorx(void const * __p, unsigned __extensions, unsigned __hints)
+_mm_monitorx(void * __p, unsigned __extensions, unsigned __hints)
{
- __builtin_ia32_monitorx((void *)__p, __extensions, __hints);
+ __builtin_ia32_monitorx(__p, __extensions, __hints);
}
static __inline__ void __DEFAULT_FN_ATTRS
diff --git a/clang/lib/Headers/pmmintrin.h b/clang/lib/Headers/pmmintrin.h
index c376f298cc30..a83b2eb6d8e2 100644
--- a/clang/lib/Headers/pmmintrin.h
+++ b/clang/lib/Headers/pmmintrin.h
@@ -263,7 +263,7 @@ _mm_movedup_pd(__m128d __a)
static __inline__ void __DEFAULT_FN_ATTRS
_mm_monitor(void const *__p, unsigned __extensions, unsigned __hints)
{
- __builtin_ia32_monitor((void *)__p, __extensions, __hints);
+ __builtin_ia32_monitor(__p, __extensions, __hints);
}
/// Used with the MONITOR instruction to wait while the processor is in
diff --git a/clang/lib/Headers/xmmintrin.h b/clang/lib/Headers/xmmintrin.h
index 75ff37655bda..0e61eab44aeb 100644
--- a/clang/lib/Headers/xmmintrin.h
+++ b/clang/lib/Headers/xmmintrin.h
@@ -1627,7 +1627,7 @@ _mm_loadh_pi(__m128 __a, const __m64 *__p)
struct __mm_loadh_pi_struct {
__mm_loadh_pi_v2f32 __u;
} __attribute__((__packed__, __may_alias__));
- __mm_loadh_pi_v2f32 __b = ((struct __mm_loadh_pi_struct*)__p)->__u;
+ __mm_loadh_pi_v2f32 __b = ((const struct __mm_loadh_pi_struct*)__p)->__u;
__m128 __bb = __builtin_shufflevector(__b, __b, 0, 1, 0, 1);
return __builtin_shufflevector(__a, __bb, 0, 1, 4, 5);
}
@@ -1654,7 +1654,7 @@ _mm_loadl_pi(__m128 __a, const __m64 *__p)
struct __mm_loadl_pi_struct {
__mm_loadl_pi_v2f32 __u;
} __attribute__((__packed__, __may_alias__));
- __mm_loadl_pi_v2f32 __b = ((struct __mm_loadl_pi_struct*)__p)->__u;
+ __mm_loadl_pi_v2f32 __b = ((const struct __mm_loadl_pi_struct*)__p)->__u;
__m128 __bb = __builtin_shufflevector(__b, __b, 0, 1, 0, 1);
return __builtin_shufflevector(__a, __bb, 4, 5, 2, 3);
}
@@ -1680,7 +1680,7 @@ _mm_load_ss(const float *__p)
struct __mm_load_ss_struct {
float __u;
} __attribute__((__packed__, __may_alias__));
- float __u = ((struct __mm_load_ss_struct*)__p)->__u;
+ float __u = ((const struct __mm_load_ss_struct*)__p)->__u;
return __extension__ (__m128){ __u, 0, 0, 0 };
}
@@ -1702,7 +1702,7 @@ _mm_load1_ps(const float *__p)
struct __mm_load1_ps_struct {
float __u;
} __attribute__((__packed__, __may_alias__));
- float __u = ((struct __mm_load1_ps_struct*)__p)->__u;
+ float __u = ((const struct __mm_load1_ps_struct*)__p)->__u;
return __extension__ (__m128){ __u, __u, __u, __u };
}
@@ -1722,7 +1722,7 @@ _mm_load1_ps(const float *__p)
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_load_ps(const float *__p)
{
- return *(__m128*)__p;
+ return *(const __m128*)__p;
}
/// Loads a 128-bit floating-point vector of [4 x float] from an
@@ -1742,7 +1742,7 @@ _mm_loadu_ps(const float *__p)
struct __loadu_ps {
__m128_u __v;
} __attribute__((__packed__, __may_alias__));
- return ((struct __loadu_ps*)__p)->__v;
+ return ((const struct __loadu_ps*)__p)->__v;
}
/// Loads four packed float values, in reverse order, from an aligned
@@ -2100,7 +2100,7 @@ _mm_storer_ps(float *__p, __m128 __a)
/// be generated. \n
/// _MM_HINT_T2: Move data using the T2 hint. The PREFETCHT2 instruction will
/// be generated.
-#define _mm_prefetch(a, sel) (__builtin_prefetch((void *)(a), \
+#define _mm_prefetch(a, sel) (__builtin_prefetch((const void *)(a), \
((sel) >> 2) & 1, (sel) & 0x3))
#endif
diff --git a/clang/lib/Index/CommentToXML.cpp b/clang/lib/Index/CommentToXML.cpp
index 55923d679fea..ce6f9e2b13bd 100644
--- a/clang/lib/Index/CommentToXML.cpp
+++ b/clang/lib/Index/CommentToXML.cpp
@@ -297,6 +297,10 @@ void CommentASTToHTMLConverter::visitInlineCommandComment(
appendToResultWithHTMLEscaping(Arg0);
Result << "</em>";
return;
+ case InlineCommandComment::RenderAnchor:
+ assert(C->getNumArgs() == 1);
+ Result << "<span id=\"" << Arg0 << "\"></span>";
+ return;
}
}
@@ -641,6 +645,10 @@ void CommentASTToXMLConverter::visitInlineCommandComment(
appendToResultWithXMLEscaping(Arg0);
Result << "</emphasized>";
return;
+ case InlineCommandComment::RenderAnchor:
+ assert(C->getNumArgs() == 1);
+ Result << "<anchor id=\"" << Arg0 << "\"></anchor>";
+ return;
}
}
diff --git a/clang/lib/Index/IndexDecl.cpp b/clang/lib/Index/IndexDecl.cpp
index 5bbbb0d32bf4..c59b1372e399 100644
--- a/clang/lib/Index/IndexDecl.cpp
+++ b/clang/lib/Index/IndexDecl.cpp
@@ -7,8 +7,9 @@
//===----------------------------------------------------------------------===//
#include "IndexingContext.h"
-#include "clang/Index/IndexDataConsumer.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclVisitor.h"
+#include "clang/Index/IndexDataConsumer.h"
using namespace clang;
using namespace index;
@@ -42,15 +43,6 @@ public:
return true;
}
- /// Returns true if the given method has been defined explicitly by the
- /// user.
- static bool hasUserDefined(const ObjCMethodDecl *D,
- const ObjCImplDecl *Container) {
- const ObjCMethodDecl *MD = Container->getMethod(D->getSelector(),
- D->isInstanceMethod());
- return MD && !MD->isImplicit() && MD->isThisDeclarationADefinition();
- }
-
void handleTemplateArgumentLoc(const TemplateArgumentLoc &TALoc,
const NamedDecl *Parent,
const DeclContext *DC) {
@@ -78,6 +70,17 @@ public:
}
}
+ /// Returns true if the given method has been defined explicitly by the
+ /// user.
+ static bool hasUserDefined(const ObjCMethodDecl *D,
+ const ObjCImplDecl *Container) {
+ const ObjCMethodDecl *MD = Container->getMethod(D->getSelector(),
+ D->isInstanceMethod());
+ return MD && !MD->isImplicit() && MD->isThisDeclarationADefinition() &&
+ !MD->isSynthesizedAccessorStub();
+ }
+
+
void handleDeclarator(const DeclaratorDecl *D,
const NamedDecl *Parent = nullptr,
bool isIBType = false) {
@@ -534,13 +537,11 @@ public:
SymbolRoleSet AccessorMethodRoles =
SymbolRoleSet(SymbolRole::Dynamic) | SymbolRoleSet(SymbolRole::Implicit);
if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) {
- if (MD->isPropertyAccessor() &&
- !hasUserDefined(MD, Container))
+ if (MD->isPropertyAccessor() && !hasUserDefined(MD, Container))
IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container);
}
if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) {
- if (MD->isPropertyAccessor() &&
- !hasUserDefined(MD, Container))
+ if (MD->isPropertyAccessor() && !hasUserDefined(MD, Container))
IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container);
}
if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) {
diff --git a/clang/lib/Index/IndexSymbol.cpp b/clang/lib/Index/IndexSymbol.cpp
index 5165567ff75e..ae9134bf1182 100644
--- a/clang/lib/Index/IndexSymbol.cpp
+++ b/clang/lib/Index/IndexSymbol.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Index/IndexSymbol.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
diff --git a/clang/lib/Index/IndexingAction.cpp b/clang/lib/Index/IndexingAction.cpp
index 6d6133e89d86..4f402135672c 100644
--- a/clang/lib/Index/IndexingAction.cpp
+++ b/clang/lib/Index/IndexingAction.cpp
@@ -151,7 +151,7 @@ static void indexPreprocessorMacros(const Preprocessor &PP,
IndexDataConsumer &DataConsumer) {
for (const auto &M : PP.macros())
if (MacroDirective *MD = M.second.getLatest())
- DataConsumer.handleMacroOccurence(
+ DataConsumer.handleMacroOccurrence(
M.first, MD->getMacroInfo(),
static_cast<unsigned>(index::SymbolRole::Definition),
MD->getLocation());
diff --git a/clang/lib/Index/IndexingContext.cpp b/clang/lib/Index/IndexingContext.cpp
index e29856007149..a7c37e8528d1 100644
--- a/clang/lib/Index/IndexingContext.cpp
+++ b/clang/lib/Index/IndexingContext.cpp
@@ -7,12 +7,13 @@
//===----------------------------------------------------------------------===//
#include "IndexingContext.h"
-#include "clang/Basic/SourceLocation.h"
-#include "clang/Index/IndexDataConsumer.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Index/IndexDataConsumer.h"
using namespace clang;
using namespace index;
@@ -98,9 +99,8 @@ static void reportModuleReferences(const Module *Mod,
return;
reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
DataConsumer);
- DataConsumer.handleModuleOccurence(ImportD, Mod,
- (SymbolRoleSet)SymbolRole::Reference,
- IdLocs.back());
+ DataConsumer.handleModuleOccurrence(
+ ImportD, Mod, (SymbolRoleSet)SymbolRole::Reference, IdLocs.back());
}
bool IndexingContext::importedModule(const ImportDecl *ImportD) {
@@ -144,7 +144,7 @@ bool IndexingContext::importedModule(const ImportDecl *ImportD) {
if (ImportD->isImplicit())
Roles |= (unsigned)SymbolRole::Implicit;
- return DataConsumer.handleModuleOccurence(ImportD, Mod, Roles, Loc);
+ return DataConsumer.handleModuleOccurrence(ImportD, Mod, Roles, Loc);
}
bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
@@ -442,26 +442,26 @@ bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
}
IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC};
- return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, Loc, Node);
+ return DataConsumer.handleDeclOccurrence(D, Roles, FinalRelations, Loc, Node);
}
void IndexingContext::handleMacroDefined(const IdentifierInfo &Name,
SourceLocation Loc,
const MacroInfo &MI) {
SymbolRoleSet Roles = (unsigned)SymbolRole::Definition;
- DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
+ DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
}
void IndexingContext::handleMacroUndefined(const IdentifierInfo &Name,
SourceLocation Loc,
const MacroInfo &MI) {
SymbolRoleSet Roles = (unsigned)SymbolRole::Undefinition;
- DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
+ DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
}
void IndexingContext::handleMacroReference(const IdentifierInfo &Name,
SourceLocation Loc,
const MacroInfo &MI) {
SymbolRoleSet Roles = (unsigned)SymbolRole::Reference;
- DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
+ DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
}
diff --git a/clang/lib/Index/USRGeneration.cpp b/clang/lib/Index/USRGeneration.cpp
index f4316fe7d067..394daf94c4b2 100644
--- a/clang/lib/Index/USRGeneration.cpp
+++ b/clang/lib/Index/USRGeneration.cpp
@@ -8,6 +8,7 @@
#include "clang/Index/USRGeneration.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/Lex/PreprocessingRecord.h"
diff --git a/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp b/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp
index f063ed711c44..029bfe1cd600 100644
--- a/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp
+++ b/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp
@@ -763,12 +763,13 @@ bool Minimizer::lexEndif(const char *&First, const char *const End) {
if (top() == pp_else)
popToken();
- // Strip out "#elif" if they're empty.
- while (top() == pp_elif)
- popToken();
-
- // If "#if" is empty, strip it and skip the "#endif".
- if (top() == pp_if || top() == pp_ifdef || top() == pp_ifndef) {
+ // If "#ifdef" is empty, strip it and skip the "#endif".
+ //
+ // FIXME: Once/if Clang starts disallowing __has_include in macro expansions,
+ // we can skip empty `#if` and `#elif` blocks as well after scanning for a
+ // literal __has_include in the condition. Even without that rule we could
+ // drop the tokens if we scan for identifiers in the condition and find none.
+ if (top() == pp_ifdef || top() == pp_ifndef) {
popToken();
skipLine(First, End);
return false;
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 17f5ab1e035d..648bda270578 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -1431,6 +1431,8 @@ void Lexer::SetByteOffset(unsigned Offset, bool StartOfLine) {
static bool isAllowedIDChar(uint32_t C, const LangOptions &LangOpts) {
if (LangOpts.AsmPreprocessor) {
return false;
+ } else if (LangOpts.DollarIdents && '$' == C) {
+ return true;
} else if (LangOpts.CPlusPlus11 || LangOpts.C11) {
static const llvm::sys::UnicodeCharSet C11AllowedIDChars(
C11AllowedIDCharRanges);
@@ -2656,6 +2658,7 @@ void Lexer::ReadToEndOfLine(SmallVectorImpl<char> *Result) {
assert(ParsingPreprocessorDirective && ParsingFilename == false &&
"Must be in a preprocessing directive!");
Token Tmp;
+ Tmp.startToken();
// CurPtr - Cache BufferPtr in an automatic variable.
const char *CurPtr = BufferPtr;
diff --git a/clang/lib/Lex/LiteralSupport.cpp b/clang/lib/Lex/LiteralSupport.cpp
index 2108408377fb..9a852141c6ee 100644
--- a/clang/lib/Lex/LiteralSupport.cpp
+++ b/clang/lib/Lex/LiteralSupport.cpp
@@ -1051,7 +1051,11 @@ NumericLiteralParser::GetFloatValue(llvm::APFloat &Result) {
Str = Buffer;
}
- return Result.convertFromString(Str, APFloat::rmNearestTiesToEven);
+ auto StatusOrErr =
+ Result.convertFromString(Str, APFloat::rmNearestTiesToEven);
+ assert(StatusOrErr && "Invalid floating point representation");
+ return !errorToBool(StatusOrErr.takeError()) ? *StatusOrErr
+ : APFloat::opInvalidOp;
}
static inline bool IsExponentPart(char c) {
diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp
index db59629997ee..fe20a3507036 100644
--- a/clang/lib/Lex/ModuleMap.cpp
+++ b/clang/lib/Lex/ModuleMap.cpp
@@ -229,7 +229,7 @@ const FileEntry *ModuleMap::findHeader(
llvm::sys::path::append(FullPathName, RelativePathName);
auto *NormalHdrFile = GetFile(FullPathName);
- if (M && !NormalHdrFile && Directory->getName().endswith(".framework")) {
+ if (!NormalHdrFile && Directory->getName().endswith(".framework")) {
// The lack of 'framework' keyword in a module declaration it's a simple
// mistake we can diagnose when the header exists within the proper
// framework style path.
diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index 3b7eaee3c914..e433b2cf1b95 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -2727,7 +2727,9 @@ void Preprocessor::HandleDefineDirective(
/*Syntactic=*/LangOpts.MicrosoftExt))
Diag(MI->getDefinitionLoc(), diag::warn_pp_macro_def_mismatch_with_pch)
<< MacroNameTok.getIdentifierInfo();
- return;
+ // Issue the diagnostic but allow the change if msvc extensions are enabled
+ if (!LangOpts.MicrosoftExt)
+ return;
}
// Finally, if this identifier already had a macro defined for it, verify that
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp
index dfbcaedcacff..cf8bb2fbab99 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/Attributes.h"
+#include "clang/Basic/Builtins.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
@@ -28,6 +29,7 @@
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorLexer.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Lex/Token.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
@@ -35,9 +37,9 @@
#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"
-#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Casting.h"
@@ -369,7 +371,11 @@ void Preprocessor::RegisterBuiltinMacros() {
Ident__has_extension = RegisterBuiltinMacro(*this, "__has_extension");
Ident__has_builtin = RegisterBuiltinMacro(*this, "__has_builtin");
Ident__has_attribute = RegisterBuiltinMacro(*this, "__has_attribute");
- Ident__has_c_attribute = RegisterBuiltinMacro(*this, "__has_c_attribute");
+ if (!LangOpts.CPlusPlus)
+ Ident__has_c_attribute = RegisterBuiltinMacro(*this, "__has_c_attribute");
+ else
+ Ident__has_c_attribute = nullptr;
+
Ident__has_declspec = RegisterBuiltinMacro(*this, "__has_declspec_attribute");
Ident__has_include = RegisterBuiltinMacro(*this, "__has_include");
Ident__has_include_next = RegisterBuiltinMacro(*this, "__has_include_next");
@@ -820,18 +826,26 @@ MacroArgs *Preprocessor::ReadMacroCallArgumentList(Token &MacroName,
}
} else if (Tok.is(tok::l_paren)) {
++NumParens;
- } else if (Tok.is(tok::comma) && NumParens == 0 &&
- !(Tok.getFlags() & Token::IgnoredComma)) {
+ } else if (Tok.is(tok::comma)) {
// In Microsoft-compatibility mode, single commas from nested macro
// expansions should not be considered as argument separators. We test
- // for this with the IgnoredComma token flag above.
-
- // Comma ends this argument if there are more fixed arguments expected.
- // However, if this is a variadic macro, and this is part of the
- // variadic part, then the comma is just an argument token.
- if (!isVariadic) break;
- if (NumFixedArgsLeft > 1)
- break;
+ // for this with the IgnoredComma token flag.
+ if (Tok.getFlags() & Token::IgnoredComma) {
+ // However, in MSVC's preprocessor, subsequent expansions do treat
+ // these commas as argument separators. This leads to a common
+ // workaround used in macros that need to work in both MSVC and
+ // compliant preprocessors. Therefore, the IgnoredComma flag can only
+ // apply once to any given token.
+ Tok.clearFlag(Token::IgnoredComma);
+ } else if (NumParens == 0) {
+ // Comma ends this argument if there are more fixed arguments
+ // expected. However, if this is a variadic macro, and this is part of
+ // the variadic part, then the comma is just an argument token.
+ if (!isVariadic)
+ break;
+ if (NumFixedArgsLeft > 1)
+ break;
+ }
} else if (Tok.is(tok::comment) && !KeepMacroComments) {
// If this is a comment token in the argument list and we're just in
// -C mode (not -CC mode), discard the comment.
@@ -1437,6 +1451,17 @@ static bool isTargetEnvironment(const TargetInfo &TI,
return TI.getTriple().getEnvironment() == Env.getEnvironment();
}
+static void remapMacroPath(
+ SmallString<256> &Path,
+ const std::map<std::string, std::string, std::greater<std::string>>
+ &MacroPrefixMap) {
+ for (const auto &Entry : MacroPrefixMap)
+ if (Path.startswith(Entry.first)) {
+ Path = (Twine(Entry.second) + Path.substr(Entry.first.size())).str();
+ break;
+ }
+}
+
/// 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) {
@@ -1503,7 +1528,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
}
// Escape this filename. Turn '\' -> '\\' '"' -> '\"'
- SmallString<128> FN;
+ SmallString<256> FN;
if (PLoc.isValid()) {
// __FILE_NAME__ is a Clang-specific extension that expands to the
// the last part of __FILE__.
@@ -1519,6 +1544,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
FN += PLoc.getFilename();
}
Lexer::Stringify(FN);
+ remapMacroPath(FN, PPOpts->MacroPrefixMap);
OS << '"' << FN << '"';
}
Tok.setKind(tok::string_literal);
diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp
index 79953804b5d3..e4636265a72b 100644
--- a/clang/lib/Lex/Pragma.cpp
+++ b/clang/lib/Lex/Pragma.cpp
@@ -848,8 +848,8 @@ void Preprocessor::HandlePragmaModuleBuild(Token &Tok) {
CurLexer->getBuffer().begin() <= End &&
End <= CurLexer->getBuffer().end() &&
"module source range not contained within same file buffer");
- TheModuleLoader.loadModuleFromSource(Loc, ModuleName->getName(),
- StringRef(Start, End - Start));
+ TheModuleLoader.createModuleFromSource(Loc, ModuleName->getName(),
+ StringRef(Start, End - Start));
}
void Preprocessor::HandlePragmaHdrstop(Token &Tok) {
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index 82007732a9b1..0e9be3923630 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -25,6 +25,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/Builtins.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemStatCache.h"
#include "clang/Basic/IdentifierTable.h"
@@ -53,9 +54,9 @@
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Capacity.h"
@@ -112,6 +113,8 @@ Preprocessor::Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts,
// We haven't read anything from the external source.
ReadMacrosFromExternalSource = false;
+ BuiltinInfo = std::make_unique<Builtin::Context>();
+
// "Poison" __VA_ARGS__, __VA_OPT__ which can only appear in the expansion of
// a macro. They get unpoisoned where it is allowed.
(Ident__VA_ARGS__ = getIdentifierInfo("__VA_ARGS__"))->setIsPoisoned();
@@ -202,7 +205,7 @@ void Preprocessor::Initialize(const TargetInfo &Target,
this->AuxTarget = AuxTarget;
// Initialize information about built-ins.
- BuiltinInfo.InitializeTarget(Target, AuxTarget);
+ BuiltinInfo->InitializeTarget(Target, AuxTarget);
HeaderInfo.setTarget(Target);
// Populate the identifier table with info about keywords for the current language.
diff --git a/clang/lib/Parse/ParseAST.cpp b/clang/lib/Parse/ParseAST.cpp
index 3efd893e499c..01510e8caf3b 100644
--- a/clang/lib/Parse/ParseAST.cpp
+++ b/clang/lib/Parse/ParseAST.cpp
@@ -151,7 +151,7 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
bool HaveLexer = S.getPreprocessor().getCurrentLexer();
if (HaveLexer) {
- llvm::TimeTraceScope TimeScope("Frontend", StringRef(""));
+ llvm::TimeTraceScope TimeScope("Frontend");
P.Initialize();
Parser::DeclGroupPtrTy ADecl;
for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl); !AtEOF;
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index aa314da8e5b4..f8b5fec43800 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -223,6 +223,7 @@ Parser::LateParsedDeclaration::~LateParsedDeclaration() {}
void Parser::LateParsedDeclaration::ParseLexedMethodDeclarations() {}
void Parser::LateParsedDeclaration::ParseLexedMemberInitializers() {}
void Parser::LateParsedDeclaration::ParseLexedMethodDefs() {}
+void Parser::LateParsedDeclaration::ParseLexedPragmas() {}
Parser::LateParsedClass::LateParsedClass(Parser *P, ParsingClass *C)
: Self(P), Class(C) {}
@@ -243,6 +244,10 @@ void Parser::LateParsedClass::ParseLexedMethodDefs() {
Self->ParseLexedMethodDefs(*Class);
}
+void Parser::LateParsedClass::ParseLexedPragmas() {
+ Self->ParseLexedPragmas(*Class);
+}
+
void Parser::LateParsedMethodDeclaration::ParseLexedMethodDeclarations() {
Self->ParseLexedMethodDeclaration(*this);
}
@@ -255,6 +260,10 @@ void Parser::LateParsedMemberInitializer::ParseLexedMemberInitializers() {
Self->ParseLexedMemberInitializer(*this);
}
+void Parser::LateParsedPragma::ParseLexedPragmas() {
+ Self->ParseLexedPragma(*this);
+}
+
/// ParseLexedMethodDeclarations - We finished parsing the member
/// specification of a top (non-nested) C++ class. Now go over the
/// stack of method declarations with some parts for which parsing was
@@ -651,6 +660,43 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) {
ConsumeAnyToken();
}
+void Parser::ParseLexedPragmas(ParsingClass &Class) {
+ bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
+ ParseScope ClassTemplateScope(this, Scope::TemplateParamScope,
+ HasTemplateScope);
+ TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
+ if (HasTemplateScope) {
+ Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate);
+ ++CurTemplateDepthTracker;
+ }
+ bool HasClassScope = !Class.TopLevelClass;
+ ParseScope ClassScope(this, Scope::ClassScope | Scope::DeclScope,
+ HasClassScope);
+
+ for (LateParsedDeclaration *LPD : Class.LateParsedDeclarations)
+ LPD->ParseLexedPragmas();
+}
+
+void Parser::ParseLexedPragma(LateParsedPragma &LP) {
+ PP.EnterToken(Tok, /*IsReinject=*/true);
+ PP.EnterTokenStream(LP.toks(), /*DisableMacroExpansion=*/true,
+ /*IsReinject=*/true);
+
+ // Consume the previously pushed token.
+ ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
+ assert(Tok.isAnnotation() && "Expected annotation token.");
+ switch (Tok.getKind()) {
+ case tok::annot_pragma_openmp: {
+ AccessSpecifier AS = LP.getAccessSpecifier();
+ ParsedAttributesWithRange Attrs(AttrFactory);
+ (void)ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs);
+ break;
+ }
+ default:
+ llvm_unreachable("Unexpected token.");
+ }
+}
+
/// ConsumeAndStoreUntil - Consume and store the token at the passed token
/// container until the token 'T' is reached (which gets
/// consumed/stored too, if ConsumeFinalToken).
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index b248d7582d84..69a3ed9cbad7 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2014,6 +2014,9 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
return nullptr;
}
+ if (Tok.is(tok::kw_requires))
+ ParseTrailingRequiresClause(D);
+
// Save late-parsed attributes for now; they need to be parsed in the
// appropriate function scope after the function Decl has been constructed.
// These will be parsed in ParseFunctionDefinition or ParseLexedAttrList.
@@ -2165,6 +2168,12 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
ParseDeclarator(D);
if (!D.isInvalidType()) {
+ // C++2a [dcl.decl]p1
+ // init-declarator:
+ // declarator initializer[opt]
+ // declarator requires-clause
+ if (Tok.is(tok::kw_requires))
+ ParseTrailingRequiresClause(D);
Decl *ThisDecl = ParseDeclarationAfterDeclarator(D);
D.complete(ThisDecl);
if (ThisDecl)
@@ -2197,7 +2206,7 @@ bool Parser::ParseAsmAttributesAfterDeclarator(Declarator &D) {
// If a simple-asm-expr is present, parse it.
if (Tok.is(tok::kw_asm)) {
SourceLocation Loc;
- ExprResult AsmLabel(ParseSimpleAsm(&Loc));
+ ExprResult AsmLabel(ParseSimpleAsm(/*ForAsmLabel*/ true, &Loc));
if (AsmLabel.isInvalid()) {
SkipUntil(tok::semi, StopBeforeMatch);
return true;
@@ -2349,7 +2358,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
<< 0 /* default */;
else
- Diag(ConsumeToken(), diag::err_default_special_members);
+ Diag(ConsumeToken(), diag::err_default_special_members)
+ << getLangOpts().CPlusPlus2a;
} else {
InitializerScopeRAII InitScope(*this, D, ThisDecl);
@@ -3948,9 +3958,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
PrevSpec = Tok.getIdentifierInfo()->getNameStart();
isInvalid = true;
break;
- };
+ }
LLVM_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;
case tok::kw___private:
case tok::kw___global:
case tok::kw___local:
@@ -5106,6 +5121,13 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
return !DisambiguatingWithExpression ||
!isStartOfObjCClassMessageMissingOpenBracket();
+ // placeholder-type-specifier
+ case tok::annot_template_id: {
+ TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
+ return TemplateId->Kind == TNK_Concept_template &&
+ (NextToken().is(tok::kw_auto) || NextToken().is(tok::kw_decltype));
+ }
+
case tok::kw___declspec:
case tok::kw___cdecl:
case tok::kw___stdcall:
@@ -6026,6 +6048,22 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
PrototypeScope.Exit();
} else if (Tok.is(tok::l_square)) {
ParseBracketDeclarator(D);
+ } else if (Tok.is(tok::kw_requires) && D.hasGroupingParens()) {
+ // This declarator is declaring a function, but the requires clause is
+ // in the wrong place:
+ // void (f() requires true);
+ // instead of
+ // void f() requires true;
+ // or
+ // void (f()) requires true;
+ Diag(Tok, diag::err_requires_clause_inside_parens);
+ ConsumeToken();
+ ExprResult TrailingRequiresClause = Actions.CorrectDelayedTyposInExpr(
+ ParseConstraintLogicalOrExpression(/*IsTrailingRequiresClause=*/true));
+ if (TrailingRequiresClause.isUsable() && D.isFunctionDeclarator() &&
+ !D.hasTrailingRequiresClause())
+ // We're already ill-formed if we got here but we'll accept it anyway.
+ D.setTrailingRequiresClause(TrailingRequiresClause.get());
} else {
break;
}
@@ -6206,6 +6244,47 @@ void Parser::ParseParenDeclarator(Declarator &D) {
PrototypeScope.Exit();
}
+void Parser::InitCXXThisScopeForDeclaratorIfRelevant(
+ const Declarator &D, const DeclSpec &DS,
+ llvm::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
+ // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq
+ // and the end of the function-definition, member-declarator, or
+ // declarator.
+ // FIXME: currently, "static" case isn't handled correctly.
+ bool IsCXX11MemberFunction = getLangOpts().CPlusPlus11 &&
+ D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
+ (D.getContext() == DeclaratorContext::MemberContext
+ ? !D.getDeclSpec().isFriendSpecified()
+ : D.getContext() == DeclaratorContext::FileContext &&
+ D.getCXXScopeSpec().isValid() &&
+ Actions.CurContext->isRecord());
+ if (!IsCXX11MemberFunction)
+ return;
+
+ Qualifiers Q = Qualifiers::fromCVRUMask(DS.getTypeQualifiers());
+ if (D.getDeclSpec().hasConstexprSpecifier() && !getLangOpts().CPlusPlus14)
+ Q.addConst();
+ // FIXME: Collect C++ address spaces.
+ // If there are multiple different address spaces, the source is invalid.
+ // Carry on using the first addr space for the qualifiers of 'this'.
+ // The diagnostic will be given later while creating the function
+ // prototype for the method.
+ if (getLangOpts().OpenCLCPlusPlus) {
+ for (ParsedAttr &attr : DS.getAttributes()) {
+ LangAS ASIdx = attr.asOpenCLLangAS();
+ if (ASIdx != LangAS::Default) {
+ Q.addAddressSpace(ASIdx);
+ break;
+ }
+ }
+ }
+ ThisScope.emplace(Actions, dyn_cast<CXXRecordDecl>(Actions.CurContext), Q,
+ IsCXX11MemberFunction);
+}
+
/// ParseFunctionDeclarator - We are after the identifier and have parsed the
/// declarator D up to a paren, which indicates that we are parsing function
/// arguments.
@@ -6219,7 +6298,8 @@ void Parser::ParseParenDeclarator(Declarator &D) {
///
/// For C++, after the parameter-list, it also parses the cv-qualifier-seq[opt],
/// (C++11) ref-qualifier[opt], exception-specification[opt],
-/// (C++11) attribute-specifier-seq[opt], and (C++11) trailing-return-type[opt].
+/// (C++11) attribute-specifier-seq[opt], (C++11) trailing-return-type[opt] and
+/// (C++2a) the trailing requires-clause.
///
/// [C++11] exception-specification:
/// dynamic-exception-specification
@@ -6314,43 +6394,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
if (ParseRefQualifier(RefQualifierIsLValueRef, RefQualifierLoc))
EndLoc = RefQualifierLoc;
- // 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
- // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq
- // and the end of the function-definition, member-declarator, or
- // declarator.
- // FIXME: currently, "static" case isn't handled correctly.
- bool IsCXX11MemberFunction =
- getLangOpts().CPlusPlus11 &&
- D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
- (D.getContext() == DeclaratorContext::MemberContext
- ? !D.getDeclSpec().isFriendSpecified()
- : D.getContext() == DeclaratorContext::FileContext &&
- D.getCXXScopeSpec().isValid() &&
- Actions.CurContext->isRecord());
-
- Qualifiers Q = Qualifiers::fromCVRUMask(DS.getTypeQualifiers());
- if (D.getDeclSpec().hasConstexprSpecifier() && !getLangOpts().CPlusPlus14)
- Q.addConst();
- // FIXME: Collect C++ address spaces.
- // If there are multiple different address spaces, the source is invalid.
- // Carry on using the first addr space for the qualifiers of 'this'.
- // The diagnostic will be given later while creating the function
- // prototype for the method.
- if (getLangOpts().OpenCLCPlusPlus) {
- for (ParsedAttr &attr : DS.getAttributes()) {
- LangAS ASIdx = attr.asOpenCLLangAS();
- if (ASIdx != LangAS::Default) {
- Q.addAddressSpace(ASIdx);
- break;
- }
- }
- }
-
- Sema::CXXThisScopeRAII ThisScope(
- Actions, dyn_cast<CXXRecordDecl>(Actions.CurContext), Q,
- IsCXX11MemberFunction);
+ llvm::Optional<Sema::CXXThisScopeRAII> ThisScope;
+ InitCXXThisScopeForDeclaratorIfRelevant(D, DS, ThisScope);
// Parse exception-specification[opt].
bool Delayed = D.isFirstDeclarationOfMember() &&
@@ -6565,6 +6610,19 @@ void Parser::ParseParameterDeclarationClause(
ParsedAttributes &FirstArgAttrs,
SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo,
SourceLocation &EllipsisLoc) {
+
+ // Avoid exceeding the maximum function scope depth.
+ // See https://bugs.llvm.org/show_bug.cgi?id=19607
+ // Note Sema::ActOnParamDeclarator calls ParmVarDecl::setScopeInfo with
+ // getFunctionPrototypeDepth() - 1.
+ if (getCurScope()->getFunctionPrototypeDepth() - 1 >
+ ParmVarDecl::getMaxFunctionScopeDepth()) {
+ Diag(Tok.getLocation(), diag::err_function_scope_depth_exceeded)
+ << ParmVarDecl::getMaxFunctionScopeDepth();
+ cutOffParsing();
+ return;
+ }
+
do {
// FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq
// before deciding this was a parameter-declaration-clause.
@@ -6605,6 +6663,17 @@ void Parser::ParseParameterDeclarationClause(
// Parse GNU attributes, if present.
MaybeParseGNUAttributes(ParmDeclarator);
+ if (Tok.is(tok::kw_requires)) {
+ // User tried to define a requires clause in a parameter declaration,
+ // which is surely not a function declaration.
+ // void f(int (*g)(int, int) requires true);
+ Diag(Tok,
+ diag::err_requires_clause_on_declarator_not_declaring_a_function);
+ ConsumeToken();
+ Actions.CorrectDelayedTyposInExpr(
+ ParseConstraintLogicalOrExpression(/*IsTrailingRequiresClause=*/true));
+ }
+
// Remember this parsed parameter in ParamInfo.
IdentifierInfo *ParmII = ParmDeclarator.getIdentifier();
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index b98ce3e66292..081d4d8b1209 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -600,7 +600,10 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context,
if (ParseOptionalCXXScopeSpecifier(D.SS, nullptr, /*EnteringContext=*/false,
/*MayBePseudoDtor=*/nullptr,
/*IsTypename=*/false,
- /*LastII=*/&LastII))
+ /*LastII=*/&LastII,
+ /*OnlyNamespace=*/false,
+ /*InUsingDeclaration=*/true))
+
return true;
if (D.SS.isInvalid())
return true;
@@ -2298,6 +2301,7 @@ bool Parser::ParseCXXMemberDeclaratorBeforeInitializer(
LateParsedAttrList &LateParsedAttrs) {
// member-declarator:
// declarator pure-specifier[opt]
+ // declarator requires-clause
// declarator brace-or-equal-initializer[opt]
// identifier[opt] ':' constant-expression
if (Tok.isNot(tok::colon))
@@ -2311,6 +2315,8 @@ bool Parser::ParseCXXMemberDeclaratorBeforeInitializer(
BitfieldSize = ParseConstantExpression();
if (BitfieldSize.isInvalid())
SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
+ } else if (Tok.is(tok::kw_requires)) {
+ ParseTrailingRequiresClause(DeclaratorInfo);
} else {
ParseOptionalCXX11VirtSpecifierSeq(
VS, getCurrentClass().IsInterface,
@@ -2322,7 +2328,7 @@ bool Parser::ParseCXXMemberDeclaratorBeforeInitializer(
// If a simple-asm-expr is present, parse it.
if (Tok.is(tok::kw_asm)) {
SourceLocation Loc;
- ExprResult AsmLabel(ParseSimpleAsm(&Loc));
+ ExprResult AsmLabel(ParseSimpleAsm(/*ForAsmLabel*/ true, &Loc));
if (AsmLabel.isInvalid())
SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
@@ -2433,6 +2439,7 @@ void Parser::MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(
///
/// member-declarator:
/// declarator virt-specifier-seq[opt] pure-specifier[opt]
+/// [C++2a] declarator requires-clause
/// declarator constant-initializer[opt]
/// [C++11] declarator brace-or-equal-initializer[opt]
/// identifier[opt] ':' constant-expression
@@ -2666,6 +2673,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
SmallVector<Decl *, 8> DeclsInGroup;
ExprResult BitfieldSize;
+ ExprResult TrailingRequiresClause;
bool ExpectSemi = true;
// Parse the first declarator.
@@ -2978,7 +2986,8 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
Diag(Tok, diag::err_default_delete_in_multiple_declaration)
<< 0 /* default */;
else
- Diag(ConsumeToken(), diag::err_default_special_members);
+ Diag(ConsumeToken(), diag::err_default_special_members)
+ << getLangOpts().CPlusPlus2a;
return ExprError();
}
}
@@ -3132,8 +3141,8 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas(
}
case tok::annot_pragma_openmp:
- return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, AccessAttrs, TagType,
- TagDecl);
+ return ParseOpenMPDeclarativeDirectiveWithExtDecl(
+ AS, AccessAttrs, /*Delayed=*/true, TagType, TagDecl);
default:
if (tok::isPragmaAnnotation(Tok.getKind())) {
@@ -3351,6 +3360,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
// declarations and the lexed inline method definitions, along with any
// delayed attributes.
SourceLocation SavedPrevTokLocation = PrevTokLocation;
+ ParseLexedPragmas(getCurrentClass());
ParseLexedAttributes(getCurrentClass());
ParseLexedMethodDeclarations(getCurrentClass());
@@ -3363,7 +3373,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
// We've finished parsing everything, including default argument
// initializers.
- Actions.ActOnFinishCXXNonNestedClass(TagDecl);
+ Actions.ActOnFinishCXXNonNestedClass();
}
if (TagDecl)
@@ -3788,6 +3798,62 @@ TypeResult Parser::ParseTrailingReturnType(SourceRange &Range,
: DeclaratorContext::TrailingReturnContext);
}
+/// Parse a requires-clause as part of a function declaration.
+void Parser::ParseTrailingRequiresClause(Declarator &D) {
+ assert(Tok.is(tok::kw_requires) && "expected requires");
+
+ SourceLocation RequiresKWLoc = ConsumeToken();
+
+ ExprResult TrailingRequiresClause;
+ ParseScope ParamScope(this,
+ Scope::DeclScope |
+ Scope::FunctionDeclarationScope |
+ Scope::FunctionPrototypeScope);
+
+ Actions.ActOnStartTrailingRequiresClause(getCurScope(), D);
+
+ llvm::Optional<Sema::CXXThisScopeRAII> ThisScope;
+ InitCXXThisScopeForDeclaratorIfRelevant(D, D.getDeclSpec(), ThisScope);
+
+ TrailingRequiresClause =
+ ParseConstraintLogicalOrExpression(/*IsTrailingRequiresClause=*/true);
+
+ TrailingRequiresClause =
+ Actions.ActOnFinishTrailingRequiresClause(TrailingRequiresClause);
+
+ if (!D.isDeclarationOfFunction()) {
+ Diag(RequiresKWLoc,
+ diag::err_requires_clause_on_declarator_not_declaring_a_function);
+ return;
+ }
+
+ if (TrailingRequiresClause.isInvalid())
+ SkipUntil({tok::l_brace, tok::arrow, tok::kw_try, tok::comma, tok::colon},
+ StopAtSemi | StopBeforeMatch);
+ else
+ D.setTrailingRequiresClause(TrailingRequiresClause.get());
+
+ // Did the user swap the trailing return type and requires clause?
+ if (D.isFunctionDeclarator() && Tok.is(tok::arrow) &&
+ D.getDeclSpec().getTypeSpecType() == TST_auto) {
+ SourceLocation ArrowLoc = Tok.getLocation();
+ SourceRange Range;
+ TypeResult TrailingReturnType =
+ ParseTrailingReturnType(Range, /*MayBeFollowedByDirectInit=*/false);
+
+ if (!TrailingReturnType.isInvalid()) {
+ Diag(ArrowLoc,
+ diag::err_requires_clause_must_appear_after_trailing_return)
+ << Range;
+ auto &FunctionChunk = D.getFunctionTypeInfo();
+ FunctionChunk.HasTrailingReturnType = TrailingReturnType.isUsable();
+ FunctionChunk.TrailingReturnType = TrailingReturnType.get();
+ } else
+ SkipUntil({tok::equal, tok::l_brace, tok::arrow, tok::kw_try, tok::comma},
+ StopAtSemi | StopBeforeMatch);
+ }
+}
+
/// We have just started parsing the definition of a new class,
/// so push that class onto our stack of classes that is currently
/// being parsed.
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index b74a95a3cd4b..1442df046bb9 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -22,6 +22,7 @@
#include "clang/Parse/Parser.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Parse/RAIIObjectsForParser.h"
#include "clang/Sema/DeclSpec.h"
@@ -145,7 +146,7 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) {
// Silence extension warnings in the sub-expression
ExtensionRAIIObject O(Diags);
- LHS = ParseCastExpression(false);
+ LHS = ParseCastExpression(AnyCastExpr);
}
if (!LHS.isInvalid())
@@ -169,7 +170,7 @@ ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) {
if (Tok.is(tok::kw_co_yield))
return ParseCoyieldExpression();
- ExprResult LHS = ParseCastExpression(/*isUnaryExpression=*/false,
+ ExprResult LHS = ParseCastExpression(AnyCastExpr,
/*isAddressOfOperand=*/false,
isTypeCast);
return ParseRHSOfBinaryExpression(LHS, prec::Assignment);
@@ -202,7 +203,7 @@ Parser::ParseConstantExpressionInExprEvalContext(TypeCastState isTypeCast) {
Sema::ExpressionEvaluationContext::ConstantEvaluated &&
"Call this function only if your ExpressionEvaluationContext is "
"already ConstantEvaluated");
- ExprResult LHS(ParseCastExpression(false, false, isTypeCast));
+ ExprResult LHS(ParseCastExpression(AnyCastExpr, false, isTypeCast));
ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
return Actions.ActOnConstantExpression(Res);
}
@@ -220,7 +221,7 @@ ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) {
ExprResult Parser::ParseCaseExpression(SourceLocation CaseLoc) {
EnterExpressionEvaluationContext ConstantEvaluated(
Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
- ExprResult LHS(ParseCastExpression(false, false, NotTypeCast));
+ ExprResult LHS(ParseCastExpression(AnyCastExpr, false, NotTypeCast));
ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
return Actions.ActOnCaseExpr(CaseLoc, Res);
}
@@ -234,13 +235,141 @@ ExprResult Parser::ParseCaseExpression(SourceLocation CaseLoc) {
ExprResult Parser::ParseConstraintExpression() {
EnterExpressionEvaluationContext ConstantEvaluated(
Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
- ExprResult LHS(ParseCastExpression(/*isUnaryExpression=*/false));
+ ExprResult LHS(ParseCastExpression(AnyCastExpr));
ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::LogicalOr));
- if (Res.isUsable() && !Actions.CheckConstraintExpression(Res.get()))
+ if (Res.isUsable() && !Actions.CheckConstraintExpression(Res.get())) {
+ Actions.CorrectDelayedTyposInExpr(Res);
return ExprError();
+ }
return Res;
}
+/// \brief Parse a constraint-logical-and-expression.
+///
+/// \verbatim
+/// C++2a[temp.constr.decl]p1
+/// constraint-logical-and-expression:
+/// primary-expression
+/// constraint-logical-and-expression '&&' primary-expression
+///
+/// \endverbatim
+ExprResult
+Parser::ParseConstraintLogicalAndExpression(bool IsTrailingRequiresClause) {
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ bool NotPrimaryExpression = false;
+ auto ParsePrimary = [&] () {
+ ExprResult E = ParseCastExpression(PrimaryExprOnly,
+ /*isAddressOfOperand=*/false,
+ /*isTypeCast=*/NotTypeCast,
+ /*isVectorLiteral=*/false,
+ &NotPrimaryExpression);
+ if (E.isInvalid())
+ return ExprError();
+ auto RecoverFromNonPrimary = [&] (ExprResult E, bool Note) {
+ E = ParsePostfixExpressionSuffix(E);
+ // Use InclusiveOr, the precedence just after '&&' to not parse the
+ // next arguments to the logical and.
+ E = ParseRHSOfBinaryExpression(E, prec::InclusiveOr);
+ if (!E.isInvalid())
+ Diag(E.get()->getExprLoc(),
+ Note
+ ? diag::note_unparenthesized_non_primary_expr_in_requires_clause
+ : diag::err_unparenthesized_non_primary_expr_in_requires_clause)
+ << FixItHint::CreateInsertion(E.get()->getBeginLoc(), "(")
+ << FixItHint::CreateInsertion(
+ PP.getLocForEndOfToken(E.get()->getEndLoc()), ")")
+ << E.get()->getSourceRange();
+ return E;
+ };
+
+ if (NotPrimaryExpression ||
+ // Check if the following tokens must be a part of a non-primary
+ // expression
+ getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
+ /*CPlusPlus11=*/true) > prec::LogicalAnd ||
+ // Postfix operators other than '(' (which will be checked for in
+ // CheckConstraintExpression).
+ Tok.isOneOf(tok::period, tok::plusplus, tok::minusminus) ||
+ (Tok.is(tok::l_square) && !NextToken().is(tok::l_square))) {
+ E = RecoverFromNonPrimary(E, /*Note=*/false);
+ if (E.isInvalid())
+ return ExprError();
+ NotPrimaryExpression = false;
+ }
+ bool PossibleNonPrimary;
+ bool IsConstraintExpr =
+ Actions.CheckConstraintExpression(E.get(), Tok, &PossibleNonPrimary,
+ IsTrailingRequiresClause);
+ if (!IsConstraintExpr || PossibleNonPrimary) {
+ // Atomic constraint might be an unparenthesized non-primary expression
+ // (such as a binary operator), in which case we might get here (e.g. in
+ // 'requires 0 + 1 && true' we would now be at '+', and parse and ignore
+ // the rest of the addition expression). Try to parse the rest of it here.
+ if (PossibleNonPrimary)
+ E = RecoverFromNonPrimary(E, /*Note=*/!IsConstraintExpr);
+ Actions.CorrectDelayedTyposInExpr(E);
+ return ExprError();
+ }
+ return E;
+ };
+ ExprResult LHS = ParsePrimary();
+ if (LHS.isInvalid())
+ return ExprError();
+ while (Tok.is(tok::ampamp)) {
+ SourceLocation LogicalAndLoc = ConsumeToken();
+ ExprResult RHS = ParsePrimary();
+ if (RHS.isInvalid()) {
+ Actions.CorrectDelayedTyposInExpr(LHS);
+ return ExprError();
+ }
+ ExprResult Op = Actions.ActOnBinOp(getCurScope(), LogicalAndLoc,
+ tok::ampamp, LHS.get(), RHS.get());
+ if (!Op.isUsable()) {
+ Actions.CorrectDelayedTyposInExpr(RHS);
+ Actions.CorrectDelayedTyposInExpr(LHS);
+ return ExprError();
+ }
+ LHS = Op;
+ }
+ return LHS;
+}
+
+/// \brief Parse a constraint-logical-or-expression.
+///
+/// \verbatim
+/// C++2a[temp.constr.decl]p1
+/// constraint-logical-or-expression:
+/// constraint-logical-and-expression
+/// constraint-logical-or-expression '||'
+/// constraint-logical-and-expression
+///
+/// \endverbatim
+ExprResult
+Parser::ParseConstraintLogicalOrExpression(bool IsTrailingRequiresClause) {
+ ExprResult LHS(ParseConstraintLogicalAndExpression(IsTrailingRequiresClause));
+ if (!LHS.isUsable())
+ return ExprError();
+ while (Tok.is(tok::pipepipe)) {
+ SourceLocation LogicalOrLoc = ConsumeToken();
+ ExprResult RHS =
+ ParseConstraintLogicalAndExpression(IsTrailingRequiresClause);
+ if (!RHS.isUsable()) {
+ Actions.CorrectDelayedTyposInExpr(LHS);
+ return ExprError();
+ }
+ ExprResult Op = Actions.ActOnBinOp(getCurScope(), LogicalOrLoc,
+ tok::pipepipe, LHS.get(), RHS.get());
+ if (!Op.isUsable()) {
+ Actions.CorrectDelayedTyposInExpr(RHS);
+ Actions.CorrectDelayedTyposInExpr(LHS);
+ return ExprError();
+ }
+ LHS = Op;
+ }
+ return LHS;
+}
+
bool Parser::isNotExpressionStart() {
tok::TokenKind K = Tok.getKind();
if (K == tok::l_brace || K == tok::r_brace ||
@@ -414,7 +543,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
} else if (getLangOpts().CPlusPlus && NextTokPrec <= prec::Conditional)
RHS = ParseAssignmentExpression();
else
- RHS = ParseCastExpression(false);
+ RHS = ParseCastExpression(AnyCastExpr);
if (RHS.isInvalid()) {
// FIXME: Errors generated by the delayed typo correction should be
@@ -519,22 +648,24 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
}
}
-/// Parse a cast-expression, or, if \p isUnaryExpression is true,
-/// parse a unary-expression.
+/// Parse a cast-expression, unary-expression or primary-expression, based
+/// on \p ExprType.
///
/// \p isAddressOfOperand exists because an id-expression that is the
/// operand of address-of gets special treatment due to member pointers.
///
-ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
+ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
bool isAddressOfOperand,
TypeCastState isTypeCast,
- bool isVectorLiteral) {
+ bool isVectorLiteral,
+ bool *NotPrimaryExpression) {
bool NotCastExpr;
- ExprResult Res = ParseCastExpression(isUnaryExpression,
+ ExprResult Res = ParseCastExpression(ParseKind,
isAddressOfOperand,
NotCastExpr,
isTypeCast,
- isVectorLiteral);
+ isVectorLiteral,
+ NotPrimaryExpression);
if (NotCastExpr)
Diag(Tok, diag::err_expected_expression);
return Res;
@@ -759,11 +890,12 @@ class CastExpressionIdValidator final : public CorrectionCandidateCallback {
/// '__is_rvalue_expr'
/// \endverbatim
///
-ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
+ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
bool isAddressOfOperand,
bool &NotCastExpr,
TypeCastState isTypeCast,
- bool isVectorLiteral) {
+ bool isVectorLiteral,
+ bool *NotPrimaryExpression) {
ExprResult Res;
tok::TokenKind SavedKind = Tok.getKind();
auto SavedType = PreferredType;
@@ -782,11 +914,21 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// ParsePostfixExpressionSuffix.
switch (SavedKind) {
case tok::l_paren: {
- // If this expression is limited to being a unary-expression, the parent can
+ // If this expression is limited to being a unary-expression, the paren can
// not start a cast expression.
- ParenParseOption ParenExprType =
- (isUnaryExpression && !getLangOpts().CPlusPlus) ? CompoundLiteral
- : CastExpr;
+ ParenParseOption ParenExprType;
+ switch (ParseKind) {
+ case CastParseKind::UnaryExprOnly:
+ if (!getLangOpts().CPlusPlus)
+ ParenExprType = CompoundLiteral;
+ LLVM_FALLTHROUGH;
+ case CastParseKind::AnyCastExpr:
+ ParenExprType = ParenParseOption::CastExpr;
+ break;
+ case CastParseKind::PrimaryExprOnly:
+ ParenExprType = FoldExpr;
+ break;
+ }
ParsedType CastTy;
SourceLocation RParenLoc;
Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/,
@@ -861,8 +1003,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
if (TryAnnotateTypeOrScopeToken())
return ExprError();
assert(Tok.isNot(tok::kw_decltype) && Tok.isNot(tok::kw___super));
- return ParseCastExpression(isUnaryExpression, isAddressOfOperand);
-
+ return ParseCastExpression(ParseKind, isAddressOfOperand, isTypeCast,
+ isVectorLiteral, NotPrimaryExpression);
+
case tok::identifier: { // primary-expression: identifier
// unqualified-id: identifier
// constant: enumeration-constant
@@ -949,8 +1092,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
= RevertibleTypeTraits.find(II);
if (Known != RevertibleTypeTraits.end()) {
Tok.setKind(Known->second);
- return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
- NotCastExpr, isTypeCast);
+ return ParseCastExpression(ParseKind, isAddressOfOperand,
+ NotCastExpr, isTypeCast,
+ isVectorLiteral, NotPrimaryExpression);
}
}
@@ -961,7 +1105,10 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
if (TryAnnotateTypeOrScopeToken())
return ExprError();
if (!Tok.is(tok::identifier))
- return ParseCastExpression(isUnaryExpression, isAddressOfOperand);
+ return ParseCastExpression(ParseKind, isAddressOfOperand,
+ NotCastExpr, isTypeCast,
+ isVectorLiteral,
+ NotPrimaryExpression);
}
}
@@ -1076,8 +1223,10 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
Tok.is(tok::r_paren) ? nullptr : &Replacement);
if (!Res.isInvalid() && Res.isUnset()) {
UnconsumeToken(Replacement);
- return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
- NotCastExpr, isTypeCast);
+ return ParseCastExpression(ParseKind, isAddressOfOperand,
+ NotCastExpr, isTypeCast,
+ /*isVectorLiteral=*/false,
+ NotPrimaryExpression);
}
if (!Res.isInvalid() && Tok.is(tok::less))
checkPotentialAngleBracket(Res);
@@ -1122,12 +1271,16 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw___builtin_FILE:
case tok::kw___builtin_FUNCTION:
case tok::kw___builtin_LINE:
+ if (NotPrimaryExpression)
+ *NotPrimaryExpression = true;
return ParseBuiltinPrimaryExpression();
case tok::kw___null:
return Actions.ActOnGNUNullExpr(ConsumeToken());
case tok::plusplus: // unary-expression: '++' unary-expression [C99]
case tok::minusminus: { // unary-expression: '--' unary-expression [C99]
+ if (NotPrimaryExpression)
+ *NotPrimaryExpression = true;
// C++ [expr.unary] has:
// unary-expression:
// ++ cast-expression
@@ -1140,7 +1293,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// One special case is implicitly handled here: if the preceding tokens are
// an ambiguous cast expression, such as "(T())++", then we recurse to
// determine whether the '++' is prefix or postfix.
- Res = ParseCastExpression(!getLangOpts().CPlusPlus,
+ Res = ParseCastExpression(getLangOpts().CPlusPlus ?
+ UnaryExprOnly : AnyCastExpr,
/*isAddressOfOperand*/false, NotCastExpr,
NotTypeCast);
if (NotCastExpr) {
@@ -1156,10 +1310,12 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
return Res;
}
case tok::amp: { // unary-expression: '&' cast-expression
+ if (NotPrimaryExpression)
+ *NotPrimaryExpression = true;
// Special treatment because of member pointers
SourceLocation SavedLoc = ConsumeToken();
PreferredType.enterUnary(Actions, Tok.getLocation(), tok::amp, SavedLoc);
- Res = ParseCastExpression(false, true);
+ Res = ParseCastExpression(AnyCastExpr, true);
if (!Res.isInvalid())
Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get());
return Res;
@@ -1172,17 +1328,21 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::exclaim: // unary-expression: '!' cast-expression
case tok::kw___real: // unary-expression: '__real' cast-expression [GNU]
case tok::kw___imag: { // unary-expression: '__imag' cast-expression [GNU]
+ if (NotPrimaryExpression)
+ *NotPrimaryExpression = true;
SourceLocation SavedLoc = ConsumeToken();
PreferredType.enterUnary(Actions, Tok.getLocation(), SavedKind, SavedLoc);
- Res = ParseCastExpression(false);
+ Res = ParseCastExpression(AnyCastExpr);
if (!Res.isInvalid())
Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get());
return Res;
}
case tok::kw_co_await: { // unary-expression: 'co_await' cast-expression
+ if (NotPrimaryExpression)
+ *NotPrimaryExpression = true;
SourceLocation CoawaitLoc = ConsumeToken();
- Res = ParseCastExpression(false);
+ Res = ParseCastExpression(AnyCastExpr);
if (!Res.isInvalid())
Res = Actions.ActOnCoawaitExpr(getCurScope(), CoawaitLoc, Res.get());
return Res;
@@ -1190,9 +1350,11 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw___extension__:{//unary-expression:'__extension__' cast-expr [GNU]
// __extension__ silences extension warnings in the subexpression.
+ if (NotPrimaryExpression)
+ *NotPrimaryExpression = true;
ExtensionRAIIObject O(Diags); // Use RAII to do this.
SourceLocation SavedLoc = ConsumeToken();
- Res = ParseCastExpression(false);
+ Res = ParseCastExpression(AnyCastExpr);
if (!Res.isInvalid())
Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get());
return Res;
@@ -1209,8 +1371,12 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw_vec_step: // unary-expression: OpenCL 'vec_step' expression
// unary-expression: '__builtin_omp_required_simd_align' '(' type-name ')'
case tok::kw___builtin_omp_required_simd_align:
+ if (NotPrimaryExpression)
+ *NotPrimaryExpression = true;
return ParseUnaryExprOrTypeTraitExpression();
case tok::ampamp: { // unary-expression: '&&' identifier
+ if (NotPrimaryExpression)
+ *NotPrimaryExpression = true;
SourceLocation AmpAmpLoc = ConsumeToken();
if (Tok.isNot(tok::identifier))
return ExprError(Diag(Tok, diag::err_expected) << tok::identifier);
@@ -1229,15 +1395,23 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw_dynamic_cast:
case tok::kw_reinterpret_cast:
case tok::kw_static_cast:
+ if (NotPrimaryExpression)
+ *NotPrimaryExpression = true;
Res = ParseCXXCasts();
break;
case tok::kw___builtin_bit_cast:
+ if (NotPrimaryExpression)
+ *NotPrimaryExpression = true;
Res = ParseBuiltinBitCast();
break;
case tok::kw_typeid:
+ if (NotPrimaryExpression)
+ *NotPrimaryExpression = true;
Res = ParseCXXTypeid();
break;
case tok::kw___uuidof:
+ if (NotPrimaryExpression)
+ *NotPrimaryExpression = true;
Res = ParseCXXUuidof();
break;
case tok::kw_this:
@@ -1302,6 +1476,10 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
return ExprError();
}
+ // Everything henceforth is a postfix-expression.
+ if (NotPrimaryExpression)
+ *NotPrimaryExpression = true;
+
if (SavedKind == tok::kw_typename) {
// postfix-expression: typename-specifier '(' expression-list[opt] ')'
// typename-specifier braced-init-list
@@ -1338,8 +1516,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
if (TryAnnotateTypeOrScopeToken())
return ExprError();
if (!Tok.is(tok::annot_cxxscope))
- return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
- NotCastExpr, isTypeCast);
+ return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr,
+ isTypeCast, isVectorLiteral,
+ NotPrimaryExpression);
Token Next = NextToken();
if (Next.is(tok::annot_template_id)) {
@@ -1352,8 +1531,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
ParseOptionalCXXScopeSpecifier(SS, nullptr,
/*EnteringContext=*/false);
AnnotateTemplateIdTokenAsType();
- return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
- NotCastExpr, isTypeCast);
+ return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr,
+ isTypeCast, isVectorLiteral,
+ NotPrimaryExpression);
}
}
@@ -1369,8 +1549,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// translate it into a type and continue parsing as a cast
// expression.
AnnotateTemplateIdTokenAsType();
- return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
- NotCastExpr, isTypeCast);
+ return ParseCastExpression(ParseKind, isAddressOfOperand,
+ NotCastExpr, isTypeCast, isVectorLiteral,
+ NotPrimaryExpression);
}
// Fall through to treat the template-id as an id-expression.
@@ -1387,15 +1568,22 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
if (TryAnnotateTypeOrScopeToken())
return ExprError();
if (!Tok.is(tok::coloncolon))
- return ParseCastExpression(isUnaryExpression, isAddressOfOperand);
+ return ParseCastExpression(ParseKind, isAddressOfOperand, isTypeCast,
+ isVectorLiteral, NotPrimaryExpression);
// ::new -> [C++] new-expression
// ::delete -> [C++] delete-expression
SourceLocation CCLoc = ConsumeToken();
- if (Tok.is(tok::kw_new))
+ if (Tok.is(tok::kw_new)) {
+ if (NotPrimaryExpression)
+ *NotPrimaryExpression = true;
return ParseCXXNewExpression(true, CCLoc);
- if (Tok.is(tok::kw_delete))
+ }
+ if (Tok.is(tok::kw_delete)) {
+ if (NotPrimaryExpression)
+ *NotPrimaryExpression = true;
return ParseCXXDeleteExpression(true, CCLoc);
+ }
// This is not a type name or scope specifier, it is an invalid expression.
Diag(CCLoc, diag::err_expected_expression);
@@ -1403,12 +1591,18 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
}
case tok::kw_new: // [C++] new-expression
+ if (NotPrimaryExpression)
+ *NotPrimaryExpression = true;
return ParseCXXNewExpression(false, Tok.getLocation());
case tok::kw_delete: // [C++] delete-expression
+ if (NotPrimaryExpression)
+ *NotPrimaryExpression = true;
return ParseCXXDeleteExpression(false, Tok.getLocation());
case tok::kw_noexcept: { // [C++0x] 'noexcept' '(' expression ')'
+ if (NotPrimaryExpression)
+ *NotPrimaryExpression = true;
Diag(Tok, diag::warn_cxx98_compat_noexcept_expr);
SourceLocation KeyLoc = ConsumeToken();
BalancedDelimiterTracker T(*this, tok::l_paren);
@@ -1437,13 +1631,19 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw___array_rank:
case tok::kw___array_extent:
+ if (NotPrimaryExpression)
+ *NotPrimaryExpression = true;
return ParseArrayTypeTrait();
case tok::kw___is_lvalue_expr:
case tok::kw___is_rvalue_expr:
+ if (NotPrimaryExpression)
+ *NotPrimaryExpression = true;
return ParseExpressionTrait();
case tok::at: {
+ if (NotPrimaryExpression)
+ *NotPrimaryExpression = true;
SourceLocation AtLoc = ConsumeToken();
return ParseObjCAtExpression(AtLoc);
}
@@ -1465,8 +1665,13 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// expression, or we have something that doesn't appear to be a lambda.
// If we're in the last case, we fall back to ParseObjCMessageExpression.
Res = TryParseLambdaExpression();
- if (!Res.isInvalid() && !Res.get())
+ if (!Res.isInvalid() && !Res.get()) {
+ // We assume Objective-C++ message expressions are not
+ // primary-expressions.
+ if (NotPrimaryExpression)
+ *NotPrimaryExpression = true;
Res = ParseObjCMessageExpression();
+ }
break;
}
Res = ParseLambdaExpression();
@@ -1486,6 +1691,11 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// are compiling for OpenCL, we need to return an error as this implies
// that the address of the function is being taken, which is illegal in CL.
+ if (ParseKind == PrimaryExprOnly)
+ // This is strictly a primary-expression - no postfix-expr pieces should be
+ // parsed.
+ return Res;
+
// These can be followed by postfix-expr pieces.
PreferredType = SavedType;
Res = ParsePostfixExpressionSuffix(Res);
@@ -1929,7 +2139,7 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
return ExprError();
}
- Operand = ParseCastExpression(true/*isUnaryExpression*/);
+ Operand = ParseCastExpression(UnaryExprOnly);
} else {
// If it starts with a '(', we know that it is either a parenthesized
// type-name, or it is a unary-expression that starts with a compound
@@ -2474,8 +2684,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
RParenLoc = T.getCloseLocation();
PreferredType.enterTypeCast(Tok.getLocation(), Ty.get().get());
- ExprResult SubExpr = ParseCastExpression(/*isUnaryExpression=*/false);
-
+ ExprResult SubExpr = ParseCastExpression(AnyCastExpr);
+
if (Ty.isInvalid() || SubExpr.isInvalid())
return ExprError();
@@ -2555,7 +2765,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
// Parse the cast-expression that follows it next.
// isVectorLiteral = true will make sure we don't parse any
// Postfix expression yet
- Result = ParseCastExpression(/*isUnaryExpression=*/false,
+ Result = ParseCastExpression(/*isUnaryExpression=*/AnyCastExpr,
/*isAddressOfOperand=*/false,
/*isTypeCast=*/IsTypeCast,
/*isVectorLiteral=*/true);
@@ -2607,7 +2817,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
PreferredType.enterTypeCast(Tok.getLocation(), CastTy.get());
// Parse the cast-expression that follows it next.
// TODO: For cast expression with CastTy.
- Result = ParseCastExpression(/*isUnaryExpression=*/false,
+ Result = ParseCastExpression(/*isUnaryExpression=*/AnyCastExpr,
/*isAddressOfOperand=*/false,
/*isTypeCast=*/IsTypeCast);
if (!Result.isInvalid()) {
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index a064e4b17587..e685d5ea8a9c 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -142,6 +142,7 @@ void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType,
///
/// \param OnlyNamespace If true, only considers namespaces in lookup.
///
+///
/// \returns true if there was an error parsing a scope specifier
bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
ParsedType ObjectType,
@@ -149,7 +150,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
bool *MayBePseudoDestructor,
bool IsTypename,
IdentifierInfo **LastII,
- bool OnlyNamespace) {
+ bool OnlyNamespace,
+ bool InUsingDeclaration) {
assert(getLangOpts().CPlusPlus &&
"Call sites of this function should be guarded by checking for C++");
@@ -240,7 +242,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// Code completion for a nested-name-specifier, where the code
// completion token follows the '::'.
Actions.CodeCompleteQualifiedId(getCurScope(), SS, EnteringContext,
- ObjectType.get(),
+ InUsingDeclaration, ObjectType.get(),
SavedType.get(SS.getBeginLoc()));
// Include code completion token into the range of the scope otherwise
// when we try to annotate the scope tokens the dangling code completion
@@ -479,6 +481,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// nested-name-specifier:
// type-name '<'
if (Next.is(tok::less)) {
+
TemplateTy Template;
UnqualifiedId TemplateName;
TemplateName.setIdentifier(&II, Tok.getLocation());
@@ -503,7 +506,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// template-id to be translated into a type annotation,
// because some clients (e.g., the parsing of class template
// specializations) still want to see the original template-id
- // token.
+ // token, and it might not be a type at all (e.g. a concept name in a
+ // type-constraint).
ConsumeToken();
if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(),
TemplateName, false))
@@ -1355,6 +1359,13 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
// Parse attribute-specifier[opt].
MaybeParseCXX11Attributes(Attr, &DeclEndLoc);
+ // Parse OpenCL addr space attribute.
+ if (Tok.isOneOf(tok::kw___private, tok::kw___global, tok::kw___local,
+ tok::kw___constant, tok::kw___generic)) {
+ ParseOpenCLQualifiers(DS.getAttributes());
+ ConsumeToken();
+ }
+
SourceLocation FunLocalRangeEnd = DeclEndLoc;
// Parse trailing-return-type[opt].
@@ -1367,10 +1378,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
DeclEndLoc = Range.getEnd();
}
- PrototypeScope.Exit();
-
- WarnIfHasCUDATargetAttr();
-
SourceLocation NoLoc;
D.AddTypeInfo(DeclaratorChunk::getFunction(
/*HasProto=*/true,
@@ -1383,21 +1390,38 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr,
/*ExceptionSpecTokens*/ nullptr,
/*DeclsInPrototype=*/None, LParenLoc, FunLocalRangeEnd, D,
- TrailingReturnType),
+ TrailingReturnType, &DS),
std::move(Attr), DeclEndLoc);
+
+ // Parse requires-clause[opt].
+ if (Tok.is(tok::kw_requires))
+ ParseTrailingRequiresClause(D);
+
+ PrototypeScope.Exit();
+
+ WarnIfHasCUDATargetAttr();
} 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___private, tok::kw___global, tok::kw___local,
+ tok::kw___constant, tok::kw___generic,
+ tok::kw_requires) ||
(Tok.is(tok::l_square) && NextToken().is(tok::l_square))) {
// It's common to forget that one needs '()' before 'mutable', an attribute
- // specifier, or the result type. Deal with this.
+ // specifier, the result type, or the requires clause. Deal with this.
unsigned TokKind = 0;
switch (Tok.getKind()) {
case tok::kw_mutable: TokKind = 0; break;
case tok::arrow: TokKind = 1; break;
case tok::kw___attribute:
+ case tok::kw___private:
+ case tok::kw___global:
+ case tok::kw___local:
+ case tok::kw___constant:
+ case tok::kw___generic:
case tok::l_square: TokKind = 2; break;
case tok::kw_constexpr: TokKind = 3; break;
case tok::kw_consteval: TokKind = 4; break;
+ case tok::kw_requires: TokKind = 5; break;
default: llvm_unreachable("Unknown token kind");
}
@@ -1429,8 +1453,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
DeclEndLoc = Range.getEnd();
}
- WarnIfHasCUDATargetAttr();
-
SourceLocation NoLoc;
D.AddTypeInfo(DeclaratorChunk::getFunction(
/*HasProto=*/true,
@@ -1451,6 +1473,12 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
/*DeclsInPrototype=*/None, DeclLoc, DeclEndLoc, D,
TrailingReturnType),
std::move(Attr), DeclEndLoc);
+
+ // Parse the requires-clause, if present.
+ if (Tok.is(tok::kw_requires))
+ ParseTrailingRequiresClause(D);
+
+ WarnIfHasCUDATargetAttr();
}
// FIXME: Rename BlockScope -> ClosureScope if we decide to continue using
@@ -1851,9 +1879,11 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
CommaLocsTy CommaLocs;
auto RunSignatureHelp = [&]() {
- QualType PreferredType = Actions.ProduceConstructorSignatureHelp(
- getCurScope(), TypeRep.get()->getCanonicalTypeInternal(),
- DS.getEndLoc(), Exprs, T.getOpenLocation());
+ QualType PreferredType;
+ if (TypeRep)
+ PreferredType = Actions.ProduceConstructorSignatureHelp(
+ getCurScope(), TypeRep.get()->getCanonicalTypeInternal(),
+ DS.getEndLoc(), Exprs, T.getOpenLocation());
CalledSignatureHelp = true;
return PreferredType;
};
@@ -2004,7 +2034,7 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt,
// simple-asm-expr[opt]
if (Tok.is(tok::kw_asm)) {
SourceLocation Loc;
- ExprResult AsmLabel(ParseSimpleAsm(&Loc));
+ ExprResult AsmLabel(ParseSimpleAsm(/*ForAsmLabel*/ true, &Loc));
if (AsmLabel.isInvalid()) {
SkipUntil(tok::semi, StopAtSemi);
return Sema::ConditionError();
@@ -3027,6 +3057,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
auto RunSignatureHelp = [&]() {
ParsedType TypeRep =
Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get();
+ assert(TypeRep && "invalid types should be handled before");
QualType PreferredType = Actions.ProduceConstructorSignatureHelp(
getCurScope(), TypeRep.get()->getCanonicalTypeInternal(),
DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen);
@@ -3224,7 +3255,7 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) {
return ExprError();
}
- ExprResult Operand(ParseCastExpression(false));
+ ExprResult Operand(ParseCastExpression(AnyCastExpr));
if (Operand.isInvalid())
return Operand;
@@ -3455,7 +3486,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
// If it is not a cast-expression, NotCastExpr will be true and no token
// will be consumed.
ColonProt.restore();
- Result = ParseCastExpression(false/*isUnaryExpression*/,
+ Result = ParseCastExpression(AnyCastExpr,
false/*isAddressofOperand*/,
NotCastExpr,
// type-id has priority.
diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp
index 42d6221a7333..efcef6d3b123 100644
--- a/clang/lib/Parse/ParseObjc.cpp
+++ b/clang/lib/Parse/ParseObjc.cpp
@@ -822,6 +822,7 @@ static void diagnoseRedundantPropertyNullability(Parser &P,
/// property-attribute:
/// getter '=' identifier
/// setter '=' identifier ':'
+/// direct
/// readonly
/// readwrite
/// assign
@@ -954,6 +955,8 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_null_resettable);
} else if (II->isStr("class")) {
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_class);
+ } else if (II->isStr("direct")) {
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_direct);
} else {
Diag(AttrName, diag::err_objc_expected_property_attr) << II;
SkipUntil(tok::r_paren, StopAtSemi);
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 91fe10e667db..1095919baa7d 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -12,6 +12,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/StmtOpenMP.h"
+#include "clang/Basic/OpenMPKinds.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
#include "clang/Parse/RAIIObjectsForParser.h"
@@ -20,6 +21,7 @@
#include "llvm/ADT/UniqueVector.h"
using namespace clang;
+using namespace llvm::omp;
//===----------------------------------------------------------------------===//
// OpenMP declarative directives.
@@ -27,7 +29,7 @@ using namespace clang;
namespace {
enum OpenMPDirectiveKindEx {
- OMPD_cancellation = OMPD_unknown + 1,
+ OMPD_cancellation = unsigned(OMPD_unknown) + 1,
OMPD_data,
OMPD_declare,
OMPD_end,
@@ -44,7 +46,20 @@ enum OpenMPDirectiveKindEx {
OMPD_target_teams_distribute_parallel,
OMPD_mapper,
OMPD_variant,
- OMPD_parallel_master,
+};
+
+// Helper to unify the enum class OpenMPDirectiveKind with its extension
+// the OpenMPDirectiveKindEx enum which allows to use them together as if they
+// are unsigned values.
+struct OpenMPDirectiveKindExWrapper {
+ OpenMPDirectiveKindExWrapper(unsigned Value) : Value(Value) {}
+ OpenMPDirectiveKindExWrapper(OpenMPDirectiveKind DK) : Value(unsigned(DK)) {}
+ bool operator==(OpenMPDirectiveKind V) const { return Value == unsigned(V); }
+ bool operator!=(OpenMPDirectiveKind V) const { return Value != unsigned(V); }
+ bool operator<(OpenMPDirectiveKind V) const { return Value < unsigned(V); }
+ operator unsigned() const { return Value; }
+ operator OpenMPDirectiveKind() const { return OpenMPDirectiveKind(Value); }
+ unsigned Value;
};
class DeclDirectiveListParserHelper final {
@@ -68,11 +83,11 @@ public:
// Map token string to extended OMP token kind that are
// OpenMPDirectiveKind + OpenMPDirectiveKindEx.
static unsigned getOpenMPDirectiveKindEx(StringRef S) {
- auto DKind = getOpenMPDirectiveKind(S);
+ OpenMPDirectiveKindExWrapper DKind = getOpenMPDirectiveKind(S);
if (DKind != OMPD_unknown)
return DKind;
- return llvm::StringSwitch<unsigned>(S)
+ return llvm::StringSwitch<OpenMPDirectiveKindExWrapper>(S)
.Case("cancellation", OMPD_cancellation)
.Case("data", OMPD_data)
.Case("declare", OMPD_declare)
@@ -87,11 +102,11 @@ static unsigned getOpenMPDirectiveKindEx(StringRef S) {
.Default(OMPD_unknown);
}
-static OpenMPDirectiveKind parseOpenMPDirectiveKind(Parser &P) {
+static OpenMPDirectiveKindExWrapper parseOpenMPDirectiveKind(Parser &P) {
// Array of foldings: F[i][0] F[i][1] ===> F[i][2].
// E.g.: OMPD_for OMPD_simd ===> OMPD_for_simd
// TODO: add other combined directives in topological order.
- static const unsigned F[][3] = {
+ static const OpenMPDirectiveKindExWrapper F[][3] = {
{OMPD_cancellation, OMPD_point, OMPD_cancellation_point},
{OMPD_declare, OMPD_reduction, OMPD_declare_reduction},
{OMPD_declare, OMPD_mapper, OMPD_declare_mapper},
@@ -140,10 +155,12 @@ static OpenMPDirectiveKind parseOpenMPDirectiveKind(Parser &P) {
{OMPD_master, OMPD_taskloop, OMPD_master_taskloop},
{OMPD_master_taskloop, OMPD_simd, OMPD_master_taskloop_simd},
{OMPD_parallel, OMPD_master, OMPD_parallel_master},
- {OMPD_parallel_master, OMPD_taskloop, OMPD_parallel_master_taskloop}};
+ {OMPD_parallel_master, OMPD_taskloop, OMPD_parallel_master_taskloop},
+ {OMPD_parallel_master_taskloop, OMPD_simd,
+ OMPD_parallel_master_taskloop_simd}};
enum { CancellationPoint = 0, DeclareReduction = 1, TargetData = 2 };
Token Tok = P.getCurToken();
- unsigned DKind =
+ OpenMPDirectiveKindExWrapper DKind =
Tok.isAnnotation()
? static_cast<unsigned>(OMPD_unknown)
: getOpenMPDirectiveKindEx(P.getPreprocessor().getSpelling(Tok));
@@ -155,7 +172,7 @@ static OpenMPDirectiveKind parseOpenMPDirectiveKind(Parser &P) {
continue;
Tok = P.getPreprocessor().LookAhead(0);
- unsigned SDKind =
+ OpenMPDirectiveKindExWrapper SDKind =
Tok.isAnnotation()
? static_cast<unsigned>(OMPD_unknown)
: getOpenMPDirectiveKindEx(P.getPreprocessor().getSpelling(Tok));
@@ -237,8 +254,9 @@ Parser::DeclGroupPtrTy
Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) {
// Parse '('.
BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
- if (T.expectAndConsume(diag::err_expected_lparen_after,
- getOpenMPDirectiveName(OMPD_declare_reduction))) {
+ if (T.expectAndConsume(
+ diag::err_expected_lparen_after,
+ getOpenMPDirectiveName(OMPD_declare_reduction).data())) {
SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
return DeclGroupPtrTy();
}
@@ -325,9 +343,8 @@ Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) {
Scope::OpenMPDirectiveScope);
// Parse <combiner> expression.
Actions.ActOnOpenMPDeclareReductionCombinerStart(getCurScope(), D);
- ExprResult CombinerResult =
- Actions.ActOnFinishFullExpr(ParseAssignmentExpression().get(),
- D->getLocation(), /*DiscardedValue*/ false);
+ ExprResult CombinerResult = Actions.ActOnFinishFullExpr(
+ ParseExpression().get(), D->getLocation(), /*DiscardedValue*/ false);
Actions.ActOnOpenMPDeclareReductionCombinerEnd(D, CombinerResult.get());
if (CombinerResult.isInvalid() && Tok.isNot(tok::r_paren) &&
@@ -366,14 +383,8 @@ Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) {
// Check if initializer is omp_priv <init_expr> or something else.
if (Tok.is(tok::identifier) &&
Tok.getIdentifierInfo()->isStr("omp_priv")) {
- if (Actions.getLangOpts().CPlusPlus) {
- InitializerResult = Actions.ActOnFinishFullExpr(
- ParseAssignmentExpression().get(), D->getLocation(),
- /*DiscardedValue*/ false);
- } else {
- ConsumeToken();
- ParseOpenMPReductionInitializerForDecl(OmpPrivParm);
- }
+ ConsumeToken();
+ ParseOpenMPReductionInitializerForDecl(OmpPrivParm);
} else {
InitializerResult = Actions.ActOnFinishFullExpr(
ParseAssignmentExpression().get(), D->getLocation(),
@@ -417,7 +428,8 @@ void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) {
return;
}
- ExprResult Init(ParseInitializer());
+ PreferredType.enterVariableInit(Tok.getLocation(), OmpPrivParm);
+ ExprResult Init = ParseInitializer();
if (Init.isInvalid()) {
SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch);
@@ -495,7 +507,7 @@ Parser::ParseOpenMPDeclareMapperDirective(AccessSpecifier AS) {
// Parse '('
BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
if (T.expectAndConsume(diag::err_expected_lparen_after,
- getOpenMPDirectiveName(OMPD_declare_mapper))) {
+ getOpenMPDirectiveName(OMPD_declare_mapper).data())) {
SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
return DeclGroupPtrTy();
}
@@ -722,10 +734,12 @@ static bool parseDeclareSimdClauses(
CKind == OMPC_linear) {
Parser::OpenMPVarListDataTy Data;
SmallVectorImpl<Expr *> *Vars = &Uniforms;
- if (CKind == OMPC_aligned)
+ if (CKind == OMPC_aligned) {
Vars = &Aligneds;
- else if (CKind == OMPC_linear)
+ } else if (CKind == OMPC_linear) {
+ Data.ExtraModifier = OMPC_LINEAR_val;
Vars = &Linears;
+ }
P.ConsumeToken();
if (P.ParseOpenMPVarList(OMPD_declare_simd,
@@ -734,11 +748,15 @@ static bool parseDeclareSimdClauses(
if (CKind == OMPC_aligned) {
Alignments.append(Aligneds.size() - Alignments.size(), Data.TailExpr);
} else if (CKind == OMPC_linear) {
- if (P.getActions().CheckOpenMPLinearModifier(Data.LinKind,
- Data.DepLinMapLoc))
- Data.LinKind = OMPC_LINEAR_val;
+ assert(0 <= Data.ExtraModifier &&
+ Data.ExtraModifier <= OMPC_LINEAR_unknown &&
+ "Unexpected linear modifier.");
+ if (P.getActions().CheckOpenMPLinearModifier(
+ static_cast<OpenMPLinearClauseKind>(Data.ExtraModifier),
+ Data.DepLinMapLastLoc))
+ Data.ExtraModifier = OMPC_LINEAR_val;
LinModifiers.append(Linears.size() - LinModifiers.size(),
- Data.LinKind);
+ Data.ExtraModifier);
Steps.append(Linears.size() - Steps.size(), Data.TailExpr);
}
} else
@@ -795,16 +813,11 @@ Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr,
/// Parse optional 'score' '(' <expr> ')' ':'.
static ExprResult parseContextScore(Parser &P) {
ExprResult ScoreExpr;
- SmallString<16> Buffer;
+ Sema::OMPCtxStringType Buffer;
StringRef SelectorName =
P.getPreprocessor().getSpelling(P.getCurToken(), Buffer);
- OMPDeclareVariantAttr::ScoreType ScoreKind =
- OMPDeclareVariantAttr::ScoreUnknown;
- (void)OMPDeclareVariantAttr::ConvertStrToScoreType(SelectorName, ScoreKind);
- if (ScoreKind == OMPDeclareVariantAttr::ScoreUnknown)
+ if (!SelectorName.equals("score"))
return ScoreExpr;
- assert(ScoreKind == OMPDeclareVariantAttr::ScoreSpecified &&
- "Expected \"score\" clause.");
(void)P.ConsumeToken();
SourceLocation RLoc;
ScoreExpr = P.ParseOpenMPParensExpr(SelectorName, RLoc);
@@ -820,11 +833,10 @@ static ExprResult parseContextScore(Parser &P) {
/// Parse context selector for 'implementation' selector set:
/// 'vendor' '(' [ 'score' '(' <score _expr> ')' ':' ] <vendor> { ',' <vendor> }
/// ')'
-static void parseImplementationSelector(
- Parser &P, SourceLocation Loc, llvm::StringMap<SourceLocation> &UsedCtx,
- llvm::function_ref<void(SourceRange,
- const Sema::OpenMPDeclareVariantCtsSelectorData &)>
- Callback) {
+static void
+parseImplementationSelector(Parser &P, SourceLocation Loc,
+ llvm::StringMap<SourceLocation> &UsedCtx,
+ SmallVectorImpl<Sema::OMPCtxSelectorData> &Data) {
const Token &Tok = P.getCurToken();
// Parse inner context selector set name, if any.
if (!Tok.is(tok::identifier)) {
@@ -836,7 +848,7 @@ static void parseImplementationSelector(
;
return;
}
- SmallString<16> Buffer;
+ Sema::OMPCtxStringType Buffer;
StringRef CtxSelectorName = P.getPreprocessor().getSpelling(Tok, Buffer);
auto Res = UsedCtx.try_emplace(CtxSelectorName, Tok.getLocation());
if (!Res.second) {
@@ -847,19 +859,16 @@ static void parseImplementationSelector(
P.Diag(Res.first->getValue(), diag::note_omp_declare_variant_ctx_used_here)
<< CtxSelectorName;
}
- OMPDeclareVariantAttr::CtxSelectorType CSKind =
- OMPDeclareVariantAttr::CtxUnknown;
- (void)OMPDeclareVariantAttr::ConvertStrToCtxSelectorType(CtxSelectorName,
- CSKind);
+ OpenMPContextSelectorKind CSKind = getOpenMPContextSelector(CtxSelectorName);
(void)P.ConsumeToken();
switch (CSKind) {
- case OMPDeclareVariantAttr::CtxVendor: {
+ case OMP_CTX_vendor: {
// Parse '('.
BalancedDelimiterTracker T(P, tok::l_paren, tok::annot_pragma_openmp_end);
(void)T.expectAndConsume(diag::err_expected_lparen_after,
CtxSelectorName.data());
- const ExprResult Score = parseContextScore(P);
- llvm::UniqueVector<llvm::SmallString<16>> Vendors;
+ ExprResult Score = parseContextScore(P);
+ llvm::UniqueVector<Sema::OMPCtxStringType> Vendors;
do {
// Parse <vendor>.
StringRef VendorName;
@@ -882,18 +891,12 @@ static void parseImplementationSelector(
} while (Tok.is(tok::identifier));
// Parse ')'.
(void)T.consumeClose();
- if (!Vendors.empty()) {
- SmallVector<StringRef, 4> ImplVendors(Vendors.size());
- llvm::copy(Vendors, ImplVendors.begin());
- Sema::OpenMPDeclareVariantCtsSelectorData Data(
- OMPDeclareVariantAttr::CtxSetImplementation, CSKind,
- llvm::makeMutableArrayRef(ImplVendors.begin(), ImplVendors.size()),
- Score);
- Callback(SourceRange(Loc, Tok.getLocation()), Data);
- }
+ if (!Vendors.empty())
+ Data.emplace_back(OMP_CTX_SET_implementation, CSKind, Score, Vendors);
break;
}
- case OMPDeclareVariantAttr::CtxUnknown:
+ case OMP_CTX_kind:
+ case OMP_CTX_unknown:
P.Diag(Tok.getLocation(), diag::warn_omp_declare_variant_cs_name_expected)
<< "implementation";
// Skip until either '}', ')', or end of directive.
@@ -904,15 +907,97 @@ static void parseImplementationSelector(
}
}
+/// Parse context selector for 'device' selector set:
+/// 'kind' '(' <kind> { ',' <kind> } ')'
+static void
+parseDeviceSelector(Parser &P, SourceLocation Loc,
+ llvm::StringMap<SourceLocation> &UsedCtx,
+ SmallVectorImpl<Sema::OMPCtxSelectorData> &Data) {
+ const Token &Tok = P.getCurToken();
+ // Parse inner context selector set name, if any.
+ if (!Tok.is(tok::identifier)) {
+ P.Diag(Tok.getLocation(), diag::warn_omp_declare_variant_cs_name_expected)
+ << "device";
+ // Skip until either '}', ')', or end of directive.
+ while (!P.SkipUntil(tok::r_brace, tok::r_paren,
+ tok::annot_pragma_openmp_end, Parser::StopBeforeMatch))
+ ;
+ return;
+ }
+ Sema::OMPCtxStringType Buffer;
+ StringRef CtxSelectorName = P.getPreprocessor().getSpelling(Tok, Buffer);
+ auto Res = UsedCtx.try_emplace(CtxSelectorName, Tok.getLocation());
+ if (!Res.second) {
+ // OpenMP 5.0, 2.3.2 Context Selectors, Restrictions.
+ // Each trait-selector-name can only be specified once.
+ P.Diag(Tok.getLocation(), diag::err_omp_declare_variant_ctx_mutiple_use)
+ << CtxSelectorName << "device";
+ P.Diag(Res.first->getValue(), diag::note_omp_declare_variant_ctx_used_here)
+ << CtxSelectorName;
+ }
+ OpenMPContextSelectorKind CSKind = getOpenMPContextSelector(CtxSelectorName);
+ (void)P.ConsumeToken();
+ switch (CSKind) {
+ case OMP_CTX_kind: {
+ // Parse '('.
+ BalancedDelimiterTracker T(P, tok::l_paren, tok::annot_pragma_openmp_end);
+ (void)T.expectAndConsume(diag::err_expected_lparen_after,
+ CtxSelectorName.data());
+ llvm::UniqueVector<Sema::OMPCtxStringType> Kinds;
+ do {
+ // Parse <kind>.
+ StringRef KindName;
+ if (Tok.is(tok::identifier)) {
+ Buffer.clear();
+ KindName = P.getPreprocessor().getSpelling(P.getCurToken(), Buffer);
+ SourceLocation SLoc = P.getCurToken().getLocation();
+ (void)P.ConsumeToken();
+ if (llvm::StringSwitch<bool>(KindName)
+ .Case("host", false)
+ .Case("nohost", false)
+ .Case("cpu", false)
+ .Case("gpu", false)
+ .Case("fpga", false)
+ .Default(true)) {
+ P.Diag(SLoc, diag::err_omp_wrong_device_kind_trait) << KindName;
+ } else {
+ Kinds.insert(KindName);
+ }
+ } else {
+ P.Diag(Tok.getLocation(), diag::err_omp_declare_variant_item_expected)
+ << "'host', 'nohost', 'cpu', 'gpu', or 'fpga'"
+ << "kind"
+ << "device";
+ }
+ if (!P.TryConsumeToken(tok::comma) && Tok.isNot(tok::r_paren)) {
+ P.Diag(Tok, diag::err_expected_punc)
+ << (KindName.empty() ? "kind of device" : KindName);
+ }
+ } while (Tok.is(tok::identifier));
+ // Parse ')'.
+ (void)T.consumeClose();
+ if (!Kinds.empty())
+ Data.emplace_back(OMP_CTX_SET_device, CSKind, ExprResult(), Kinds);
+ break;
+ }
+ case OMP_CTX_vendor:
+ case OMP_CTX_unknown:
+ P.Diag(Tok.getLocation(), diag::warn_omp_declare_variant_cs_name_expected)
+ << "device";
+ // Skip until either '}', ')', or end of directive.
+ while (!P.SkipUntil(tok::r_brace, tok::r_paren,
+ tok::annot_pragma_openmp_end, Parser::StopBeforeMatch))
+ ;
+ return;
+ }
+}
+
/// Parses clauses for 'declare variant' directive.
/// clause:
/// <selector_set_name> '=' '{' <context_selectors> '}'
/// [ ',' <selector_set_name> '=' '{' <context_selectors> '}' ]
bool Parser::parseOpenMPContextSelectors(
- SourceLocation Loc,
- llvm::function_ref<void(SourceRange,
- const Sema::OpenMPDeclareVariantCtsSelectorData &)>
- Callback) {
+ SourceLocation Loc, SmallVectorImpl<Sema::OMPCtxSelectorData> &Data) {
llvm::StringMap<SourceLocation> UsedCtxSets;
do {
// Parse inner context selector set name.
@@ -921,7 +1006,7 @@ bool Parser::parseOpenMPContextSelectors(
<< getOpenMPClauseName(OMPC_match);
return true;
}
- SmallString<16> Buffer;
+ Sema::OMPCtxStringType Buffer;
StringRef CtxSelectorSetName = PP.getSpelling(Tok, Buffer);
auto Res = UsedCtxSets.try_emplace(CtxSelectorSetName, Tok.getLocation());
if (!Res.second) {
@@ -949,17 +1034,18 @@ bool Parser::parseOpenMPContextSelectors(
tok::annot_pragma_openmp_end);
if (TBr.expectAndConsume(diag::err_expected_lbrace_after, "="))
return true;
- OMPDeclareVariantAttr::CtxSelectorSetType CSSKind =
- OMPDeclareVariantAttr::CtxSetUnknown;
- (void)OMPDeclareVariantAttr::ConvertStrToCtxSelectorSetType(
- CtxSelectorSetName, CSSKind);
+ OpenMPContextSelectorSetKind CSSKind =
+ getOpenMPContextSelectorSet(CtxSelectorSetName);
llvm::StringMap<SourceLocation> UsedCtx;
do {
switch (CSSKind) {
- case OMPDeclareVariantAttr::CtxSetImplementation:
- parseImplementationSelector(*this, Loc, UsedCtx, Callback);
+ case OMP_CTX_SET_implementation:
+ parseImplementationSelector(*this, Loc, UsedCtx, Data);
break;
- case OMPDeclareVariantAttr::CtxSetUnknown:
+ case OMP_CTX_SET_device:
+ parseDeviceSelector(*this, Loc, UsedCtx, Data);
+ break;
+ case OMP_CTX_SET_unknown:
// Skip until either '}', ')', or end of directive.
while (!SkipUntil(tok::r_brace, tok::r_paren,
tok::annot_pragma_openmp_end, StopBeforeMatch))
@@ -998,9 +1084,16 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr,
SourceLocation RLoc;
// Parse with IsAddressOfOperand set to true to parse methods as DeclRefExprs
// instead of MemberExprs.
- ExprResult AssociatedFunction =
- ParseOpenMPParensExpr(getOpenMPDirectiveName(OMPD_declare_variant), RLoc,
- /*IsAddressOfOperand=*/true);
+ ExprResult AssociatedFunction;
+ {
+ // Do not mark function as is used to prevent its emission if this is the
+ // only place where it is used.
+ EnterExpressionEvaluationContext Unevaluated(
+ Actions, Sema::ExpressionEvaluationContext::Unevaluated);
+ AssociatedFunction = ParseOpenMPParensExpr(
+ getOpenMPDirectiveName(OMPD_declare_variant), RLoc,
+ /*IsAddressOfOperand=*/true);
+ }
if (!AssociatedFunction.isUsable()) {
if (!Tok.is(tok::annot_pragma_openmp_end))
while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch))
@@ -1039,15 +1132,8 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr,
}
// Parse inner context selectors.
- if (!parseOpenMPContextSelectors(
- Loc, [this, &DeclVarData](
- SourceRange SR,
- const Sema::OpenMPDeclareVariantCtsSelectorData &Data) {
- if (DeclVarData.hasValue())
- Actions.ActOnOpenMPDeclareVariantDirective(
- DeclVarData.getValue().first, DeclVarData.getValue().second,
- SR, Data);
- })) {
+ SmallVector<Sema::OMPCtxSelectorData, 4> Data;
+ if (!parseOpenMPContextSelectors(Loc, Data)) {
// Parse ')'.
(void)T.consumeClose();
// Need to check for extra tokens.
@@ -1060,6 +1146,10 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr,
// Skip last tokens.
while (Tok.isNot(tok::annot_pragma_openmp_end))
ConsumeAnyToken();
+ if (DeclVarData.hasValue())
+ Actions.ActOnOpenMPDeclareVariantDirective(
+ DeclVarData.getValue().first, DeclVarData.getValue().second,
+ SourceRange(Loc, Tok.getLocation()), Data);
// Skip the last annot_pragma_openmp_end.
(void)ConsumeAnnotationToken();
}
@@ -1245,13 +1335,45 @@ void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind DKind,
/// annot_pragma_openmp_end
///
Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
- AccessSpecifier &AS, ParsedAttributesWithRange &Attrs,
+ AccessSpecifier &AS, ParsedAttributesWithRange &Attrs, bool Delayed,
DeclSpec::TST TagType, Decl *Tag) {
assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
+ ParsingOpenMPDirectiveRAII DirScope(*this);
ParenBraceBracketBalancer BalancerRAIIObj(*this);
- SourceLocation Loc = ConsumeAnnotationToken();
- OpenMPDirectiveKind DKind = parseOpenMPDirectiveKind(*this);
+ SourceLocation Loc;
+ OpenMPDirectiveKind DKind;
+ if (Delayed) {
+ TentativeParsingAction TPA(*this);
+ Loc = ConsumeAnnotationToken();
+ DKind = parseOpenMPDirectiveKind(*this);
+ if (DKind == OMPD_declare_reduction || DKind == OMPD_declare_mapper) {
+ // Need to delay parsing until completion of the parent class.
+ TPA.Revert();
+ CachedTokens Toks;
+ unsigned Cnt = 1;
+ Toks.push_back(Tok);
+ while (Cnt && Tok.isNot(tok::eof)) {
+ (void)ConsumeAnyToken();
+ if (Tok.is(tok::annot_pragma_openmp))
+ ++Cnt;
+ else if (Tok.is(tok::annot_pragma_openmp_end))
+ --Cnt;
+ Toks.push_back(Tok);
+ }
+ // Skip last annot_pragma_openmp_end.
+ if (Cnt == 0)
+ (void)ConsumeAnyToken();
+ auto *LP = new LateParsedPragma(this, AS);
+ LP->takeToks(Toks);
+ getCurrentClass().LateParsedDeclarations.push_back(LP);
+ return nullptr;
+ }
+ TPA.Commit();
+ } else {
+ Loc = ConsumeAnnotationToken();
+ DKind = parseOpenMPDirectiveKind(*this);
+ }
switch (DKind) {
case OMPD_threadprivate: {
@@ -1403,7 +1525,8 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
DeclGroupPtrTy Ptr;
if (Tok.is(tok::annot_pragma_openmp)) {
- Ptr = ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs, TagType, Tag);
+ Ptr = ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs, Delayed,
+ TagType, Tag);
} else if (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
// Here we expect to see some function declaration.
if (AS == AS_none) {
@@ -1496,6 +1619,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
case OMPD_parallel_sections:
+ case OMPD_parallel_master:
case OMPD_atomic:
case OMPD_target:
case OMPD_teams:
@@ -1511,6 +1635,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
case OMPD_master_taskloop:
case OMPD_master_taskloop_simd:
case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_master_taskloop_simd:
case OMPD_distribute:
case OMPD_end_declare_target:
case OMPD_target_update:
@@ -1562,24 +1687,26 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
/// executable-directive:
/// annot_pragma_openmp 'parallel' | 'simd' | 'for' | 'sections' |
/// 'section' | 'single' | 'master' | 'critical' [ '(' <name> ')' ] |
-/// 'parallel for' | 'parallel sections' | 'task' | 'taskyield' |
-/// 'barrier' | 'taskwait' | 'flush' | 'ordered' | 'atomic' |
-/// 'for simd' | 'parallel for simd' | 'target' | 'target data' |
-/// 'taskgroup' | 'teams' | 'taskloop' | 'taskloop simd' | 'master
-/// taskloop' | 'master taskloop simd' | 'parallel master taskloop' |
-/// 'distribute' | 'target enter data' | 'target exit data' | 'target
-/// parallel' | 'target parallel for' | 'target update' | 'distribute
-/// parallel for' | 'distribute paralle for simd' | 'distribute simd' |
-/// 'target parallel for simd' | 'target simd' | 'teams distribute' |
-/// 'teams distribute simd' | 'teams distribute parallel for simd' |
-/// 'teams distribute parallel for' | 'target teams' | 'target teams
-/// distribute' | 'target teams distribute parallel for' | 'target teams
-/// distribute parallel for simd' | 'target teams distribute simd'
-/// {clause} annot_pragma_openmp_end
+/// 'parallel for' | 'parallel sections' | 'parallel master' | 'task' |
+/// 'taskyield' | 'barrier' | 'taskwait' | 'flush' | 'ordered' |
+/// '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
+/// enter data' | 'target exit data' | 'target parallel' | 'target
+/// parallel for' | 'target update' | 'distribute parallel for' |
+/// 'distribute paralle for simd' | 'distribute simd' | 'target parallel
+/// for simd' | 'target simd' | 'teams distribute' | 'teams distribute
+/// simd' | 'teams distribute parallel for simd' | 'teams distribute
+/// parallel for' | 'target teams' | 'target teams distribute' | 'target
+/// teams distribute parallel for' | 'target teams distribute parallel
+/// for simd' | 'target teams distribute simd' {clause}
+/// annot_pragma_openmp_end
///
StmtResult
Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) {
assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
+ ParsingOpenMPDirectiveRAII DirScope(*this);
ParenBraceBracketBalancer BalancerRAIIObj(*this);
SmallVector<OMPClause *, 5> Clauses;
SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, OMPC_unknown + 1>
@@ -1739,6 +1866,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) {
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
case OMPD_parallel_sections:
+ case OMPD_parallel_master:
case OMPD_task:
case OMPD_ordered:
case OMPD_atomic:
@@ -1753,6 +1881,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) {
case OMPD_master_taskloop:
case OMPD_master_taskloop_simd:
case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_master_taskloop_simd:
case OMPD_distribute:
case OMPD_distribute_parallel_for:
case OMPD_distribute_parallel_for_simd:
@@ -1890,7 +2019,7 @@ bool Parser::ParseOpenMPSimpleVarList(
// Parse '('.
BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
if (T.expectAndConsume(diag::err_expected_lparen_after,
- getOpenMPDirectiveName(Kind)))
+ getOpenMPDirectiveName(Kind).data()))
return true;
bool IsCorrect = true;
bool NoIdentIsFound = true;
@@ -1963,7 +2092,8 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
bool ErrorFound = false;
bool WrongDirective = false;
// Check if clause is allowed for the given directive.
- if (CKind != OMPC_unknown && !isAllowedClauseForDirective(DKind, CKind)) {
+ if (CKind != OMPC_unknown &&
+ !isAllowedClauseForDirective(DKind, CKind, getLangOpts().OpenMP)) {
Diag(Tok, diag::err_omp_unexpected_clause) << getOpenMPClauseName(CKind)
<< getOpenMPDirectiveName(DKind);
ErrorFound = true;
@@ -2042,15 +2172,15 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
case OMPC_defaultmap:
// OpenMP [2.7.1, Restrictions, p. 3]
// Only one schedule clause can appear on a loop directive.
- // OpenMP [2.10.4, Restrictions, p. 106]
+ // OpenMP 4.5 [2.10.4, Restrictions, p. 106]
// At most one defaultmap clause can appear on the directive.
- if (!FirstClause) {
+ if ((getLangOpts().OpenMP < 50 || CKind != OMPC_defaultmap) &&
+ !FirstClause) {
Diag(Tok, diag::err_omp_more_one_clause)
<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;
ErrorFound = true;
}
LLVM_FALLTHROUGH;
-
case OMPC_if:
Clause = ParseOpenMPSingleExprWithArgClause(CKind, WrongDirective);
break;
@@ -2102,6 +2232,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
case OMPC_use_device_ptr:
case OMPC_is_device_ptr:
case OMPC_allocate:
+ case OMPC_nontemporal:
Clause = ParseOpenMPVarListClause(DKind, CKind, WrongDirective);
break;
case OMPC_device_type:
@@ -2133,8 +2264,8 @@ ExprResult Parser::ParseOpenMPParensExpr(StringRef ClauseName,
return ExprError();
SourceLocation ELoc = Tok.getLocation();
- ExprResult LHS(ParseCastExpression(
- /*isUnaryExpression=*/false, IsAddressOfOperand, NotTypeCast));
+ ExprResult LHS(ParseCastExpression(AnyCastExpr, IsAddressOfOperand,
+ NotTypeCast));
ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
Val = Actions.ActOnFinishFullExpr(Val.get(), ELoc, /*DiscardedValue*/ false);
@@ -2334,8 +2465,13 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind,
DelimLoc = ConsumeAnyToken();
} else if (Kind == OMPC_defaultmap) {
// Get a defaultmap modifier
- Arg.push_back(getOpenMPSimpleClauseType(
- Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok)));
+ unsigned Modifier = getOpenMPSimpleClauseType(
+ Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok));
+ // Set defaultmap modifier to unknown if it is either scalar, aggregate, or
+ // pointer
+ if (Modifier < OMPC_DEFAULTMAP_MODIFIER_unknown)
+ Modifier = OMPC_DEFAULTMAP_MODIFIER_unknown;
+ Arg.push_back(Modifier);
KLoc.push_back(Tok.getLocation());
if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
Tok.isNot(tok::annot_pragma_openmp_end))
@@ -2356,15 +2492,16 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind,
assert(Kind == OMPC_if);
KLoc.push_back(Tok.getLocation());
TentativeParsingAction TPA(*this);
- Arg.push_back(parseOpenMPDirectiveKind(*this));
- if (Arg.back() != OMPD_unknown) {
+ auto DK = parseOpenMPDirectiveKind(*this);
+ Arg.push_back(DK);
+ if (DK != OMPD_unknown) {
ConsumeToken();
if (Tok.is(tok::colon) && getLangOpts().OpenMP > 40) {
TPA.Commit();
DelimLoc = ConsumeToken();
} else {
TPA.Revert();
- Arg.back() = OMPD_unknown;
+ Arg.back() = unsigned(OMPD_unknown);
}
} else {
TPA.Revert();
@@ -2376,7 +2513,7 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind,
Kind == OMPC_if;
if (NeedAnExpression) {
SourceLocation ELoc = Tok.getLocation();
- ExprResult LHS(ParseCastExpression(false, false, NotTypeCast));
+ ExprResult LHS(ParseCastExpression(AnyCastExpr, false, NotTypeCast));
Val = ParseRHSOfBinaryExpression(LHS, prec::Conditional);
Val =
Actions.ActOnFinishFullExpr(Val.get(), ELoc, /*DiscardedValue*/ false);
@@ -2541,8 +2678,8 @@ static void parseMapType(Parser &P, Parser::OpenMPVarListDataTy &Data) {
P.Diag(Tok, diag::err_omp_map_type_missing);
return;
}
- Data.MapType = isMapType(P);
- if (Data.MapType == OMPC_MAP_unknown)
+ Data.ExtraModifier = isMapType(P);
+ if (Data.ExtraModifier == OMPC_MAP_unknown)
P.Diag(Tok, diag::err_omp_unknown_map_type);
P.ConsumeToken();
}
@@ -2587,20 +2724,18 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
Data.ReductionOrMapperId =
Actions.GetNameFromUnqualifiedId(UnqualifiedReductionId);
} else if (Kind == OMPC_depend) {
- // Handle dependency type for depend clause.
+ // Handle dependency type for depend clause.
ColonProtectionRAIIObject ColonRAII(*this);
- Data.DepKind =
- static_cast<OpenMPDependClauseKind>(getOpenMPSimpleClauseType(
- Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : ""));
- Data.DepLinMapLoc = Tok.getLocation();
-
- if (Data.DepKind == OMPC_DEPEND_unknown) {
+ Data.ExtraModifier = getOpenMPSimpleClauseType(
+ Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "");
+ Data.DepLinMapLastLoc = Tok.getLocation();
+ if (Data.ExtraModifier == OMPC_DEPEND_unknown) {
SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
StopBeforeMatch);
} else {
ConsumeToken();
// Special processing for depend(source) clause.
- if (DKind == OMPD_ordered && Data.DepKind == OMPC_DEPEND_source) {
+ if (DKind == OMPD_ordered && Data.ExtraModifier == OMPC_DEPEND_source) {
// Parse ')'.
T.consumeClose();
return false;
@@ -2615,13 +2750,32 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
}
} else if (Kind == OMPC_linear) {
// Try to parse modifier if any.
+ Data.ExtraModifier = OMPC_LINEAR_val;
if (Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::l_paren)) {
- Data.LinKind = static_cast<OpenMPLinearClauseKind>(
- getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)));
- Data.DepLinMapLoc = ConsumeToken();
+ Data.ExtraModifier = getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok));
+ Data.DepLinMapLastLoc = ConsumeToken();
LinearT.consumeOpen();
NeedRParenForLinear = true;
}
+ } else if (Kind == OMPC_lastprivate) {
+ // Try to parse modifier if any.
+ Data.ExtraModifier = OMPC_LASTPRIVATE_unknown;
+ // Conditional modifier allowed only in OpenMP 5.0 and not supported in
+ // distribute and taskloop based directives.
+ if ((getLangOpts().OpenMP >= 50 && !isOpenMPDistributeDirective(DKind) &&
+ !isOpenMPTaskLoopDirective(DKind)) &&
+ Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::colon)) {
+ Data.ExtraModifier = getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok));
+ Data.DepLinMapLastLoc = Tok.getLocation();
+ if (Data.ExtraModifier == OMPC_LASTPRIVATE_unknown) {
+ SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
+ StopBeforeMatch);
+ } else {
+ ConsumeToken();
+ }
+ assert(Tok.is(tok::colon) && "Expected colon.");
+ Data.ColonLoc = ConsumeToken();
+ }
} else if (Kind == OMPC_map) {
// Handle map type for map clause.
ColonProtectionRAIIObject ColonRAII(*this);
@@ -2629,7 +2783,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
// The first identifier may be a list item, a map-type or a
// map-type-modifier. The map-type can also be delete which has the same
// spelling of the C++ delete keyword.
- Data.DepLinMapLoc = Tok.getLocation();
+ Data.ExtraModifier = OMPC_MAP_unknown;
+ Data.DepLinMapLastLoc = Tok.getLocation();
// Check for presence of a colon in the map clause.
TentativeParsingAction TPA(*this);
@@ -2649,8 +2804,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
else
SkipUntil(tok::colon, tok::annot_pragma_openmp_end, StopBeforeMatch);
}
- if (Data.MapType == OMPC_MAP_unknown) {
- Data.MapType = OMPC_MAP_tofrom;
+ if (Data.ExtraModifier == OMPC_MAP_unknown) {
+ Data.ExtraModifier = OMPC_MAP_tofrom;
Data.IsMapTypeImplicit = true;
}
@@ -2716,8 +2871,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
(Kind != OMPC_reduction && Kind != OMPC_task_reduction &&
Kind != OMPC_in_reduction && Kind != OMPC_depend && Kind != OMPC_map) ||
(Kind == OMPC_reduction && !InvalidReductionId) ||
- (Kind == OMPC_map && Data.MapType != OMPC_MAP_unknown) ||
- (Kind == OMPC_depend && Data.DepKind != OMPC_DEPEND_unknown);
+ (Kind == OMPC_map && Data.ExtraModifier != OMPC_MAP_unknown) ||
+ (Kind == OMPC_depend && Data.ExtraModifier != OMPC_DEPEND_unknown);
const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned);
while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) &&
Tok.isNot(tok::annot_pragma_openmp_end))) {
@@ -2767,7 +2922,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
Data.RLoc = Tok.getLocation();
if (!T.consumeClose())
Data.RLoc = T.getCloseLocation();
- return (Kind == OMPC_depend && Data.DepKind != OMPC_DEPEND_unknown &&
+ return (Kind == OMPC_depend && Data.ExtraModifier != OMPC_DEPEND_unknown &&
Vars.empty()) ||
(Kind != OMPC_depend && Kind != OMPC_map && Vars.empty()) ||
(MustHaveTail && !Data.TailExpr) || InvalidReductionId ||
@@ -2837,8 +2992,8 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind,
OMPVarListLocTy Locs(Loc, LOpen, Data.RLoc);
return Actions.ActOnOpenMPVarListClause(
Kind, Vars, Data.TailExpr, Locs, Data.ColonLoc,
- Data.ReductionOrMapperIdScopeSpec, Data.ReductionOrMapperId, Data.DepKind,
- Data.LinKind, Data.MapTypeModifiers, Data.MapTypeModifiersLoc,
- Data.MapType, Data.IsMapTypeImplicit, Data.DepLinMapLoc);
+ Data.ReductionOrMapperIdScopeSpec, Data.ReductionOrMapperId,
+ Data.ExtraModifier, Data.MapTypeModifiers, Data.MapTypeModifiersLoc,
+ Data.IsMapTypeImplicit, Data.DepLinMapLastLoc);
}
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index cdbf697cf7f1..df411e1928d6 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -734,7 +734,7 @@ void Parser::HandlePragmaMSVtorDisp() {
uintptr_t Value = reinterpret_cast<uintptr_t>(Tok.getAnnotationValue());
Sema::PragmaMsStackAction Action =
static_cast<Sema::PragmaMsStackAction>((Value >> 16) & 0xFFFF);
- MSVtorDispAttr::Mode Mode = MSVtorDispAttr::Mode(Value & 0xFFFF);
+ MSVtorDispMode Mode = MSVtorDispMode(Value & 0xFFFF);
SourceLocation PragmaLoc = ConsumeAnnotationToken();
Actions.ActOnPragmaMSVtorDisp(Action, PragmaLoc, Mode);
}
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 727ab75adae8..0339328ca513 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -1191,6 +1191,99 @@ bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt,
return false;
}
+namespace {
+
+enum MisleadingStatementKind { MSK_if, MSK_else, MSK_for, MSK_while };
+
+struct MisleadingIndentationChecker {
+ Parser &P;
+ SourceLocation StmtLoc;
+ SourceLocation PrevLoc;
+ unsigned NumDirectives;
+ MisleadingStatementKind Kind;
+ bool ShouldSkip;
+ MisleadingIndentationChecker(Parser &P, MisleadingStatementKind K,
+ SourceLocation SL)
+ : P(P), StmtLoc(SL), PrevLoc(P.getCurToken().getLocation()),
+ NumDirectives(P.getPreprocessor().getNumDirectives()), Kind(K),
+ ShouldSkip(P.getCurToken().is(tok::l_brace)) {
+ if (!P.MisleadingIndentationElseLoc.isInvalid()) {
+ StmtLoc = P.MisleadingIndentationElseLoc;
+ P.MisleadingIndentationElseLoc = SourceLocation();
+ }
+ if (Kind == MSK_else && !ShouldSkip)
+ P.MisleadingIndentationElseLoc = SL;
+ }
+
+ /// Compute the column number will aligning tabs on TabStop (-ftabstop), this
+ /// gives the visual indentation of the SourceLocation.
+ static unsigned getVisualIndentation(SourceManager &SM, SourceLocation Loc) {
+ unsigned TabStop = SM.getDiagnostics().getDiagnosticOptions().TabStop;
+
+ unsigned ColNo = SM.getSpellingColumnNumber(Loc);
+ if (ColNo == 0 || TabStop == 1)
+ return ColNo;
+
+ std::pair<FileID, unsigned> FIDAndOffset = SM.getDecomposedLoc(Loc);
+
+ bool Invalid;
+ StringRef BufData = SM.getBufferData(FIDAndOffset.first, &Invalid);
+ if (Invalid)
+ return 0;
+
+ const char *EndPos = BufData.data() + FIDAndOffset.second;
+ // FileOffset are 0-based and Column numbers are 1-based
+ assert(FIDAndOffset.second + 1 >= ColNo &&
+ "Column number smaller than file offset?");
+
+ unsigned VisualColumn = 0; // Stored as 0-based column, here.
+ // Loop from beginning of line up to Loc's file position, counting columns,
+ // expanding tabs.
+ for (const char *CurPos = EndPos - (ColNo - 1); CurPos != EndPos;
+ ++CurPos) {
+ if (*CurPos == '\t')
+ // Advance visual column to next tabstop.
+ VisualColumn += (TabStop - VisualColumn % TabStop);
+ else
+ VisualColumn++;
+ }
+ return VisualColumn + 1;
+ }
+
+ void Check() {
+ Token Tok = P.getCurToken();
+ if (P.getActions().getDiagnostics().isIgnored(
+ diag::warn_misleading_indentation, Tok.getLocation()) ||
+ ShouldSkip || NumDirectives != P.getPreprocessor().getNumDirectives() ||
+ Tok.isOneOf(tok::semi, tok::r_brace) || Tok.isAnnotation() ||
+ Tok.getLocation().isMacroID() || PrevLoc.isMacroID() ||
+ StmtLoc.isMacroID() ||
+ (Kind == MSK_else && P.MisleadingIndentationElseLoc.isInvalid())) {
+ P.MisleadingIndentationElseLoc = SourceLocation();
+ return;
+ }
+ if (Kind == MSK_else)
+ P.MisleadingIndentationElseLoc = SourceLocation();
+
+ SourceManager &SM = P.getPreprocessor().getSourceManager();
+ unsigned PrevColNum = getVisualIndentation(SM, PrevLoc);
+ unsigned CurColNum = getVisualIndentation(SM, Tok.getLocation());
+ unsigned StmtColNum = getVisualIndentation(SM, StmtLoc);
+
+ if (PrevColNum != 0 && CurColNum != 0 && StmtColNum != 0 &&
+ ((PrevColNum > StmtColNum && PrevColNum == CurColNum) ||
+ !Tok.isAtStartOfLine()) &&
+ SM.getPresumedLineNumber(StmtLoc) !=
+ SM.getPresumedLineNumber(Tok.getLocation()) &&
+ (Tok.isNot(tok::identifier) ||
+ P.getPreprocessor().LookAhead(0).isNot(tok::colon))) {
+ P.Diag(Tok.getLocation(), diag::warn_misleading_indentation) << Kind;
+ P.Diag(StmtLoc, diag::note_previous_statement);
+ }
+ }
+};
+
+}
/// ParseIfStatement
/// if-statement: [C99 6.8.4.1]
@@ -1265,6 +1358,8 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
//
ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace));
+ MisleadingIndentationChecker MIChecker(*this, MSK_if, IfLoc);
+
// Read the 'then' stmt.
SourceLocation ThenStmtLoc = Tok.getLocation();
@@ -1278,6 +1373,9 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
ThenStmt = ParseStatement(&InnerStatementTrailingElseLoc);
}
+ if (Tok.isNot(tok::kw_else))
+ MIChecker.Check();
+
// Pop the 'if' scope if needed.
InnerScope.Exit();
@@ -1305,12 +1403,17 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
ParseScope InnerScope(this, Scope::DeclScope, C99orCXX,
Tok.is(tok::l_brace));
+ MisleadingIndentationChecker MIChecker(*this, MSK_else, ElseLoc);
+
EnterExpressionEvaluationContext PotentiallyDiscarded(
Actions, Sema::ExpressionEvaluationContext::DiscardedStatement, nullptr,
Sema::ExpressionEvaluationContextRecord::EK_Other,
/*ShouldEnter=*/ConstexprCondition && *ConstexprCondition);
ElseStmt = ParseStatement();
+ if (ElseStmt.isUsable())
+ MIChecker.Check();
+
// Pop the 'else' scope if needed.
InnerScope.Exit();
} else if (Tok.is(tok::code_completion)) {
@@ -1484,9 +1587,13 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) {
//
ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace));
+ MisleadingIndentationChecker MIChecker(*this, MSK_while, WhileLoc);
+
// Read the body statement.
StmtResult Body(ParseStatement(TrailingElseLoc));
+ if (Body.isUsable())
+ MIChecker.Check();
// Pop the body scope if needed.
InnerScope.Exit();
WhileScope.Exit();
@@ -1918,9 +2025,14 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
if (C99orCXXorObjC)
getCurScope()->decrementMSManglingNumber();
+ MisleadingIndentationChecker MIChecker(*this, MSK_for, ForLoc);
+
// Read the body statement.
StmtResult Body(ParseStatement(TrailingElseLoc));
+ if (Body.isUsable())
+ MIChecker.Check();
+
// Pop the body scope if needed.
InnerScope.Exit();
diff --git a/clang/lib/Parse/ParseStmtAsm.cpp b/clang/lib/Parse/ParseStmtAsm.cpp
index 1153c2510b05..ea2c871d6a82 100644
--- a/clang/lib/Parse/ParseStmtAsm.cpp
+++ b/clang/lib/Parse/ParseStmtAsm.cpp
@@ -547,12 +547,9 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
// We need an actual supported target.
const llvm::Triple &TheTriple = Actions.Context.getTargetInfo().getTriple();
- llvm::Triple::ArchType ArchTy = TheTriple.getArch();
const std::string &TT = TheTriple.getTriple();
const llvm::Target *TheTarget = nullptr;
- bool UnsupportedArch =
- (ArchTy != llvm::Triple::x86 && ArchTy != llvm::Triple::x86_64);
- if (UnsupportedArch) {
+ if (!TheTriple.isX86()) {
Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName();
} else {
std::string Error;
@@ -563,16 +560,19 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
assert(!LBraceLocs.empty() && "Should have at least one location here");
+ SmallString<512> AsmString;
+ auto EmptyStmt = [&] {
+ return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, AsmString,
+ /*NumOutputs*/ 0, /*NumInputs*/ 0,
+ ConstraintRefs, ClobberRefs, Exprs, EndLoc);
+ };
// If we don't support assembly, or the assembly is empty, we don't
// need to instantiate the AsmParser, etc.
if (!TheTarget || AsmToks.empty()) {
- return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, StringRef(),
- /*NumOutputs*/ 0, /*NumInputs*/ 0,
- ConstraintRefs, ClobberRefs, Exprs, EndLoc);
+ return EmptyStmt();
}
// Expand the tokens into a string buffer.
- SmallString<512> AsmString;
SmallVector<unsigned, 8> TokOffsets;
if (buildMSAsmString(PP, AsmLoc, AsmToks, TokOffsets, AsmString))
return StmtError();
@@ -582,12 +582,26 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
llvm::join(TO.Features.begin(), TO.Features.end(), ",");
std::unique_ptr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));
- std::unique_ptr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT));
+ if (!MRI) {
+ Diag(AsmLoc, diag::err_msasm_unable_to_create_target)
+ << "target MC unavailable";
+ return EmptyStmt();
+ }
+ // FIXME: init MCOptions from sanitizer flags here.
+ llvm::MCTargetOptions MCOptions;
+ std::unique_ptr<llvm::MCAsmInfo> MAI(
+ TheTarget->createMCAsmInfo(*MRI, TT, MCOptions));
// Get the instruction descriptor.
std::unique_ptr<llvm::MCInstrInfo> MII(TheTarget->createMCInstrInfo());
std::unique_ptr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo());
std::unique_ptr<llvm::MCSubtargetInfo> STI(
TheTarget->createMCSubtargetInfo(TT, TO.CPU, FeaturesStr));
+ // Target MCTargetDesc may not be linked in clang-based tools.
+ if (!MAI || !MII | !MOFI || !STI) {
+ Diag(AsmLoc, diag::err_msasm_unable_to_create_target)
+ << "target MC unavailable";
+ return EmptyStmt();
+ }
llvm::SourceMgr TempSrcMgr;
llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr);
@@ -602,10 +616,14 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
std::unique_ptr<llvm::MCAsmParser> Parser(
createMCAsmParser(TempSrcMgr, Ctx, *Str.get(), *MAI));
- // FIXME: init MCOptions from sanitizer flags here.
- llvm::MCTargetOptions MCOptions;
std::unique_ptr<llvm::MCTargetAsmParser> TargetParser(
TheTarget->createMCAsmParser(*STI, *Parser, *MII, MCOptions));
+ // Target AsmParser may not be linked in clang-based tools.
+ if (!TargetParser) {
+ Diag(AsmLoc, diag::err_msasm_unable_to_create_target)
+ << "target ASM parser unavailable";
+ return EmptyStmt();
+ }
std::unique_ptr<llvm::MCInstPrinter> IP(
TheTarget->createMCInstPrinter(llvm::Triple(TT), 1, *MAI, *MII, *MRI));
@@ -725,7 +743,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
- ExprResult AsmString(ParseAsmStringLiteral());
+ ExprResult AsmString(ParseAsmStringLiteral(/*ForAsmLabel*/ false));
// Check if GNU-style InlineAsm is disabled.
// Error on anything other than empty string.
@@ -805,7 +823,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
// Parse the asm-string list for clobbers if present.
if (!AteExtraColon && isTokenStringLiteral()) {
while (1) {
- ExprResult Clobber(ParseAsmStringLiteral());
+ ExprResult Clobber(ParseAsmStringLiteral(/*ForAsmLabel*/ false));
if (Clobber.isInvalid())
break;
@@ -902,7 +920,7 @@ bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,
} else
Names.push_back(nullptr);
- ExprResult Constraint(ParseAsmStringLiteral());
+ ExprResult Constraint(ParseAsmStringLiteral(/*ForAsmLabel*/ false));
if (Constraint.isInvalid()) {
SkipUntil(tok::r_paren, StopAtSemi);
return true;
diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index 928bc5aa25b3..1b9301b6591d 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -12,6 +12,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
#include "clang/Parse/RAIIObjectsForParser.h"
@@ -130,7 +131,9 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization(
if (TryConsumeToken(tok::kw_requires)) {
OptionalRequiresClauseConstraintER =
- Actions.CorrectDelayedTyposInExpr(ParseConstraintExpression());
+ Actions.CorrectDelayedTyposInExpr(
+ ParseConstraintLogicalOrExpression(
+ /*IsTrailingRequiresClause=*/false));
if (!OptionalRequiresClauseConstraintER.isUsable()) {
// Skip until the semi-colon or a '}'.
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
@@ -254,8 +257,12 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate(
});
LateParsedAttrList LateParsedAttrs(true);
- if (DeclaratorInfo.isFunctionDeclarator())
+ if (DeclaratorInfo.isFunctionDeclarator()) {
+ if (Tok.is(tok::kw_requires))
+ ParseTrailingRequiresClause(DeclaratorInfo);
+
MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
+ }
if (DeclaratorInfo.isFunctionDeclarator() &&
isStartOfFunctionDefinition(DeclaratorInfo)) {
@@ -492,7 +499,10 @@ Parser::ParseTemplateParameterList(const unsigned Depth,
/// Determine whether the parser is at the start of a template
/// type parameter.
-bool Parser::isStartOfTemplateTypeParameter() {
+/// \param ScopeError will receive true if there was an error parsing a
+/// scope specifier at the current location.
+bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) {
+ ScopeError = false;
if (Tok.is(tok::kw_class)) {
// "class" may be the start of an elaborated-type-specifier or a
// type-parameter. Per C++ [temp.param]p3, we prefer the type-parameter.
@@ -525,6 +535,40 @@ bool Parser::isStartOfTemplateTypeParameter() {
}
}
+ bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope);
+ CXXScopeSpec SS;
+ ScopeError =
+ ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
+ /*EnteringContext=*/false,
+ /*MayBePseudoDestructor=*/nullptr,
+ // If this is not a type-constraint, then
+ // this scope-spec is part of the typename
+ // of a non-type template parameter
+ /*IsTypename=*/true, /*LastII=*/nullptr,
+ // We won't find concepts in
+ // non-namespaces anyway, so might as well
+ // parse this correctly for possible type
+ // names.
+ /*OnlyNamespace=*/false);
+ if (ScopeError)
+ return false;
+ if (TryAnnotateTypeConstraint(SS))
+ return false;
+ bool IsTypeConstraint = isTypeConstraintAnnotation();
+ if (!IsTypeConstraint && SS.isNotEmpty()) {
+ // This isn't a type-constraint but we've already parsed this scope
+ // specifier - annotate it.
+ AnnotateScopeToken(SS, /*isNewAnnotation=*/!WasScopeAnnotation);
+ return false;
+ }
+
+ if (IsTypeConstraint &&
+ // Next token might be 'auto' or 'decltype', indicating that this
+ // type-constraint is in fact part of a placeholder-type-specifier of a
+ // non-type template parameter.
+ !NextToken().isOneOf(tok::kw_auto, tok::kw_decltype))
+ return true;
+
// 'typedef' is a reasonably-common typo/thinko for 'typename', and is
// ill-formed otherwise.
if (Tok.isNot(tok::kw_typename) && Tok.isNot(tok::kw_typedef))
@@ -568,24 +612,37 @@ bool Parser::isStartOfTemplateTypeParameter() {
/// type-parameter
/// parameter-declaration
///
-/// type-parameter: (see below)
-/// 'class' ...[opt] identifier[opt]
-/// 'class' identifier[opt] '=' type-id
-/// 'typename' ...[opt] identifier[opt]
-/// 'typename' identifier[opt] '=' type-id
-/// 'template' '<' template-parameter-list '>'
-/// 'class' ...[opt] identifier[opt]
-/// 'template' '<' template-parameter-list '>' 'class' identifier[opt]
-/// = id-expression
+/// type-parameter: (See below)
+/// type-parameter-key ...[opt] identifier[opt]
+/// type-parameter-key identifier[opt] = type-id
+/// (C++2a) type-constraint ...[opt] identifier[opt]
+/// (C++2a) type-constraint identifier[opt] = type-id
+/// 'template' '<' template-parameter-list '>' type-parameter-key
+/// ...[opt] identifier[opt]
+/// 'template' '<' template-parameter-list '>' type-parameter-key
+/// identifier[opt] '=' id-expression
+///
+/// type-parameter-key:
+/// class
+/// typename
+///
NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
- if (isStartOfTemplateTypeParameter()) {
- // Is there just a typo in the input code? ('typedef' instead of 'typename')
+ // We could be facing a type-constraint, which (could) start a type parameter.
+ // Annotate it now (we might end up not using it if we determine this
+ // type-constraint is in fact part of a placeholder-type-specifier of a
+ // non-type template parameter.
+
+ bool ScopeError;
+ if (isStartOfTemplateTypeParameter(ScopeError)) {
+ // Is there just a typo in the input code? ('typedef' instead of
+ // 'typename')
if (Tok.is(tok::kw_typedef)) {
Diag(Tok.getLocation(), diag::err_expected_template_parameter);
Diag(Tok.getLocation(), diag::note_meant_to_use_typename)
<< FixItHint::CreateReplacement(CharSourceRange::getCharRange(
- Tok.getLocation(), Tok.getEndLoc()),
+ Tok.getLocation(),
+ Tok.getEndLoc()),
"typename");
Tok.setKind(tok::kw_typename);
@@ -593,7 +650,26 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
return ParseTypeParameter(Depth, Position);
}
-
+ if (ScopeError) {
+ // We return an invalid parameter as opposed to null to avoid having bogus
+ // diagnostics about an empty template parameter list.
+ // FIXME: Fix ParseTemplateParameterList to better handle nullptr results
+ // from here.
+ // Return a NTTP as if there was an error in a scope specifier, the user
+ // probably meant to write the type of a NTTP.
+ DeclSpec DS(getAttrFactory());
+ DS.SetTypeSpecError();
+ Declarator D(DS, DeclaratorContext::TemplateParamContext);
+ D.SetIdentifier(nullptr, Tok.getLocation());
+ D.setInvalidType(true);
+ NamedDecl *ErrorParam = Actions.ActOnNonTypeTemplateParameter(
+ getCurScope(), D, Depth, Position, /*EqualLoc=*/SourceLocation(),
+ /*DefaultArg=*/nullptr);
+ ErrorParam->setInvalidDecl(true);
+ SkipUntil(tok::comma, tok::greater, tok::greatergreater,
+ StopAtSemi | StopBeforeMatch);
+ return ErrorParam;
+ }
if (Tok.is(tok::kw_template))
return ParseTemplateTemplateParameter(Depth, Position);
@@ -603,6 +679,56 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
return ParseNonTypeTemplateParameter(Depth, Position);
}
+/// Check whether the current token is a template-id annotation denoting a
+/// type-constraint.
+bool Parser::isTypeConstraintAnnotation() {
+ if (Tok.isNot(tok::annot_template_id))
+ return false;
+ const auto *ExistingAnnot =
+ static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ return ExistingAnnot->Kind == TNK_Concept_template;
+}
+
+/// Try parsing a type-constraint construct at the current location, after the
+/// optional scope specifier.
+///
+/// type-constraint:
+/// nested-name-specifier[opt] concept-name
+/// nested-name-specifier[opt] concept-name
+/// '<' template-argument-list[opt] '>'[opt]
+///
+/// \returns true if an error occurred, and false otherwise.
+bool Parser::TryAnnotateTypeConstraint(CXXScopeSpec &SS) {
+ if (!getLangOpts().ConceptsTS || Tok.isNot(tok::identifier))
+ return false;
+
+ UnqualifiedId PossibleConceptName;
+ PossibleConceptName.setIdentifier(Tok.getIdentifierInfo(),
+ Tok.getLocation());
+
+ TemplateTy PossibleConcept;
+ bool MemberOfUnknownSpecialization = false;
+ auto TNK = Actions.isTemplateName(getCurScope(), SS,
+ /*hasTemplateKeyword=*/false,
+ PossibleConceptName,
+ /*ObjectType=*/ParsedType(),
+ /*EnteringContext=*/false,
+ PossibleConcept,
+ MemberOfUnknownSpecialization);
+ assert(!MemberOfUnknownSpecialization
+ && "Member when we only allowed namespace scope qualifiers??");
+ if (!PossibleConcept || TNK != TNK_Concept_template)
+ return false;
+
+ // At this point we're sure we're dealing with a constrained parameter. It
+ // may or may not have a template parameter list following the concept name.
+ return AnnotateTemplateIdToken(PossibleConcept, TNK, SS,
+ /*TemplateKWLoc=*/SourceLocation(),
+ PossibleConceptName,
+ /*AllowTypeAnnotation=*/false,
+ /*TypeConstraint=*/true);
+}
+
/// ParseTypeParameter - Parse a template type parameter (C++ [temp.param]).
/// Other kinds of template parameters are parsed in
/// ParseTemplateTemplateParameter and ParseNonTypeTemplateParameter.
@@ -613,12 +739,25 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
/// 'typename' ...[opt][C++0x] identifier[opt]
/// 'typename' identifier[opt] '=' type-id
NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
- assert(Tok.isOneOf(tok::kw_class, tok::kw_typename) &&
- "A type-parameter starts with 'class' or 'typename'");
+ assert(Tok.isOneOf(tok::kw_class, tok::kw_typename, tok::annot_template_id) &&
+ "A type-parameter starts with 'class', 'typename' or a "
+ "type-constraint");
- // Consume the 'class' or 'typename' keyword.
- bool TypenameKeyword = Tok.is(tok::kw_typename);
- SourceLocation KeyLoc = ConsumeToken();
+ TemplateIdAnnotation *TypeConstraint = nullptr;
+ bool TypenameKeyword = false;
+ SourceLocation KeyLoc;
+ if (Tok.is(tok::annot_template_id)) {
+ // Consume the 'type-constraint'.
+ TypeConstraint =
+ static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ assert(TypeConstraint->Kind == TNK_Concept_template &&
+ "stray non-concept template-id annotation");
+ KeyLoc = ConsumeAnnotationToken();
+ } else {
+ // Consume the 'class' or 'typename' keyword.
+ TypenameKeyword = Tok.is(tok::kw_typename);
+ KeyLoc = ConsumeToken();
+ }
// Grab the ellipsis (if given).
SourceLocation EllipsisLoc;
@@ -658,9 +797,19 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
DefaultArg = ParseTypeName(/*Range=*/nullptr,
DeclaratorContext::TemplateTypeArgContext).get();
- return Actions.ActOnTypeParameter(getCurScope(), TypenameKeyword, EllipsisLoc,
- KeyLoc, ParamName, NameLoc, Depth, Position,
- EqualLoc, DefaultArg);
+ NamedDecl *NewDecl = Actions.ActOnTypeParameter(getCurScope(),
+ TypenameKeyword, EllipsisLoc,
+ KeyLoc, ParamName, NameLoc,
+ Depth, Position, EqualLoc,
+ DefaultArg,
+ TypeConstraint != nullptr);
+
+ if (TypeConstraint)
+ Actions.ActOnTypeConstraint(TypeConstraint,
+ cast<TemplateTypeParmDecl>(NewDecl),
+ EllipsisLoc);
+
+ return NewDecl;
}
/// ParseTemplateTemplateParameter - Handle the parsing of template
@@ -823,7 +972,7 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
// Create the parameter.
return Actions.ActOnNonTypeTemplateParameter(getCurScope(), ParamDecl,
- Depth, Position, EqualLoc,
+ Depth, Position, EqualLoc,
DefaultArg.get());
}
@@ -1099,6 +1248,10 @@ Parser::ParseTemplateIdAfterTemplateName(bool ConsumeLastToken,
/// simple-template-id is always replaced with a template-id
/// annotation token.
///
+/// \param TypeConstraint if true, then this is actually a type-constraint,
+/// meaning that the template argument list can be omitted (and the template in
+/// question must be a concept).
+///
/// If an unrecoverable parse error occurs and no annotation token can be
/// formed, this function returns true.
///
@@ -1106,10 +1259,15 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
UnqualifiedId &TemplateName,
- bool AllowTypeAnnotation) {
+ bool AllowTypeAnnotation,
+ bool TypeConstraint) {
assert(getLangOpts().CPlusPlus && "Can only annotate template-ids in C++");
- assert(Template && Tok.is(tok::less) &&
+ assert(Template && (Tok.is(tok::less) || TypeConstraint) &&
"Parser isn't at the beginning of a template-id");
+ assert(!(TypeConstraint && AllowTypeAnnotation) && "type-constraint can't be "
+ "a type annotation");
+ assert((!TypeConstraint || TNK == TNK_Concept_template) && "type-constraint "
+ "must accompany a concept name");
// Consume the template-name.
SourceLocation TemplateNameLoc = TemplateName.getSourceRange().getBegin();
@@ -1117,17 +1275,19 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
// Parse the enclosed template argument list.
SourceLocation LAngleLoc, RAngleLoc;
TemplateArgList TemplateArgs;
- bool Invalid = ParseTemplateIdAfterTemplateName(false, LAngleLoc,
- TemplateArgs,
- RAngleLoc);
+ if (!TypeConstraint || Tok.is(tok::less)) {
+ bool Invalid = ParseTemplateIdAfterTemplateName(false, LAngleLoc,
+ TemplateArgs,
+ RAngleLoc);
- if (Invalid) {
- // If we failed to parse the template ID but skipped ahead to a >, we're not
- // going to be able to form a token annotation. Eat the '>' if present.
- TryConsumeToken(tok::greater);
- // FIXME: Annotate the token stream so we don't produce the same errors
- // again if we're doing this annotation as part of a tentative parse.
- return true;
+ if (Invalid) {
+ // If we failed to parse the template ID but skipped ahead to a >, we're not
+ // going to be able to form a token annotation. Eat the '>' if present.
+ TryConsumeToken(tok::greater);
+ // FIXME: Annotate the token stream so we don't produce the same errors
+ // again if we're doing this annotation as part of a tentative parse.
+ return true;
+ }
}
ASTTemplateArgsPtr TemplateArgsPtr(TemplateArgs);
@@ -1365,8 +1525,9 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() {
// Parse a non-type template argument.
SourceLocation Loc = Tok.getLocation();
ExprResult ExprArg = ParseConstantExpressionInExprEvalContext(MaybeTypeCast);
- if (ExprArg.isInvalid() || !ExprArg.get())
+ if (ExprArg.isInvalid() || !ExprArg.get()) {
return ParsedTemplateArgument();
+ }
return ParsedTemplateArgument(ParsedTemplateArgument::NonType,
ExprArg.get(), Loc);
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index e2e16ca63d1e..4d69fb4693fb 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -1031,6 +1031,10 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
// direct-declarator '[' constant-expression[opt] ']'
// direct-abstract-declarator[opt] '[' constant-expression[opt] ']'
TPR = TryParseBracketDeclarator();
+ } else if (Tok.is(tok::kw_requires)) {
+ // declarator requires-clause
+ // A requires clause indicates a function declaration.
+ TPR = TPResult::True;
} else {
break;
}
@@ -2014,7 +2018,6 @@ Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration,
/// 'throw' '(' type-id-list[opt] ')'
///
Parser::TPResult Parser::TryParseFunctionDeclarator() {
-
// The '(' is already parsed.
TPResult TPR = TryParseParameterDeclarationClause();
@@ -2066,9 +2069,21 @@ Parser::TPResult Parser::TryParseFunctionDeclarator() {
///
Parser::TPResult Parser::TryParseBracketDeclarator() {
ConsumeBracket();
- if (!SkipUntil(tok::r_square, StopAtSemi))
+
+ // A constant-expression cannot begin with a '{', but the
+ // expr-or-braced-init-list of a postfix-expression can.
+ if (Tok.is(tok::l_brace))
+ return TPResult::False;
+
+ if (!SkipUntil(tok::r_square, tok::comma, StopAtSemi | StopBeforeMatch))
return TPResult::Error;
+ // If we hit a comma before the ']', this is not a constant-expression,
+ // but might still be the expr-or-braced-init-list of a postfix-expression.
+ if (Tok.isNot(tok::r_square))
+ return TPResult::False;
+
+ ConsumeBracket();
return TPResult::Ambiguous;
}
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 2645f27e656f..4249de361b89 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -278,6 +278,10 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) {
case tok::annot_pragma_openmp:
case tok::annot_pragma_openmp_end:
// Stop before an OpenMP pragma boundary.
+ if (OpenMPDirectiveParsing)
+ return false;
+ ConsumeAnnotationToken();
+ break;
case tok::annot_module_begin:
case tok::annot_module_end:
case tok::annot_module_include:
@@ -799,7 +803,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
SourceLocation StartLoc = Tok.getLocation();
SourceLocation EndLoc;
- ExprResult Result(ParseSimpleAsm(&EndLoc));
+ ExprResult Result(ParseSimpleAsm(/*ForAsmLabel*/ false, &EndLoc));
// Check if GNU-style InlineAsm is disabled.
// Empty asm string is allowed because it will not introduce
@@ -1463,11 +1467,14 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
/// ParseAsmStringLiteral - This is just a normal string-literal, but is not
/// allowed to be a wide string, and is not subject to character translation.
+/// Unlike GCC, we also diagnose an empty string literal when parsing for an
+/// asm label as opposed to an asm statement, because such a construct does not
+/// behave well.
///
/// [GNU] asm-string-literal:
/// string-literal
///
-ExprResult Parser::ParseAsmStringLiteral() {
+ExprResult Parser::ParseAsmStringLiteral(bool ForAsmLabel) {
if (!isTokenStringLiteral()) {
Diag(Tok, diag::err_expected_string_literal)
<< /*Source='in...'*/0 << "'asm'";
@@ -1483,6 +1490,11 @@ ExprResult Parser::ParseAsmStringLiteral() {
<< SL->getSourceRange();
return ExprError();
}
+ if (ForAsmLabel && SL->getString().empty()) {
+ Diag(Tok, diag::err_asm_operand_wide_string_literal)
+ << 2 /* an empty */ << SL->getSourceRange();
+ return ExprError();
+ }
}
return AsmString;
}
@@ -1492,7 +1504,7 @@ ExprResult Parser::ParseAsmStringLiteral() {
/// [GNU] simple-asm-expr:
/// 'asm' '(' asm-string-literal ')'
///
-ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) {
+ExprResult Parser::ParseSimpleAsm(bool ForAsmLabel, SourceLocation *EndLoc) {
assert(Tok.is(tok::kw_asm) && "Not an asm!");
SourceLocation Loc = ConsumeToken();
@@ -1512,7 +1524,7 @@ ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) {
return ExprError();
}
- ExprResult Result(ParseAsmStringLiteral());
+ ExprResult Result(ParseAsmStringLiteral(ForAsmLabel));
if (!Result.isInvalid()) {
// Close the paren and get the location of the end bracket
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 2c70c0599ecf..04611dadde66 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -1174,7 +1174,7 @@ namespace {
// We analyze lambda bodies separately. Skip them here.
bool TraverseLambdaExpr(LambdaExpr *LE) {
// Traverse the captures, but not the body.
- for (const auto &C : zip(LE->captures(), LE->capture_inits()))
+ for (const auto C : zip(LE->captures(), LE->capture_inits()))
TraverseLambdaCapture(LE, &std::get<0>(C), std::get<1>(C));
return true;
}
diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp
index c8743df90e34..960e62d4a2db 100644
--- a/clang/lib/Sema/JumpDiagnostics.cpp
+++ b/clang/lib/Sema/JumpDiagnostics.cpp
@@ -546,8 +546,8 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S,
SmallVector<const Expr *, 4> CommaLHS;
SmallVector<SubobjectAdjustment, 4> Adjustments;
const Expr *ExtendedObject =
- MTE->GetTemporaryExpr()->skipRValueSubobjectAdjustments(
- CommaLHS, Adjustments);
+ MTE->getSubExpr()->skipRValueSubobjectAdjustments(CommaLHS,
+ Adjustments);
if (ExtendedObject->getType().isDestructedType()) {
Scopes.push_back(GotoScope(ParentScope, 0,
diag::note_exits_temporary_dtor,
diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp
index b0aa67454a7b..2b0cd6b8c4fc 100644
--- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp
+++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -15,6 +15,8 @@
using namespace clang;
+char MultiplexExternalSemaSource::ID;
+
///Constructs a new multiplexing external sema source and appends the
/// given element to it.
///
diff --git a/clang/lib/Sema/OpenCLBuiltins.td b/clang/lib/Sema/OpenCLBuiltins.td
index 298614059467..9d6bb411eff8 100644
--- a/clang/lib/Sema/OpenCLBuiltins.td
+++ b/clang/lib/Sema/OpenCLBuiltins.td
@@ -40,6 +40,30 @@ def ConstantAS : AddressSpace<"clang::LangAS::opencl_constant">;
def LocalAS : AddressSpace<"clang::LangAS::opencl_local">;
def GenericAS : AddressSpace<"clang::LangAS::opencl_generic">;
+// OpenCL language extension.
+class AbstractExtension<string _Ext> {
+ // One or more OpenCL extensions, space separated. Each extension must be
+ // a valid extension name for the opencl extension pragma.
+ string ExtName = _Ext;
+}
+
+// Extension associated to a builtin function.
+class FunctionExtension<string _Ext> : AbstractExtension<_Ext>;
+
+// FunctionExtension definitions.
+def FuncExtNone : FunctionExtension<"">;
+def FuncExtKhrSubgroups : FunctionExtension<"cl_khr_subgroups">;
+def FuncExtKhrGlobalInt32BaseAtomics : FunctionExtension<"cl_khr_global_int32_base_atomics">;
+def FuncExtKhrGlobalInt32ExtendedAtomics : FunctionExtension<"cl_khr_global_int32_extended_atomics">;
+def FuncExtKhrLocalInt32BaseAtomics : FunctionExtension<"cl_khr_local_int32_base_atomics">;
+def FuncExtKhrLocalInt32ExtendedAtomics : FunctionExtension<"cl_khr_local_int32_extended_atomics">;
+def FuncExtKhrInt64BaseAtomics : FunctionExtension<"cl_khr_int64_base_atomics">;
+def FuncExtKhrInt64ExtendedAtomics : FunctionExtension<"cl_khr_int64_extended_atomics">;
+def FuncExtKhrMipmapImage : FunctionExtension<"cl_khr_mipmap_image">;
+def FuncExtKhrGlMsaaSharing : FunctionExtension<"cl_khr_gl_msaa_sharing">;
+
+// Multiple extensions
+def FuncExtKhrMipmapAndWrite3d : FunctionExtension<"cl_khr_mipmap_image cl_khr_3d_image_writes">;
// Qualified Type. These map to ASTContext::QualType.
class QualType<string _Name, bit _IsAbstract=0> {
@@ -180,18 +204,32 @@ class GenericType<string _Ty, TypeList _TypeList, IntList _VectorList> :
let VecWidth = 0;
}
+// Builtin function attributes.
+def Attr {
+ list<bit> None = [0, 0, 0];
+ list<bit> Pure = [1, 0, 0];
+ list<bit> Const = [0, 1, 0];
+ list<bit> Convergent = [0, 0, 1];
+}
+
//===----------------------------------------------------------------------===//
// OpenCL C class for builtin functions
//===----------------------------------------------------------------------===//
-class Builtin<string _Name, list<Type> _Signature> {
+class Builtin<string _Name, list<Type> _Signature, list<bit> _Attributes = Attr.None> {
// Name of the builtin function
string Name = _Name;
// List of types used by the function. The first one is the return type and
// the following are the arguments. The list must have at least one element
// (the return type).
list<Type> Signature = _Signature;
- // OpenCL Extension to which the function belongs (cl_khr_subgroups, ...)
- string Extension = "";
+ // Function attribute __attribute__((pure))
+ bit IsPure = _Attributes[0];
+ // Function attribute __attribute__((const))
+ bit IsConst = _Attributes[1];
+ // Function attribute __attribute__((convergent))
+ bit IsConv = _Attributes[2];
+ // OpenCL extensions to which the function belongs.
+ FunctionExtension Extension = FuncExtNone;
// Version of OpenCL from which the function is available (e.g.: CL10).
// MinVersion is inclusive.
Version MinVersion = CL10;
@@ -260,10 +298,25 @@ def Event : Type<"Event", QualType<"OCLEventTy">>;
def VecAndScalar: IntList<"VecAndScalar", [1, 2, 3, 4, 8, 16]>;
def VecNoScalar : IntList<"VecNoScalar", [2, 3, 4, 8, 16]>;
def Vec1 : IntList<"Vec1", [1]>;
+def Vec2 : IntList<"Vec2", [2]>;
+def Vec4 : IntList<"Vec4", [4]>;
+def Vec8 : IntList<"Vec8", [8]>;
+def Vec16 : IntList<"Vec16", [16]>;
+def Vec1234 : IntList<"Vec1234", [1, 2, 3, 4]>;
// Type lists.
-def TLAll : TypeList<"TLAll", [Char, UChar, Short, UShort, Int, UInt, Long, ULong, Float, Double, Half]>;
+def TLAll : TypeList<"TLAll", [Char, UChar, Short, UShort, Int, UInt, Long, ULong, Float, Double, Half]>;
+def TLAllUnsigned : TypeList<"TLAllUnsigned", [UChar, UChar, UShort, UShort, UInt, UInt, ULong, ULong, UInt, ULong, UShort]>;
def TLFloat : TypeList<"TLFloat", [Float, Double, Half]>;
+def TLSignedInts : TypeList<"TLSignedInts", [Char, Short, Int, Long]>;
+def TLUnsignedInts : TypeList<"TLUnsignedInts", [UChar, UShort, UInt, ULong]>;
+
+def TLIntLongFloats : TypeList<"TLIntLongFloats", [Int, UInt, Long, ULong, Float, Double, Half]>;
+
+// All unsigned integer types twice, to facilitate unsigned return types for e.g.
+// uchar abs(char) and
+// uchar abs(uchar).
+def TLAllUIntsTwice : TypeList<"TLAllUIntsTwice", [UChar, UChar, UShort, UShort, UInt, UInt, ULong, ULong]>;
def TLAllInts : TypeList<"TLAllInts", [Char, UChar, Short, UShort, Int, UInt, Long, ULong]>;
@@ -276,8 +329,16 @@ def AGenTypeNNoScalar : GenericType<"AGenTypeNNoScalar", TLAll, VecNoScalar
def AIGenType1 : GenericType<"AIGenType1", TLAllInts, Vec1>;
def AIGenTypeN : GenericType<"AIGenTypeN", TLAllInts, VecAndScalar>;
def AIGenTypeNNoScalar : GenericType<"AIGenTypeNNoScalar", TLAllInts, VecNoScalar>;
+// All integer to unsigned
+def AI2UGenTypeN : GenericType<"AI2UGenTypeN", TLAllUIntsTwice, VecAndScalar>;
+// Signed integer
+def SGenTypeN : GenericType<"SGenTypeN", TLSignedInts, VecAndScalar>;
+// Unsigned integer
+def UGenTypeN : GenericType<"UGenTypeN", TLUnsignedInts, VecAndScalar>;
// Float
def FGenTypeN : GenericType<"FGenTypeN", TLFloat, VecAndScalar>;
+// (u)int, (u)long, and all floats
+def IntLongFloatGenType1 : GenericType<"IntLongFloatGenType1", TLIntLongFloats, Vec1>;
// GenType definitions for every single base type (e.g. fp32 only).
// Names are like: GenTypeFloatVecAndScalar.
@@ -292,6 +353,14 @@ foreach Type = [Char, UChar, Short, UShort,
}
}
+// GenType definitions for vec1234.
+foreach Type = [Float, Double, Half] in {
+ def "GenType" # Type # Vec1234 :
+ GenericType<"GenType" # Type # Vec1234,
+ TypeList<"GL" # Type.Name, [Type]>,
+ Vec1234>;
+}
+
//===----------------------------------------------------------------------===//
// Definitions of OpenCL builtin functions
@@ -307,11 +376,12 @@ foreach RType = [Float, Double, Half, Char, UChar, Short,
UShort, Int, UInt, Long, ULong] in {
foreach sat = ["", "_sat"] in {
foreach rnd = ["", "_rte", "_rtn", "_rtp", "_rtz"] in {
- def : Builtin<"convert_" # RType.Name # sat # rnd, [RType, IType]>;
+ def : Builtin<"convert_" # RType.Name # sat # rnd, [RType, IType],
+ Attr.Const>;
foreach v = [2, 3, 4, 8, 16] in {
def : Builtin<"convert_" # RType.Name # v # sat # rnd,
- [VectorType<RType, v>,
- VectorType<IType, v>]>;
+ [VectorType<RType, v>, VectorType<IType, v>],
+ Attr.Const>;
}
}
}
@@ -321,11 +391,11 @@ foreach RType = [Float, Double, Half, Char, UChar, Short,
//--------------------------------------------------------------------
// OpenCL v1.1 s6.11.1, v1.2 s6.12.1, v2.0 s6.13.1 - Work-item Functions
// --- Table 7 ---
-def : Builtin<"get_work_dim", [UInt]>;
+def : Builtin<"get_work_dim", [UInt], Attr.Const>;
foreach name = ["get_global_size", "get_global_id", "get_local_size",
"get_local_id", "get_num_groups", "get_group_id",
"get_global_offset"] in {
- def : Builtin<name, [Size, UInt]>;
+ def : Builtin<name, [Size, UInt], Attr.Const>;
}
let MinVersion = CL20 in {
@@ -335,9 +405,303 @@ let MinVersion = CL20 in {
}
}
+
+//--------------------------------------------------------------------
+// OpenCL v1.1 s6.11.2, v1.2 s6.12.2, v2.0 s6.13.2 - Math functions
+// OpenCL Extension v2.0 s5.1.2 and s6.1.2 - Math Functions
+// --- Table 8 ---
+// --- 1 argument ---
+foreach name = ["acos", "acosh", "acospi",
+ "asin", "asinh", "asinpi",
+ "atan", "atanh", "atanpi",
+ "cbrt", "ceil",
+ "cos", "cosh", "cospi",
+ "erfc", "erf",
+ "exp", "exp2", "exp10", "expm1",
+ "fabs", "floor",
+ "log", "log2", "log10", "log1p", "logb",
+ "rint", "round", "rsqrt",
+ "sin", "sinh", "sinpi",
+ "sqrt",
+ "tan", "tanh", "tanpi",
+ "tgamma", "trunc",
+ "lgamma"] in {
+ def : Builtin<name, [FGenTypeN, FGenTypeN], Attr.Const>;
+}
+foreach name = ["nan"] in {
+ def : Builtin<name, [GenTypeFloatVecAndScalar, GenTypeUIntVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeDoubleVecAndScalar, GenTypeULongVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeHalfVecAndScalar, GenTypeUShortVecAndScalar], Attr.Const>;
+}
+
+// --- 2 arguments ---
+foreach name = ["atan2", "atan2pi", "copysign", "fdim", "fmod", "hypot",
+ "maxmag", "minmag", "nextafter", "pow", "powr",
+ "remainder"] in {
+ def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN], Attr.Const>;
+}
+foreach name = ["fmax", "fmin"] in {
+ def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN], Attr.Const>;
+ def : Builtin<name, [GenTypeFloatVecNoScalar, GenTypeFloatVecNoScalar, Float], Attr.Const>;
+ def : Builtin<name, [GenTypeDoubleVecNoScalar, GenTypeDoubleVecNoScalar, Double], Attr.Const>;
+ def : Builtin<name, [GenTypeHalfVecNoScalar, GenTypeHalfVecNoScalar, Half], Attr.Const>;
+}
+foreach name = ["ilogb"] in {
+ def : Builtin<name, [GenTypeIntVecAndScalar, GenTypeFloatVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeIntVecAndScalar, GenTypeDoubleVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeIntVecAndScalar, GenTypeHalfVecAndScalar], Attr.Const>;
+}
+foreach name = ["ldexp"] in {
+ def : Builtin<name, [GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeFloatVecNoScalar, GenTypeFloatVecNoScalar, Int], Attr.Const>;
+ def : Builtin<name, [GenTypeDoubleVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeDoubleVecNoScalar, GenTypeDoubleVecNoScalar, Int], Attr.Const>;
+ def : Builtin<name, [GenTypeHalfVecAndScalar, GenTypeHalfVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeHalfVecNoScalar, GenTypeHalfVecNoScalar, Int], Attr.Const>;
+}
+foreach name = ["pown", "rootn"] in {
+ def : Builtin<name, [GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeDoubleVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeHalfVecAndScalar, GenTypeHalfVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>;
+}
+
+// --- 3 arguments ---
+foreach name = ["fma", "mad"] in {
+ def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN, FGenTypeN], Attr.Const>;
+}
+
+// --- Version dependent ---
+let MaxVersion = CL20 in {
+ foreach AS = [GlobalAS, LocalAS, PrivateAS] in {
+ foreach name = ["fract", "modf", "sincos"] in {
+ def : Builtin<name, [FGenTypeN, FGenTypeN, PointerType<FGenTypeN, AS>]>;
+ }
+ foreach name = ["frexp", "lgamma_r"] in {
+ foreach Type = [GenTypeFloatVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeHalfVecAndScalar] in {
+ def : Builtin<name, [Type, Type, PointerType<GenTypeIntVecAndScalar, AS>]>;
+ }
+ }
+ foreach name = ["remquo"] in {
+ foreach Type = [GenTypeFloatVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeHalfVecAndScalar] in {
+ def : Builtin<name, [Type, Type, Type, PointerType<GenTypeIntVecAndScalar, AS>]>;
+ }
+ }
+ }
+}
+let MinVersion = CL20 in {
+ foreach name = ["fract", "modf", "sincos"] in {
+ def : Builtin<name, [FGenTypeN, FGenTypeN, PointerType<FGenTypeN, GenericAS>]>;
+ }
+ foreach name = ["frexp", "lgamma_r"] in {
+ foreach Type = [GenTypeFloatVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeHalfVecAndScalar] in {
+ def : Builtin<name, [Type, Type, PointerType<GenTypeIntVecAndScalar, GenericAS>]>;
+ } }
+ foreach name = ["remquo"] in {
+ foreach Type = [GenTypeFloatVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeHalfVecAndScalar] in {
+ def : Builtin<name, [Type, Type, Type, PointerType<GenTypeIntVecAndScalar, GenericAS>]>;
+ }
+ }
+}
+
+// --- Table 9 ---
+foreach name = ["half_cos",
+ "half_exp", "half_exp2", "half_exp10",
+ "half_log", "half_log2", "half_log10",
+ "half_recip", "half_rsqrt",
+ "half_sin", "half_sqrt", "half_tan",
+ "native_cos",
+ "native_exp", "native_exp2", "native_exp10",
+ "native_log", "native_log2", "native_log10",
+ "native_recip", "native_rsqrt",
+ "native_sin", "native_sqrt", "native_tan"] in {
+ def : Builtin<name, [GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar], Attr.Const>;
+}
+foreach name = ["half_divide", "half_powr",
+ "native_divide", "native_powr"] in {
+ def : Builtin<name, [GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar], Attr.Const>;
+}
+
+//--------------------------------------------------------------------
+// OpenCL v1.1 s6.11.3, v1.2 s6.12.3, v2.0 s6.13.3 - Integer Functions
+// --- Table 10 ---
+// --- 1 argument ---
+foreach name = ["abs"] in {
+ def : Builtin<name, [AI2UGenTypeN, AIGenTypeN], Attr.Const>;
+}
+foreach name = ["clz", "popcount"] in {
+ def : Builtin<name, [AIGenTypeN, AIGenTypeN], Attr.Const>;
+}
+let MinVersion = CL20 in {
+ foreach name = ["ctz"] in {
+ def : Builtin<name, [AIGenTypeN, AIGenTypeN]>;
+ }
+}
+
+// --- 2 arguments ---
+foreach name = ["abs_diff"] in {
+ def : Builtin<name, [AI2UGenTypeN, AIGenTypeN, AIGenTypeN], Attr.Const>;
+}
+foreach name = ["add_sat", "hadd", "rhadd", "mul_hi", "rotate", "sub_sat"] in {
+ def : Builtin<name, [AIGenTypeN, AIGenTypeN, AIGenTypeN], Attr.Const>;
+}
+foreach name = ["max", "min"] in {
+ def : Builtin<name, [AIGenTypeN, AIGenTypeN, AIGenTypeN], Attr.Const>;
+ def : Builtin<name, [AIGenTypeNNoScalar, AIGenTypeNNoScalar, AIGenType1], Attr.Const>;
+}
+foreach name = ["upsample"] in {
+ def : Builtin<name, [GenTypeShortVecAndScalar, GenTypeCharVecAndScalar, GenTypeUCharVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeUShortVecAndScalar, GenTypeUCharVecAndScalar, GenTypeUCharVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeIntVecAndScalar, GenTypeShortVecAndScalar, GenTypeUShortVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeUIntVecAndScalar, GenTypeUShortVecAndScalar, GenTypeUShortVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeLongVecAndScalar, GenTypeIntVecAndScalar, GenTypeUIntVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeULongVecAndScalar, GenTypeUIntVecAndScalar, GenTypeUIntVecAndScalar], Attr.Const>;
+}
+
+// --- 3 arguments ---
+foreach name = ["clamp"] in {
+ def : Builtin<name, [AIGenTypeN, AIGenTypeN, AIGenTypeN, AIGenTypeN], Attr.Const>;
+ def : Builtin<name, [AIGenTypeNNoScalar, AIGenTypeNNoScalar, AIGenType1, AIGenType1], Attr.Const>;
+}
+foreach name = ["mad_hi", "mad_sat"] in {
+ def : Builtin<name, [AIGenTypeN, AIGenTypeN, AIGenTypeN, AIGenTypeN], Attr.Const>;
+}
+
+// --- Table 11 ---
+foreach name = ["mad24"] in {
+ def : Builtin<name, [GenTypeIntVecAndScalar, GenTypeIntVecAndScalar, GenTypeIntVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeUIntVecAndScalar, GenTypeUIntVecAndScalar, GenTypeUIntVecAndScalar, GenTypeUIntVecAndScalar], Attr.Const>;
+}
+foreach name = ["mul24"] in {
+ def : Builtin<name, [GenTypeIntVecAndScalar, GenTypeIntVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeUIntVecAndScalar, GenTypeUIntVecAndScalar, GenTypeUIntVecAndScalar], Attr.Const>;
+}
+
+//--------------------------------------------------------------------
+// OpenCL v1.1 s6.11.4, v1.2 s6.12.4, v2.0 s6.13.4 - Common Functions
+// OpenCL Extension v2.0 s5.1.3 and s6.1.3 - Common Functions
+// --- Table 12 ---
+// --- 1 argument ---
+foreach name = ["degrees", "radians", "sign"] in {
+ def : Builtin<name, [FGenTypeN, FGenTypeN], Attr.Const>;
+}
+
+// --- 2 arguments ---
+foreach name = ["max", "min"] in {
+ def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN], Attr.Const>;
+ def : Builtin<name, [GenTypeFloatVecNoScalar, GenTypeFloatVecNoScalar, Float], Attr.Const>;
+ def : Builtin<name, [GenTypeDoubleVecNoScalar, GenTypeDoubleVecNoScalar, Double], Attr.Const>;
+ def : Builtin<name, [GenTypeHalfVecNoScalar, GenTypeHalfVecNoScalar, Half], Attr.Const>;
+}
+foreach name = ["step"] in {
+ def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN], Attr.Const>;
+ def : Builtin<name, [GenTypeFloatVecNoScalar, Float, GenTypeFloatVecNoScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeDoubleVecNoScalar, Double, GenTypeDoubleVecNoScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeHalfVecNoScalar, Half, GenTypeHalfVecNoScalar], Attr.Const>;
+}
+
+// --- 3 arguments ---
+foreach name = ["clamp", "mix"] in {
+ def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN, FGenTypeN], Attr.Const>;
+ def : Builtin<name, [GenTypeFloatVecNoScalar, GenTypeFloatVecNoScalar, Float, Float], Attr.Const>;
+ def : Builtin<name, [GenTypeDoubleVecNoScalar, GenTypeDoubleVecNoScalar, Double, Double], Attr.Const>;
+ def : Builtin<name, [GenTypeHalfVecNoScalar, GenTypeHalfVecNoScalar, Half, Half], Attr.Const>;
+}
+foreach name = ["smoothstep"] in {
+ def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN, FGenTypeN], Attr.Const>;
+ def : Builtin<name, [GenTypeFloatVecNoScalar, Float, Float, GenTypeFloatVecNoScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeDoubleVecNoScalar, Double, Double, GenTypeDoubleVecNoScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeHalfVecNoScalar, Half, Half, GenTypeHalfVecNoScalar], Attr.Const>;
+}
+
+
+//--------------------------------------------------------------------
+// OpenCL v1.1 s6.11.5, v1.2 s6.12.5, v2.0 s6.13.5 - Geometric Functions
+// OpenCL Extension v2.0 s5.1.4 and s6.1.4 - Geometric Functions
+// --- Table 13 ---
+// --- 1 argument ---
+foreach name = ["length"] in {
+ def : Builtin<name, [Float, GenTypeFloatVec1234], Attr.Const>;
+ def : Builtin<name, [Double, GenTypeDoubleVec1234], Attr.Const>;
+ def : Builtin<name, [Half, GenTypeHalfVec1234], Attr.Const>;
+}
+foreach name = ["normalize"] in {
+ def : Builtin<name, [GenTypeFloatVec1234, GenTypeFloatVec1234], Attr.Const>;
+ def : Builtin<name, [GenTypeDoubleVec1234, GenTypeDoubleVec1234], Attr.Const>;
+ def : Builtin<name, [GenTypeHalfVec1234, GenTypeHalfVec1234], Attr.Const>;
+}
+foreach name = ["fast_length"] in {
+ def : Builtin<name, [Float, GenTypeFloatVec1234], Attr.Const>;
+}
+foreach name = ["fast_normalize"] in {
+ def : Builtin<name, [GenTypeFloatVec1234, GenTypeFloatVec1234], Attr.Const>;
+}
+
+// --- 2 arguments ---
+foreach name = ["cross"] in {
+ foreach VSize = [3, 4] in {
+ def : Builtin<name, [VectorType<Float, VSize>, VectorType<Float, VSize>, VectorType<Float, VSize>], Attr.Const>;
+ def : Builtin<name, [VectorType<Double, VSize>, VectorType<Double, VSize>, VectorType<Double, VSize>], Attr.Const>;
+ def : Builtin<name, [VectorType<Half, VSize>, VectorType<Half, VSize>, VectorType<Half, VSize>], Attr.Const>;
+ }
+}
+foreach name = ["dot", "distance"] in {
+ def : Builtin<name, [Float, GenTypeFloatVec1234, GenTypeFloatVec1234], Attr.Const>;
+ def : Builtin<name, [Double, GenTypeDoubleVec1234, GenTypeDoubleVec1234], Attr.Const>;
+ def : Builtin<name, [Half, GenTypeHalfVec1234, GenTypeHalfVec1234], Attr.Const>;
+}
+foreach name = ["fast_distance"] in {
+ def : Builtin<name, [Float, GenTypeFloatVec1234, GenTypeFloatVec1234], Attr.Const>;
+}
+
+
+//--------------------------------------------------------------------
+// OpenCL v1.1 s6.11.6, v1.2 s6.12.6, v2.0 s6.13.6 - Relational Functions
+// OpenCL Extension v2.0 s5.1.5 and s6.1.5 - Relational Functions
+// --- Table 14 ---
+// --- 1 argument ---
+foreach name = ["isfinite", "isinf", "isnan", "isnormal", "signbit"] in {
+ def : Builtin<name, [GenTypeIntVecAndScalar, GenTypeFloatVecAndScalar], Attr.Const>;
+ def : Builtin<name, [Int, Double], Attr.Const>;
+ def : Builtin<name, [GenTypeLongVecNoScalar, GenTypeDoubleVecNoScalar], Attr.Const>;
+ def : Builtin<name, [Int, Half], Attr.Const>;
+ def : Builtin<name, [GenTypeShortVecNoScalar, GenTypeHalfVecNoScalar], Attr.Const>;
+}
+foreach name = ["any", "all"] in {
+ def : Builtin<name, [Int, AIGenTypeN], Attr.Const>;
+}
+
+// --- 2 arguments ---
+foreach name = ["isequal", "isnotequal", "isgreater", "isgreaterequal",
+ "isless", "islessequal", "islessgreater", "isordered",
+ "isunordered"] in {
+ def : Builtin<name, [GenTypeIntVecAndScalar, GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar], Attr.Const>;
+ def : Builtin<name, [Int, Double, Double], Attr.Const>;
+ def : Builtin<name, [GenTypeLongVecNoScalar, GenTypeDoubleVecNoScalar, GenTypeDoubleVecNoScalar], Attr.Const>;
+ def : Builtin<name, [Int, Half, Half], Attr.Const>;
+ def : Builtin<name, [GenTypeShortVecNoScalar, GenTypeHalfVecNoScalar, GenTypeHalfVecNoScalar], Attr.Const>;
+}
+
+// --- 3 arguments ---
+foreach name = ["bitselect"] in {
+ def : Builtin<name, [AGenTypeN, AGenTypeN, AGenTypeN, AGenTypeN], Attr.Const>;
+}
+foreach name = ["select"] in {
+ def : Builtin<name, [SGenTypeN, SGenTypeN, SGenTypeN, SGenTypeN], Attr.Const>;
+ def : Builtin<name, [SGenTypeN, SGenTypeN, SGenTypeN, UGenTypeN], Attr.Const>;
+ def : Builtin<name, [UGenTypeN, UGenTypeN, UGenTypeN, UGenTypeN], Attr.Const>;
+ def : Builtin<name, [UGenTypeN, UGenTypeN, UGenTypeN, SGenTypeN], Attr.Const>;
+ def : Builtin<name, [GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar, GenTypeUIntVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeDoubleVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeLongVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeDoubleVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeULongVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeHalfVecAndScalar, GenTypeHalfVecAndScalar, GenTypeHalfVecAndScalar, GenTypeShortVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeHalfVecAndScalar, GenTypeHalfVecAndScalar, GenTypeHalfVecAndScalar, GenTypeUShortVecAndScalar], Attr.Const>;
+}
+
+
//--------------------------------------------------------------------
// OpenCL v1.1 s6.11.7, v1.2 s6.12.7, v2.0 s6.13.7 - Vector Data Load and Store Functions
-// OpenCL Extension v1.1 s9.3.6 and s9.6.6, v1.2 s9.5.6, v2.0 s9.4.6, v2.0 s5.1.6 and 6.1.6 - Vector Data Load and Store Functions
+// OpenCL Extension v1.1 s9.3.6 and s9.6.6, v1.2 s9.5.6, v2.0 s5.1.6 and s6.1.6 - Vector Data Load and Store Functions
// --- Table 15 ---
// Variants for OpenCL versions below 2.0, using pointers to the global, local
// and private address spaces.
@@ -448,6 +812,55 @@ foreach VSize = [2, 3, 4, 8, 16] in {
}
}
}
+let MaxVersion = CL20 in {
+ foreach AS = [GlobalAS, LocalAS, PrivateAS] in {
+ def : Builtin<"vload_half", [Float, Size, PointerType<ConstType<Half>, AS>]>;
+ foreach VSize = [2, 3, 4, 8, 16] in {
+ foreach name = ["vload_half" # VSize] in {
+ def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, AS>]>;
+ }
+ }
+ foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in {
+ def : Builtin<"vstore_half" # rnd, [Void, Float, Size, PointerType<Half, AS>]>;
+ def : Builtin<"vstore_half" # rnd, [Void, Double, Size, PointerType<Half, AS>]>;
+ foreach VSize = [2, 3, 4, 8, 16] in {
+ foreach name = ["vstore_half" # VSize # rnd] in {
+ def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<Half, AS>]>;
+ def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<Half, AS>]>;
+ }
+ }
+ }
+ }
+}
+let MinVersion = CL20 in {
+ foreach AS = [GenericAS] in {
+ def : Builtin<"vload_half", [Float, Size, PointerType<ConstType<Half>, AS>]>;
+ foreach VSize = [2, 3, 4, 8, 16] in {
+ foreach name = ["vload_half" # VSize] in {
+ def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, AS>]>;
+ }
+ }
+ foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in {
+ def : Builtin<"vstore_half" # rnd, [Void, Float, Size, PointerType<Half, AS>]>;
+ def : Builtin<"vstore_half" # rnd, [Void, Double, Size, PointerType<Half, AS>]>;
+ foreach VSize = [2, 3, 4, 8, 16] in {
+ foreach name = ["vstore_half" # VSize # rnd] in {
+ def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<Half, AS>]>;
+ def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<Half, AS>]>;
+ }
+ }
+ }
+ }
+}
+
+foreach AS = [ConstantAS] in {
+ def : Builtin<"vload_half", [Float, Size, PointerType<ConstType<Half>, AS>]>;
+ foreach VSize = [2, 3, 4, 8, 16] in {
+ foreach name = ["vload_half" # VSize] in {
+ def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, AS>]>;
+ }
+ }
+}
//--------------------------------------------------------------------
// OpenCL v1.1 s6.11.10, v1.2 s6.12.10, v2.0 s6.13.10: Async Copies from Global to Local Memory, Local to Global Memory, and Prefetch
@@ -473,42 +886,116 @@ foreach name = ["prefetch"] in {
// Functions that use memory_order and cl_mem_fence_flags enums are not
// declared here as the TableGen backend does not handle enums.
-// OpenCL v1.0 s9.5, s9.6, s9.7 - Atomic Functions for 32-bit integers.
+// OpenCL v1.0 s9.5, s9.6, s9.7 - Atomic Functions for 32-bit integers
// --- Table 9.1 ---
-foreach Type = [Int, UInt] in {
- foreach name = ["atom_add", "atom_sub", "atom_xchg"] in {
- def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>, Type]>;
+let Extension = FuncExtKhrGlobalInt32BaseAtomics in {
+ foreach Type = [Int, UInt] in {
+ foreach name = ["atom_add", "atom_sub", "atom_xchg"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>, Type]>;
+ }
+ foreach name = ["atom_inc", "atom_dec"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>]>;
+ }
+ foreach name = ["atom_cmpxchg"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>, Type, Type]>;
+ }
+ }
+}
+// --- Table 9.3 ---
+let Extension = FuncExtKhrLocalInt32BaseAtomics in {
+ foreach Type = [Int, UInt] in {
+ foreach name = ["atom_add", "atom_sub", "atom_xchg"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, LocalAS>, Type]>;
+ }
+ foreach name = ["atom_inc", "atom_dec"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, LocalAS>]>;
+ }
+ foreach name = ["atom_cmpxchg"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, LocalAS>, Type, Type]>;
+ }
+ }
+}
+// --- Table 9.5 ---
+let Extension = FuncExtKhrInt64BaseAtomics in {
+ foreach AS = [GlobalAS, LocalAS] in {
+ foreach Type = [Long, ULong] in {
+ foreach name = ["atom_add", "atom_sub", "atom_xchg"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, AS>, Type]>;
+ }
+ foreach name = ["atom_inc", "atom_dec"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, AS>]>;
+ }
+ foreach name = ["atom_cmpxchg"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, AS>, Type, Type]>;
+ }
+ }
}
- foreach name = ["atom_inc", "atom_dec"] in {
- def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>]>;
+}
+// --- Table 9.2 ---
+let Extension = FuncExtKhrGlobalInt32ExtendedAtomics in {
+ foreach Type = [Int, UInt] in {
+ foreach name = ["atom_min", "atom_max", "atom_and",
+ "atom_or", "atom_xor"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>, Type]>;
+ }
}
- foreach name = ["atom_cmpxchg"] in {
- def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>, Type, Type]>;
+}
+// --- Table 9.4 ---
+let Extension = FuncExtKhrLocalInt32ExtendedAtomics in {
+ foreach Type = [Int, UInt] in {
+ foreach name = ["atom_min", "atom_max", "atom_and",
+ "atom_or", "atom_xor"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, LocalAS>, Type]>;
+ }
}
}
-
-// OpenCL v1.2 s6.12.2: Math Functions
-foreach name = ["acos", "acosh", "acospi",
- "asin", "asinh", "asinpi",
- "atan", "atanh", "atanpi"] in {
- def : Builtin<name, [FGenTypeN, FGenTypeN]>;
+// --- Table 9.6 ---
+let Extension = FuncExtKhrInt64ExtendedAtomics in {
+ foreach AS = [GlobalAS, LocalAS] in {
+ foreach Type = [Long, ULong] in {
+ foreach name = ["atom_min", "atom_max", "atom_and",
+ "atom_or", "atom_xor"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, AS>, Type]>;
+ }
+ }
+ }
}
-
-foreach name = ["atan2", "atan2pi"] in {
- def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN]>;
+// OpenCL v1.1 s6.11.1, v1.2 s6.12.11 - Atomic Functions
+foreach AS = [GlobalAS, LocalAS] in {
+ foreach Type = [Int, UInt] in {
+ foreach name = ["atomic_add", "atomic_sub", "atomic_xchg",
+ "atomic_min", "atomic_max", "atomic_and",
+ "atomic_or", "atomic_xor"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, AS>, Type]>;
+ }
+ foreach name = ["atomic_inc", "atomic_dec"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, AS>]>;
+ }
+ foreach name = ["atomic_cmpxchg"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, AS>, Type, Type]>;
+ }
+ }
}
-foreach name = ["fmax", "fmin"] in {
- def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN]>;
- def : Builtin<name, [GenTypeFloatVecNoScalar, GenTypeFloatVecNoScalar, Float]>;
- def : Builtin<name, [GenTypeDoubleVecNoScalar, GenTypeDoubleVecNoScalar, Double]>;
- def : Builtin<name, [GenTypeHalfVecNoScalar, GenTypeHalfVecNoScalar, Half]>;
+//--------------------------------------------------------------------
+// OpenCL v1.1 s6.11.12, v1.2 s6.12.12, v2.0 s6.13.12 - Miscellaneous Vector Functions
+// --- Table 19 ---
+foreach VSize1 = [Vec2, Vec4, Vec8, Vec16] in {
+ foreach VSize2 = [Vec2, Vec4, Vec8, Vec16] in {
+ def : Builtin<"shuffle", [GenericType<"TLAll" # VSize1.Name, TLAll, VSize1>,
+ GenericType<"TLAll" # VSize2.Name, TLAll, VSize2>,
+ GenericType<"TLAllUnsigned" # VSize1.Name, TLAllUnsigned, VSize1>],
+ Attr.Const>;
+ }
}
-
-// OpenCL v1.1 s6.11.3, v1.2 s6.12.3, v2.0 s6.13.3 - Integer Functions
-foreach name = ["max", "min"] in {
- def : Builtin<name, [AIGenTypeN, AIGenTypeN, AIGenTypeN]>;
- def : Builtin<name, [AIGenTypeNNoScalar, AIGenTypeNNoScalar, AIGenType1]>;
+foreach VSize1 = [Vec2, Vec4, Vec8, Vec16] in {
+ foreach VSize2 = [Vec2, Vec4, Vec8, Vec16] in {
+ def : Builtin<"shuffle2", [GenericType<"TLAll" # VSize1.Name, TLAll, VSize1>,
+ GenericType<"TLAll" # VSize2.Name, TLAll, VSize2>,
+ GenericType<"TLAll" # VSize2.Name, TLAll, VSize2>,
+ GenericType<"TLAllUnsigned" # VSize1.Name, TLAllUnsigned, VSize1>],
+ Attr.Const>;
+ }
}
//--------------------------------------------------------------------
@@ -517,49 +1004,49 @@ foreach name = ["max", "min"] in {
// --- Table 22: Image Read Functions with Samplers ---
foreach imgTy = [Image1d] in {
foreach coordTy = [Int, Float] in {
- def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, coordTy]>;
- def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, coordTy]>;
- def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, coordTy]>;
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, coordTy], Attr.Pure>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, coordTy], Attr.Pure>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, coordTy], Attr.Pure>;
}
}
foreach imgTy = [Image2d, Image1dArray] in {
foreach coordTy = [Int, Float] in {
- def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>]>;
- def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>]>;
- def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>]>;
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>], Attr.Pure>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>], Attr.Pure>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>], Attr.Pure>;
}
}
foreach imgTy = [Image3d, Image2dArray] in {
foreach coordTy = [Int, Float] in {
- def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>]>;
- def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>]>;
- def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>]>;
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>], Attr.Pure>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>], Attr.Pure>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>], Attr.Pure>;
}
}
foreach coordTy = [Int, Float] in {
- def : Builtin<"read_imagef", [Float, ImageType<Image2dDepth, "RO">, Sampler, VectorType<coordTy, 2>]>;
- def : Builtin<"read_imagef", [Float, ImageType<Image2dArrayDepth, "RO">, Sampler, VectorType<coordTy, 4>]>;
+ def : Builtin<"read_imagef", [Float, ImageType<Image2dDepth, "RO">, Sampler, VectorType<coordTy, 2>], Attr.Pure>;
+ def : Builtin<"read_imagef", [Float, ImageType<Image2dArrayDepth, "RO">, Sampler, VectorType<coordTy, 4>], Attr.Pure>;
}
// --- Table 23: Sampler-less Read Functions ---
foreach aQual = ["RO", "RW"] in {
foreach imgTy = [Image2d, Image1dArray] in {
- def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>]>;
- def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>]>;
- def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>]>;
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>], Attr.Pure>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>], Attr.Pure>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>], Attr.Pure>;
}
foreach imgTy = [Image3d, Image2dArray] in {
- def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>;
- def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>;
- def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>;
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>], Attr.Pure>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>], Attr.Pure>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>], Attr.Pure>;
}
foreach imgTy = [Image1d, Image1dBuffer] in {
- def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, Int]>;
- def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, Int]>;
- def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Int]>;
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, Int], Attr.Pure>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, Int], Attr.Pure>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Int], Attr.Pure>;
}
- def : Builtin<"read_imagef", [Float, ImageType<Image2dDepth, aQual>, VectorType<Int, 2>]>;
- def : Builtin<"read_imagef", [Float, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>]>;
+ def : Builtin<"read_imagef", [Float, ImageType<Image2dDepth, aQual>, VectorType<Int, 2>], Attr.Pure>;
+ def : Builtin<"read_imagef", [Float, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>], Attr.Pure>;
}
// --- Table 24: Image Write Functions ---
@@ -624,13 +1111,13 @@ foreach aQual = ["RO"] in {
foreach name = ["read_imageh"] in {
foreach coordTy = [Int, Float] in {
foreach imgTy = [Image2d, Image1dArray] in {
- def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<coordTy, 2>]>;
+ def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<coordTy, 2>], Attr.Pure>;
}
foreach imgTy = [Image3d, Image2dArray] in {
- def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<coordTy, 4>]>;
+ def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<coordTy, 4>], Attr.Pure>;
}
foreach imgTy = [Image1d] in {
- def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, coordTy]>;
+ def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, coordTy], Attr.Pure>;
}
}
}
@@ -640,13 +1127,13 @@ foreach aQual = ["RO"] in {
foreach aQual = ["RO", "RW"] in {
foreach name = ["read_imageh"] in {
foreach imgTy = [Image2d, Image1dArray] in {
- def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>]>;
+ def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>], Attr.Pure>;
}
foreach imgTy = [Image3d, Image2dArray] in {
- def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>;
+ def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>], Attr.Pure>;
}
foreach imgTy = [Image1d, Image1dBuffer] in {
- def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Int]>;
+ def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Int], Attr.Pure>;
}
}
}
@@ -664,11 +1151,201 @@ foreach aQual = ["WO", "RW"] in {
}
+//--------------------------------------------------------------------
+// OpenCL v2.0 s6.13.15 - Work-group Functions
+// --- Table 26 ---
+let MinVersion = CL20 in {
+ foreach name = ["work_group_all", "work_group_any"] in {
+ def : Builtin<name, [Int, Int], Attr.Convergent>;
+ }
+ foreach name = ["work_group_broadcast"] in {
+ def : Builtin<name, [IntLongFloatGenType1, IntLongFloatGenType1, Size], Attr.Convergent>;
+ def : Builtin<name, [IntLongFloatGenType1, IntLongFloatGenType1, Size, Size], Attr.Convergent>;
+ def : Builtin<name, [IntLongFloatGenType1, IntLongFloatGenType1, Size, Size, Size], Attr.Convergent>;
+ }
+ foreach op = ["add", "min", "max"] in {
+ foreach name = ["work_group_reduce_", "work_group_scan_exclusive_",
+ "work_group_scan_inclusive_"] in {
+ def : Builtin<name # op, [IntLongFloatGenType1, IntLongFloatGenType1], Attr.Convergent>;
+ }
+ }
+}
+
+
// OpenCL v2.0 s9.17.3: Additions to section 6.13.1: Work-Item Functions
let MinVersion = CL20 in {
- let Extension = "cl_khr_subgroups" in {
+ let Extension = FuncExtKhrSubgroups in {
def get_sub_group_size : Builtin<"get_sub_group_size", [UInt]>;
def get_max_sub_group_size : Builtin<"get_max_sub_group_size", [UInt]>;
def get_num_sub_groups : Builtin<"get_num_sub_groups", [UInt]>;
}
}
+
+//--------------------------------------------------------------------
+// End of the builtin functions defined in the OpenCL C specification.
+// Builtin functions defined in the OpenCL C Extension are below.
+//--------------------------------------------------------------------
+
+
+// OpenCL Extension v2.0 s9.18 - Mipmaps
+let Extension = FuncExtKhrMipmapImage in {
+ // Added to section 6.13.14.2.
+ foreach aQual = ["RO"] in {
+ foreach imgTy = [Image2d] in {
+ foreach name = ["read_imagef"] in {
+ def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, VectorType<Float, 2>, VectorType<Float, 2>], Attr.Pure>;
+ }
+ foreach name = ["read_imagei"] in {
+ def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, VectorType<Float, 2>, VectorType<Float, 2>], Attr.Pure>;
+ }
+ foreach name = ["read_imageui"] in {
+ def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, VectorType<Float, 2>, VectorType<Float, 2>], Attr.Pure>;
+ }
+ }
+ foreach imgTy = [Image2dDepth] in {
+ foreach name = ["read_imagef"] in {
+ def : Builtin<name, [Float, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float], Attr.Pure>;
+ def : Builtin<name, [Float, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, VectorType<Float, 2>, VectorType<Float, 2>], Attr.Pure>;
+ }
+ }
+ foreach imgTy = [Image1d] in {
+ foreach name = ["read_imagef"] in {
+ def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, Float, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, Float, Float, Float], Attr.Pure>;
+ }
+ foreach name = ["read_imagei"] in {
+ def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, Float, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, Float, Float, Float], Attr.Pure>;
+ }
+ foreach name = ["read_imageui"] in {
+ def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, Float, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, Float, Float, Float], Attr.Pure>;
+ }
+ }
+ foreach imgTy = [Image3d] in {
+ foreach name = ["read_imagef"] in {
+ def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, VectorType<Float, 4>, VectorType<Float, 4>], Attr.Pure>;
+ def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, Float], Attr.Pure>;
+ }
+ foreach name = ["read_imagei"] in {
+ def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, VectorType<Float, 4>, VectorType<Float, 4>], Attr.Pure>;
+ def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, Float], Attr.Pure>;
+ }
+ foreach name = ["read_imageui"] in {
+ def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, VectorType<Float, 4>, VectorType<Float, 4>], Attr.Pure>;
+ def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, Float], Attr.Pure>;
+ }
+ }
+ foreach imgTy = [Image1dArray] in {
+ foreach name = ["read_imagef"] in {
+ def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float, Float], Attr.Pure>;
+ }
+ foreach name = ["read_imagei"] in {
+ def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float, Float], Attr.Pure>;
+ }
+ foreach name = ["read_imageui"] in {
+ def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float, Float], Attr.Pure>;
+ }
+ }
+ foreach imgTy = [Image2dArray] in {
+ foreach name = ["read_imagef"] in {
+ def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, VectorType<Float, 2>, VectorType<Float, 2>], Attr.Pure>;
+ }
+ foreach name = ["read_imagei"] in {
+ def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, VectorType<Float, 2>, VectorType<Float, 2>], Attr.Pure>;
+ }
+ foreach name = ["read_imageui"] in {
+ def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, VectorType<Float, 2>, VectorType<Float, 2>], Attr.Pure>;
+ }
+ }
+ foreach imgTy = [Image2dArrayDepth] in {
+ foreach name = ["read_imagef"] in {
+ def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, VectorType<Float, 2>, VectorType<Float, 2>], Attr.Pure>;
+ }
+ }
+ }
+ // Added to section 6.13.14.4.
+ foreach aQual = ["WO"] in {
+ foreach imgTy = [Image2d] in {
+ def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int, VectorType<Float, 4>]>;
+ def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int, VectorType<Int, 4>]>;
+ def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int, VectorType<UInt, 4>]>;
+ }
+ def : Builtin<"write_imagef", [Void, ImageType<Image2dDepth, aQual>, VectorType<Int, 2>, Int, Float]>;
+ foreach imgTy = [Image1d] in {
+ def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, Int, Int, VectorType<Float, 4>]>;
+ def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, Int, Int, VectorType<Int, 4>]>;
+ def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, Int, Int, VectorType<UInt, 4>]>;
+ }
+ foreach imgTy = [Image1dArray] in {
+ def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int, VectorType<Float, 4>]>;
+ def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int, VectorType<Int, 4>]>;
+ def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int, VectorType<UInt, 4>]>;
+ }
+ foreach imgTy = [Image2dArray] in {
+ def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<Float, 4>]>;
+ def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<Int, 4>]>;
+ def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<UInt, 4>]>;
+ }
+ def : Builtin<"write_imagef", [Void, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>, Int, Float]>;
+ let Extension = FuncExtKhrMipmapAndWrite3d in {
+ foreach imgTy = [Image3d] in {
+ def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<Float, 4>]>;
+ def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<Int, 4>]>;
+ def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<UInt, 4>]>;
+ }
+ }
+ }
+ // Added to section 6.13.14.5
+ foreach aQual = ["RO", "WO", "RW"] in {
+ foreach imgTy = [Image1d, Image2d, Image3d, Image1dArray, Image2dArray, Image2dDepth, Image2dArrayDepth] in {
+ def : Builtin<"get_image_num_mip_levels", [Int, ImageType<imgTy, aQual>]>;
+ }
+ }
+}
+
+
+//--------------------------------------------------------------------
+// OpenCL Extension v2.0 s18.3 - Creating OpenCL Memory Objects from OpenGL MSAA Textures
+let Extension = FuncExtKhrGlMsaaSharing in {
+ // --- Table 6.13.14.3 ---
+ foreach aQual = ["RO", "RW"] in {
+ foreach imgTy = [Image2dMsaa] in {
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int], Attr.Pure>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int], Attr.Pure>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int], Attr.Pure>;
+ }
+ foreach imgTy = [Image2dArrayMsaa] in {
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int], Attr.Pure>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int], Attr.Pure>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int], Attr.Pure>;
+ }
+ foreach name = ["read_imagef"] in {
+ def : Builtin<name, [Float, ImageType<Image2dMsaaDepth, aQual>, VectorType<Int, 2>, Int], Attr.Pure>;
+ def : Builtin<name, [Float, ImageType<Image2dArrayMsaaDepth, aQual>, VectorType<Int, 4>, Int], Attr.Pure>;
+ }
+ }
+
+ // --- Table 6.13.14.5 ---
+ foreach aQual = ["RO", "WO", "RW"] in {
+ foreach imgTy = [Image2dMsaa, Image2dArrayMsaa, Image2dMsaaDepth, Image2dArrayMsaaDepth] in {
+ foreach name = ["get_image_width", "get_image_height",
+ "get_image_channel_data_type", "get_image_channel_order",
+ "get_image_num_samples"] in {
+ def : Builtin<name, [Int, ImageType<imgTy, aQual>], Attr.Const>;
+ }
+ def : Builtin<"get_image_dim", [VectorType<Int, 2>, ImageType<imgTy, aQual>], Attr.Const>;
+ }
+ def : Builtin<"get_image_array_size", [Size, ImageType<Image2dArrayMsaaDepth, aQual>], Attr.Const>;
+ }
+}
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index bedea2167950..2cd158a8b43c 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -137,7 +137,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
OriginalLexicalContext(nullptr), MSStructPragmaOn(false),
MSPointerToMemberRepresentationMethod(
LangOpts.getMSPointerToMemberRepresentationMethod()),
- VtorDispStack(MSVtorDispAttr::Mode(LangOpts.VtorDispMode)), PackStack(0),
+ VtorDispStack(LangOpts.getVtorDispMode()), PackStack(0),
DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
CodeSegStack(nullptr), CurInitSeg(nullptr), VisContext(nullptr),
PragmaAttributeCurrentTargetDecl(nullptr),
@@ -189,6 +189,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
SemaPPCallbackHandler->set(*this);
}
+// Anchor Sema's type info to this TU.
+void Sema::anchor() {}
+
void Sema::addImplicitTypedef(StringRef Name, QualType T) {
DeclarationName DN = &Context.Idents.get(Name);
if (IdResolver.begin(DN) == IdResolver.end())
@@ -921,8 +924,7 @@ void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) {
}
{
- llvm::TimeTraceScope TimeScope("PerformPendingInstantiations",
- StringRef(""));
+ llvm::TimeTraceScope TimeScope("PerformPendingInstantiations");
PerformPendingInstantiations();
}
@@ -1134,6 +1136,13 @@ void Sema::ActOnEndOfTranslationUnit() {
Consumer.CompleteTentativeDefinition(VD);
}
+ for (auto D : ExternalDeclarations) {
+ if (!D || D->isInvalidDecl() || D->getPreviousDecl() || !D->isUsed())
+ continue;
+
+ Consumer.CompleteExternalDeclaration(D);
+ }
+
// If there were errors, disable 'unused' warnings since they will mostly be
// noise. Don't warn for a use from a module: either we should warn on all
// file-scope declarations in modules or not at all, but whether the
@@ -1287,6 +1296,12 @@ NamedDecl *Sema::getCurFunctionOrMethodDecl() {
return nullptr;
}
+LangAS Sema::getDefaultCXXMethodAddrSpace() const {
+ if (getLangOpts().OpenCL)
+ return LangAS::opencl_generic;
+ return LangAS::Default;
+}
+
void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
// FIXME: It doesn't make sense to me that DiagID is an incoming argument here
// and yet we also use the current diag ID on the DiagnosticsEngine. This has
@@ -1902,6 +1917,7 @@ void Sema::ActOnComment(SourceRange Comment) {
// Pin this vtable to this file.
ExternalSemaSource::~ExternalSemaSource() {}
+char ExternalSemaSource::ID;
void ExternalSemaSource::ReadMethodPool(Selector Sel) { }
void ExternalSemaSource::updateOutOfDateSelector(Selector Sel) { }
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp
index 9dbb93322b7d..bd15b81cbed0 100644
--- a/clang/lib/Sema/SemaAccess.cpp
+++ b/clang/lib/Sema/SemaAccess.cpp
@@ -1560,21 +1560,24 @@ Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
return CheckAccess(*this, E->getMemberLoc(), Entity);
}
-/// Is the given special member function accessible for the purposes of
-/// deciding whether to define a special member function as deleted?
-bool Sema::isSpecialMemberAccessibleForDeletion(CXXMethodDecl *decl,
- AccessSpecifier access,
- QualType objectType) {
+/// Is the given member accessible for the purposes of deciding whether to
+/// define a special member function as deleted?
+bool Sema::isMemberAccessibleForDeletion(CXXRecordDecl *NamingClass,
+ DeclAccessPair Found,
+ QualType ObjectType,
+ SourceLocation Loc,
+ const PartialDiagnostic &Diag) {
// Fast path.
- if (access == AS_public || !getLangOpts().AccessControl) return true;
+ if (Found.getAccess() == AS_public || !getLangOpts().AccessControl)
+ return true;
- AccessTarget entity(Context, AccessTarget::Member, decl->getParent(),
- DeclAccessPair::make(decl, access), objectType);
+ AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
+ ObjectType);
// Suppress diagnostics.
- entity.setDiag(PDiag());
+ Entity.setDiag(Diag);
- switch (CheckAccess(*this, SourceLocation(), entity)) {
+ switch (CheckAccess(*this, Loc, Entity)) {
case AR_accessible: return true;
case AR_inaccessible: return false;
case AR_dependent: llvm_unreachable("dependent for =delete computation");
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 70186c966f8f..cd2a65276b09 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -80,9 +80,9 @@ void Sema::AddMsStructLayoutForRecord(RecordDecl *RD) {
// FIXME: We should merge AddAlignmentAttributesForRecord with
// AddMsStructLayoutForRecord into AddPragmaAttributesForRecord, which takes
// all active pragmas and applies them as attributes to class definitions.
- if (VtorDispStack.CurrentValue != getLangOpts().VtorDispMode)
- RD->addAttr(
- MSVtorDispAttr::CreateImplicit(Context, VtorDispStack.CurrentValue));
+ if (VtorDispStack.CurrentValue != getLangOpts().getVtorDispMode())
+ RD->addAttr(MSVtorDispAttr::CreateImplicit(
+ Context, unsigned(VtorDispStack.CurrentValue)));
}
template <typename Attribute>
@@ -416,7 +416,7 @@ void Sema::ActOnPragmaMSPointersToMembers(
void Sema::ActOnPragmaMSVtorDisp(PragmaMsStackAction Action,
SourceLocation PragmaLoc,
- MSVtorDispAttr::Mode Mode) {
+ MSVtorDispMode Mode) {
if (Action & PSK_Pop && VtorDispStack.Stack.empty())
Diag(PragmaLoc, diag::warn_pragma_pop_failed) << "vtordisp"
<< "stack empty";
diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp
index d0ddfd040c9c..0c61057e1072 100644
--- a/clang/lib/Sema/SemaCUDA.cpp
+++ b/clang/lib/Sema/SemaCUDA.cpp
@@ -492,6 +492,8 @@ void Sema::checkAllowedCUDAInitializer(VarDecl *VD) {
const Expr *Init = VD->getInit();
if (VD->hasAttr<CUDADeviceAttr>() || VD->hasAttr<CUDAConstantAttr>() ||
VD->hasAttr<CUDASharedAttr>()) {
+ if (LangOpts.GPUAllowDeviceInit)
+ return;
assert(!VD->isStaticLocal() || VD->hasAttr<CUDASharedAttr>());
bool AllowedInit = false;
if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(Init))
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index 0ebb5c68f7c2..a905ebc67305 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -423,7 +423,7 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
case OR_Ambiguous:
msg = diag::err_ovl_ambiguous_conversion_in_cast;
- howManyCandidates = OCD_ViableCandidates;
+ howManyCandidates = OCD_AmbiguousCandidates;
break;
case OR_Deleted:
@@ -740,7 +740,7 @@ void CastOperation::CheckDynamicCast() {
assert(DestPointer && "Reference to void is not possible");
} else if (DestRecord) {
if (Self.RequireCompleteType(OpRange.getBegin(), DestPointee,
- diag::err_bad_dynamic_cast_incomplete,
+ diag::err_bad_cast_incomplete,
DestRange)) {
SrcExpr = ExprError();
return;
@@ -763,7 +763,7 @@ void CastOperation::CheckDynamicCast() {
SrcPointee = SrcPointer->getPointeeType();
} else {
Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ptr)
- << OrigSrcType << SrcExpr.get()->getSourceRange();
+ << OrigSrcType << this->DestType << SrcExpr.get()->getSourceRange();
SrcExpr = ExprError();
return;
}
@@ -785,7 +785,7 @@ void CastOperation::CheckDynamicCast() {
const RecordType *SrcRecord = SrcPointee->getAs<RecordType>();
if (SrcRecord) {
if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee,
- diag::err_bad_dynamic_cast_incomplete,
+ diag::err_bad_cast_incomplete,
SrcExpr.get())) {
SrcExpr = ExprError();
return;
@@ -1182,6 +1182,11 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
// The same goes for reverse floating point promotion/conversion and
// floating-integral conversions. Again, only floating->enum is relevant.
if (DestType->isEnumeralType()) {
+ if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
+ diag::err_bad_cast_incomplete)) {
+ SrcExpr = ExprError();
+ return TC_Failed;
+ }
if (SrcType->isIntegralOrEnumerationType()) {
Kind = CK_IntegralCast;
return TC_Success;
@@ -1301,10 +1306,6 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
// Because we try the reference downcast before this function, from now on
// this is the only cast possibility, so we issue an error if we fail now.
// FIXME: Should allow casting away constness if CStyle.
- bool DerivedToBase;
- bool ObjCConversion;
- bool ObjCLifetimeConversion;
- bool FunctionConversion;
QualType FromType = SrcExpr->getType();
QualType ToType = R->getPointeeType();
if (CStyle) {
@@ -1312,9 +1313,9 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
ToType = ToType.getUnqualifiedType();
}
+ Sema::ReferenceConversions RefConv;
Sema::ReferenceCompareResult RefResult = Self.CompareReferenceRelationship(
- SrcExpr->getBeginLoc(), ToType, FromType, DerivedToBase, ObjCConversion,
- ObjCLifetimeConversion, FunctionConversion);
+ SrcExpr->getBeginLoc(), ToType, FromType, &RefConv);
if (RefResult != Sema::Ref_Compatible) {
if (CStyle || RefResult == Sema::Ref_Incompatible)
return TC_NotApplicable;
@@ -1326,7 +1327,7 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
return TC_Failed;
}
- if (DerivedToBase) {
+ if (RefConv & Sema::ReferenceConversions::DerivedToBase) {
Kind = CK_DerivedToBase;
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/true);
@@ -1651,7 +1652,7 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
CastKind &Kind, bool ListInitialization) {
if (DestType->isRecordType()) {
if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
- diag::err_bad_dynamic_cast_incomplete) ||
+ diag::err_bad_cast_incomplete) ||
Self.RequireNonAbstractType(OpRange.getBegin(), DestType,
diag::err_allocation_of_abstract_type)) {
msg = 0;
@@ -2007,7 +2008,7 @@ static bool fixOverloadedReinterpretCastExpr(Sema &Self, QualType DestType,
// No guarantees that ResolveAndFixSingleFunctionTemplateSpecialization
// preserves Result.
Result = E;
- if (!Self.resolveAndFixAddressOfOnlyViableOverloadCandidate(
+ if (!Self.resolveAndFixAddressOfSingleOverloadCandidate(
Result, /*DoFunctionPointerConversion=*/true))
return false;
return Result.isUsable();
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index dca81d1d275f..74742023d1b3 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -201,6 +201,87 @@ static bool SemaBuiltinPreserveAI(Sema &S, CallExpr *TheCall) {
return false;
}
+/// Check that the value argument for __builtin_is_aligned(value, alignment) and
+/// __builtin_aligned_{up,down}(value, alignment) is an integer or a pointer
+/// type (but not a function pointer) and that the alignment is a power-of-two.
+static bool SemaBuiltinAlignment(Sema &S, CallExpr *TheCall, unsigned ID) {
+ if (checkArgCount(S, TheCall, 2))
+ return true;
+
+ clang::Expr *Source = TheCall->getArg(0);
+ bool IsBooleanAlignBuiltin = ID == Builtin::BI__builtin_is_aligned;
+
+ auto IsValidIntegerType = [](QualType Ty) {
+ return Ty->isIntegerType() && !Ty->isEnumeralType() && !Ty->isBooleanType();
+ };
+ QualType SrcTy = Source->getType();
+ // We should also be able to use it with arrays (but not functions!).
+ if (SrcTy->canDecayToPointerType() && SrcTy->isArrayType()) {
+ SrcTy = S.Context.getDecayedType(SrcTy);
+ }
+ if ((!SrcTy->isPointerType() && !IsValidIntegerType(SrcTy)) ||
+ SrcTy->isFunctionPointerType()) {
+ // FIXME: this is not quite the right error message since we don't allow
+ // floating point types, or member pointers.
+ S.Diag(Source->getExprLoc(), diag::err_typecheck_expect_scalar_operand)
+ << SrcTy;
+ return true;
+ }
+
+ clang::Expr *AlignOp = TheCall->getArg(1);
+ if (!IsValidIntegerType(AlignOp->getType())) {
+ S.Diag(AlignOp->getExprLoc(), diag::err_typecheck_expect_int)
+ << AlignOp->getType();
+ return true;
+ }
+ Expr::EvalResult AlignResult;
+ unsigned MaxAlignmentBits = S.Context.getIntWidth(SrcTy) - 1;
+ // We can't check validity of alignment if it is type dependent.
+ if (!AlignOp->isInstantiationDependent() &&
+ AlignOp->EvaluateAsInt(AlignResult, S.Context,
+ Expr::SE_AllowSideEffects)) {
+ llvm::APSInt AlignValue = AlignResult.Val.getInt();
+ llvm::APSInt MaxValue(
+ llvm::APInt::getOneBitSet(MaxAlignmentBits + 1, MaxAlignmentBits));
+ if (AlignValue < 1) {
+ S.Diag(AlignOp->getExprLoc(), diag::err_alignment_too_small) << 1;
+ return true;
+ }
+ if (llvm::APSInt::compareValues(AlignValue, MaxValue) > 0) {
+ S.Diag(AlignOp->getExprLoc(), diag::err_alignment_too_big)
+ << MaxValue.toString(10);
+ return true;
+ }
+ if (!AlignValue.isPowerOf2()) {
+ S.Diag(AlignOp->getExprLoc(), diag::err_alignment_not_power_of_two);
+ return true;
+ }
+ if (AlignValue == 1) {
+ S.Diag(AlignOp->getExprLoc(), diag::warn_alignment_builtin_useless)
+ << IsBooleanAlignBuiltin;
+ }
+ }
+
+ ExprResult SrcArg = S.PerformCopyInitialization(
+ InitializedEntity::InitializeParameter(S.Context, SrcTy, false),
+ SourceLocation(), Source);
+ if (SrcArg.isInvalid())
+ return true;
+ TheCall->setArg(0, SrcArg.get());
+ ExprResult AlignArg =
+ S.PerformCopyInitialization(InitializedEntity::InitializeParameter(
+ S.Context, AlignOp->getType(), false),
+ SourceLocation(), AlignOp);
+ if (AlignArg.isInvalid())
+ return true;
+ TheCall->setArg(1, AlignArg.get());
+ // For align_up/align_down, the return type is the same as the (potentially
+ // decayed) argument type including qualifiers. For is_aligned(), the result
+ // is always bool.
+ TheCall->setType(IsBooleanAlignBuiltin ? S.Context.BoolTy : SrcTy);
+ return false;
+}
+
static bool SemaBuiltinOverflow(Sema &S, CallExpr *TheCall) {
if (checkArgCount(S, TheCall, 3))
return true;
@@ -340,7 +421,8 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
case Builtin::BI__builtin___strncat_chk:
case Builtin::BI__builtin___strncpy_chk:
case Builtin::BI__builtin___stpncpy_chk:
- case Builtin::BI__builtin___memccpy_chk: {
+ case Builtin::BI__builtin___memccpy_chk:
+ case Builtin::BI__builtin___mempcpy_chk: {
DiagID = diag::warn_builtin_chk_overflow;
IsChkVariant = true;
SizeIndex = TheCall->getNumArgs() - 2;
@@ -379,7 +461,9 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
case Builtin::BImemmove:
case Builtin::BI__builtin_memmove:
case Builtin::BImemset:
- case Builtin::BI__builtin_memset: {
+ case Builtin::BI__builtin_memset:
+ case Builtin::BImempcpy:
+ case Builtin::BI__builtin_mempcpy: {
DiagID = diag::warn_fortify_source_overflow;
SizeIndex = TheCall->getNumArgs() - 1;
ObjectIndex = 0;
@@ -1354,6 +1438,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
if (SemaBuiltinAddressof(*this, TheCall))
return ExprError();
break;
+ case Builtin::BI__builtin_is_aligned:
+ case Builtin::BI__builtin_align_up:
+ case Builtin::BI__builtin_align_down:
+ if (SemaBuiltinAlignment(*this, TheCall, BuiltinID))
+ return ExprError();
+ break;
case Builtin::BI__builtin_add_overflow:
case Builtin::BI__builtin_sub_overflow:
case Builtin::BI__builtin_mul_overflow:
@@ -1536,6 +1626,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
return ExprError();
break;
case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_32:
case llvm::Triple::aarch64_be:
if (CheckAArch64BuiltinFunctionCall(BuiltinID, TheCall))
return ExprError();
@@ -1685,6 +1776,7 @@ bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
llvm::Triple::ArchType Arch = Context.getTargetInfo().getTriple().getArch();
bool IsPolyUnsigned = Arch == llvm::Triple::aarch64 ||
+ Arch == llvm::Triple::aarch64_32 ||
Arch == llvm::Triple::aarch64_be;
bool IsInt64Long =
Context.getTargetInfo().getInt64Type() == TargetInfo::SignedLong;
@@ -1717,6 +1809,14 @@ bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return SemaBuiltinConstantArgRange(TheCall, i, l, u + l);
}
+bool Sema::CheckMVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
+ switch (BuiltinID) {
+ default:
+ return false;
+ #include "clang/Basic/arm_mve_builtin_sema.inc"
+ }
+}
+
bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall,
unsigned MaxWidth) {
assert((BuiltinID == ARM::BI__builtin_arm_ldrex ||
@@ -1857,6 +1957,8 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall))
return true;
+ if (CheckMVEBuiltinFunctionCall(BuiltinID, TheCall))
+ return true;
// For intrinsics which take an immediate value as part of the instruction,
// range check them here.
@@ -3039,8 +3141,37 @@ bool Sema::CheckHexagonBuiltinFunctionCall(unsigned BuiltinID,
CheckHexagonBuiltinArgument(BuiltinID, TheCall);
}
+bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
+ return CheckMipsBuiltinCpu(BuiltinID, TheCall) ||
+ CheckMipsBuiltinArgument(BuiltinID, TheCall);
+}
+
+bool Sema::CheckMipsBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall) {
+ const TargetInfo &TI = Context.getTargetInfo();
+
+ if (Mips::BI__builtin_mips_addu_qb <= BuiltinID &&
+ BuiltinID <= Mips::BI__builtin_mips_lwx) {
+ if (!TI.hasFeature("dsp"))
+ return Diag(TheCall->getBeginLoc(), diag::err_mips_builtin_requires_dsp);
+ }
+
+ if (Mips::BI__builtin_mips_absq_s_qb <= BuiltinID &&
+ BuiltinID <= Mips::BI__builtin_mips_subuh_r_qb) {
+ if (!TI.hasFeature("dspr2"))
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_mips_builtin_requires_dspr2);
+ }
-// CheckMipsBuiltinFunctionCall - Checks the constant value passed to the
+ if (Mips::BI__builtin_msa_add_a_b <= BuiltinID &&
+ BuiltinID <= Mips::BI__builtin_msa_xori_b) {
+ if (!TI.hasFeature("msa"))
+ return Diag(TheCall->getBeginLoc(), diag::err_mips_builtin_requires_msa);
+ }
+
+ return false;
+}
+
+// CheckMipsBuiltinArgument - Checks the constant value passed to the
// intrinsic is correct. The switch statement is ordered by DSP, MSA. The
// ordering for DSP is unspecified. MSA is ordered by the data format used
// by the underlying instruction i.e., df/m, df/n and then by size.
@@ -3049,7 +3180,7 @@ bool Sema::CheckHexagonBuiltinFunctionCall(unsigned BuiltinID,
// definitions from include/clang/Basic/BuiltinsMips.def.
// FIXME: GCC is strict on signedness for some of these intrinsics, we should
// be too.
-bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
+bool Sema::CheckMipsBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) {
unsigned i = 0, l = 0, u = 0, m = 0;
switch (BuiltinID) {
default: return false;
@@ -4560,20 +4691,19 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
&& sizeof(NumVals)/sizeof(NumVals[0]) == NumForm,
"need to update code for modified forms");
static_assert(AtomicExpr::AO__c11_atomic_init == 0 &&
- AtomicExpr::AO__c11_atomic_fetch_xor + 1 ==
+ AtomicExpr::AO__c11_atomic_fetch_min + 1 ==
AtomicExpr::AO__atomic_load,
"need to update code for modified C11 atomics");
bool IsOpenCL = Op >= AtomicExpr::AO__opencl_atomic_init &&
Op <= AtomicExpr::AO__opencl_atomic_fetch_max;
bool IsC11 = (Op >= AtomicExpr::AO__c11_atomic_init &&
- Op <= AtomicExpr::AO__c11_atomic_fetch_xor) ||
+ Op <= AtomicExpr::AO__c11_atomic_fetch_min) ||
IsOpenCL;
bool IsN = Op == AtomicExpr::AO__atomic_load_n ||
Op == AtomicExpr::AO__atomic_store_n ||
Op == AtomicExpr::AO__atomic_exchange_n ||
Op == AtomicExpr::AO__atomic_compare_exchange_n;
bool IsAddSub = false;
- bool IsMinMax = false;
switch (Op) {
case AtomicExpr::AO__c11_atomic_init:
@@ -4602,8 +4732,6 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
case AtomicExpr::AO__c11_atomic_fetch_sub:
case AtomicExpr::AO__opencl_atomic_fetch_add:
case AtomicExpr::AO__opencl_atomic_fetch_sub:
- case AtomicExpr::AO__opencl_atomic_fetch_min:
- case AtomicExpr::AO__opencl_atomic_fetch_max:
case AtomicExpr::AO__atomic_fetch_add:
case AtomicExpr::AO__atomic_fetch_sub:
case AtomicExpr::AO__atomic_add_fetch:
@@ -4624,12 +4752,14 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
case AtomicExpr::AO__atomic_or_fetch:
case AtomicExpr::AO__atomic_xor_fetch:
case AtomicExpr::AO__atomic_nand_fetch:
- Form = Arithmetic;
- break;
-
+ case AtomicExpr::AO__c11_atomic_fetch_min:
+ case AtomicExpr::AO__c11_atomic_fetch_max:
+ case AtomicExpr::AO__opencl_atomic_fetch_min:
+ case AtomicExpr::AO__opencl_atomic_fetch_max:
+ case AtomicExpr::AO__atomic_min_fetch:
+ case AtomicExpr::AO__atomic_max_fetch:
case AtomicExpr::AO__atomic_fetch_min:
case AtomicExpr::AO__atomic_fetch_max:
- IsMinMax = true;
Form = Arithmetic;
break;
@@ -4721,16 +4851,8 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
<< IsC11 << Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
- if (IsMinMax) {
- const BuiltinType *BT = ValType->getAs<BuiltinType>();
- if (!BT || (BT->getKind() != BuiltinType::Int &&
- BT->getKind() != BuiltinType::UInt)) {
- Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_int32_or_ptr);
- return ExprError();
- }
- }
- if (!IsAddSub && !IsMinMax && !ValType->isIntegerType()) {
- Diag(ExprRange.getBegin(), diag::err_atomic_op_bitwise_needs_atomic_int)
+ if (!IsAddSub && !ValType->isIntegerType()) {
+ Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic_int)
<< IsC11 << Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
@@ -5506,7 +5628,8 @@ ExprResult Sema::CheckOSLogFormatStringArg(Expr *Arg) {
static bool checkVAStartABI(Sema &S, unsigned BuiltinID, Expr *Fn) {
const llvm::Triple &TT = S.Context.getTargetInfo().getTriple();
bool IsX64 = TT.getArch() == llvm::Triple::x86_64;
- bool IsAArch64 = TT.getArch() == llvm::Triple::aarch64;
+ bool IsAArch64 = (TT.getArch() == llvm::Triple::aarch64 ||
+ TT.getArch() == llvm::Triple::aarch64_32);
bool IsWindows = TT.isOSWindows();
bool IsMSVAStart = BuiltinID == Builtin::BI__builtin_ms_va_start;
if (IsX64 || IsAArch64) {
@@ -5723,7 +5846,8 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) {
// Do standard promotions between the two arguments, returning their common
// type.
- QualType Res = UsualArithmeticConversions(OrigArg0, OrigArg1, false);
+ QualType Res = UsualArithmeticConversions(
+ OrigArg0, OrigArg1, TheCall->getExprLoc(), ACK_Comparison);
if (OrigArg0.isInvalid() || OrigArg1.isInvalid())
return true;
@@ -5763,36 +5887,41 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) {
<< SourceRange(TheCall->getArg(NumArgs)->getBeginLoc(),
(*(TheCall->arg_end() - 1))->getEndLoc());
+ // __builtin_fpclassify is the only case where NumArgs != 1, so we can count
+ // on all preceding parameters just being int. Try all of those.
+ for (unsigned i = 0; i < NumArgs - 1; ++i) {
+ Expr *Arg = TheCall->getArg(i);
+
+ if (Arg->isTypeDependent())
+ return false;
+
+ ExprResult Res = PerformImplicitConversion(Arg, Context.IntTy, AA_Passing);
+
+ if (Res.isInvalid())
+ return true;
+ TheCall->setArg(i, Res.get());
+ }
+
Expr *OrigArg = TheCall->getArg(NumArgs-1);
if (OrigArg->isTypeDependent())
return false;
+ // Usual Unary Conversions will convert half to float, which we want for
+ // machines that use fp16 conversion intrinsics. Else, we wnat to leave the
+ // type how it is, but do normal L->Rvalue conversions.
+ if (Context.getTargetInfo().useFP16ConversionIntrinsics())
+ OrigArg = UsualUnaryConversions(OrigArg).get();
+ else
+ OrigArg = DefaultFunctionArrayLvalueConversion(OrigArg).get();
+ TheCall->setArg(NumArgs - 1, OrigArg);
+
// This operation requires a non-_Complex floating-point number.
if (!OrigArg->getType()->isRealFloatingType())
return Diag(OrigArg->getBeginLoc(),
diag::err_typecheck_call_invalid_unary_fp)
<< OrigArg->getType() << OrigArg->getSourceRange();
- // If this is an implicit conversion from float -> float, double, or
- // long double, remove it.
- if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(OrigArg)) {
- // Only remove standard FloatCasts, leaving other casts inplace
- if (Cast->getCastKind() == CK_FloatingCast) {
- Expr *CastArg = Cast->getSubExpr();
- if (CastArg->getType()->isSpecificBuiltinType(BuiltinType::Float)) {
- assert(
- (Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) ||
- Cast->getType()->isSpecificBuiltinType(BuiltinType::Float) ||
- Cast->getType()->isSpecificBuiltinType(BuiltinType::LongDouble)) &&
- "promotion from float to either float, double, or long double is "
- "the only expected cast here");
- Cast->setSubExpr(nullptr);
- TheCall->setArg(NumArgs-1, CastArg);
- }
- }
- }
-
return false;
}
@@ -6235,6 +6364,101 @@ bool Sema::SemaBuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum,
return false;
}
+/// SemaBuiltinConstantArgPower2 - Check if argument ArgNum of TheCall is a
+/// constant expression representing a power of 2.
+bool Sema::SemaBuiltinConstantArgPower2(CallExpr *TheCall, int ArgNum) {
+ llvm::APSInt Result;
+
+ // We can't check the value of a dependent argument.
+ Expr *Arg = TheCall->getArg(ArgNum);
+ if (Arg->isTypeDependent() || Arg->isValueDependent())
+ return false;
+
+ // Check constant-ness first.
+ if (SemaBuiltinConstantArg(TheCall, ArgNum, Result))
+ return true;
+
+ // Bit-twiddling to test for a power of 2: for x > 0, x & (x-1) is zero if
+ // and only if x is a power of 2.
+ if (Result.isStrictlyPositive() && (Result & (Result - 1)) == 0)
+ return false;
+
+ return Diag(TheCall->getBeginLoc(), diag::err_argument_not_power_of_2)
+ << Arg->getSourceRange();
+}
+
+static bool IsShiftedByte(llvm::APSInt Value) {
+ if (Value.isNegative())
+ return false;
+
+ // Check if it's a shifted byte, by shifting it down
+ while (true) {
+ // If the value fits in the bottom byte, the check passes.
+ if (Value < 0x100)
+ return true;
+
+ // Otherwise, if the value has _any_ bits in the bottom byte, the check
+ // fails.
+ if ((Value & 0xFF) != 0)
+ return false;
+
+ // If the bottom 8 bits are all 0, but something above that is nonzero,
+ // then shifting the value right by 8 bits won't affect whether it's a
+ // shifted byte or not. So do that, and go round again.
+ Value >>= 8;
+ }
+}
+
+/// SemaBuiltinConstantArgShiftedByte - Check if argument ArgNum of TheCall is
+/// a constant expression representing an arbitrary byte value shifted left by
+/// a multiple of 8 bits.
+bool Sema::SemaBuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum) {
+ llvm::APSInt Result;
+
+ // We can't check the value of a dependent argument.
+ Expr *Arg = TheCall->getArg(ArgNum);
+ if (Arg->isTypeDependent() || Arg->isValueDependent())
+ return false;
+
+ // Check constant-ness first.
+ if (SemaBuiltinConstantArg(TheCall, ArgNum, Result))
+ return true;
+
+ if (IsShiftedByte(Result))
+ return false;
+
+ return Diag(TheCall->getBeginLoc(), diag::err_argument_not_shifted_byte)
+ << Arg->getSourceRange();
+}
+
+/// SemaBuiltinConstantArgShiftedByteOr0xFF - Check if argument ArgNum of
+/// TheCall is a constant expression representing either a shifted byte value,
+/// or a value of the form 0x??FF (i.e. a member of the arithmetic progression
+/// 0x00FF, 0x01FF, ..., 0xFFFF). This strange range check is needed for some
+/// Arm MVE intrinsics.
+bool Sema::SemaBuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall,
+ int ArgNum) {
+ llvm::APSInt Result;
+
+ // We can't check the value of a dependent argument.
+ Expr *Arg = TheCall->getArg(ArgNum);
+ if (Arg->isTypeDependent() || Arg->isValueDependent())
+ return false;
+
+ // Check constant-ness first.
+ if (SemaBuiltinConstantArg(TheCall, ArgNum, Result))
+ return true;
+
+ // Check to see if it's in either of the required forms.
+ if (IsShiftedByte(Result) ||
+ (Result > 0 && Result < 0x10000 && (Result & 0xFF) == 0xFF))
+ return false;
+
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_argument_not_shifted_byte_or_xxff)
+ << Arg->getSourceRange();
+}
+
/// SemaBuiltinARMMemoryTaggingCall - Handle calls of memory tagging extensions
bool Sema::SemaBuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall) {
if (BuiltinID == AArch64::BI__builtin_arm_irg) {
@@ -9162,7 +9386,7 @@ void Sema::CheckMaxUnsignedZero(const CallExpr *Call,
auto IsLiteralZeroArg = [](const Expr* E) -> bool {
const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E);
if (!MTE) return false;
- const auto *Num = dyn_cast<IntegerLiteral>(MTE->GetTemporaryExpr());
+ const auto *Num = dyn_cast<IntegerLiteral>(MTE->getSubExpr());
if (!Num) return false;
if (Num->getValue() != 0) return false;
return true;
@@ -11371,32 +11595,6 @@ static const IntegerLiteral *getIntegerLiteral(Expr *E) {
return IL;
}
-static void CheckConditionalWithEnumTypes(Sema &S, SourceLocation Loc,
- Expr *LHS, Expr *RHS) {
- QualType LHSStrippedType = LHS->IgnoreParenImpCasts()->getType();
- QualType RHSStrippedType = RHS->IgnoreParenImpCasts()->getType();
-
- const auto *LHSEnumType = LHSStrippedType->getAs<EnumType>();
- if (!LHSEnumType)
- return;
- const auto *RHSEnumType = RHSStrippedType->getAs<EnumType>();
- if (!RHSEnumType)
- return;
-
- // Ignore anonymous enums.
- if (!LHSEnumType->getDecl()->hasNameForLinkage())
- return;
- if (!RHSEnumType->getDecl()->hasNameForLinkage())
- return;
-
- if (S.Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType))
- return;
-
- S.Diag(Loc, diag::warn_conditional_mixed_enum_types)
- << LHSStrippedType << RHSStrippedType << LHS->getSourceRange()
- << RHS->getSourceRange();
-}
-
static void DiagnoseIntInBoolContext(Sema &S, Expr *E) {
E = E->IgnoreParenImpCasts();
SourceLocation ExprLoc = E->getExprLoc();
@@ -11737,7 +11935,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
return;
if (isObjCSignedCharBool(S, T) && !Source->isCharType() &&
- !E->isKnownToHaveBooleanValue()) {
+ !E->isKnownToHaveBooleanValue(/*Semantic=*/false)) {
return adornObjCBoolConversionDiagWithTernaryFixit(
S, E,
S.Diag(CC, diag::warn_impcast_int_to_objc_signed_char_bool)
@@ -11888,8 +12086,6 @@ static void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
bool Suspicious = false;
CheckConditionalOperand(S, E->getTrueExpr(), T, CC, Suspicious);
CheckConditionalOperand(S, E->getFalseExpr(), T, CC, Suspicious);
- CheckConditionalWithEnumTypes(S, E->getBeginLoc(), E->getTrueExpr(),
- E->getFalseExpr());
if (T->isBooleanType())
DiagnoseIntInBoolContext(S, E);
@@ -12360,8 +12556,8 @@ namespace {
/// Visitor for expressions which looks for unsequenced operations on the
/// same object.
-class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
- using Base = EvaluatedExprVisitor<SequenceChecker>;
+class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
+ using Base = ConstEvaluatedExprVisitor<SequenceChecker>;
/// A tree of sequenced regions within an expression. Two regions are
/// unsequenced if one is an ancestor or a descendent of the other. When we
@@ -12431,7 +12627,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
};
/// An object for which we can track unsequenced uses.
- using Object = NamedDecl *;
+ using Object = const NamedDecl *;
/// Different flavors of object usage which we track. We only track the
/// least-sequenced usage of each kind.
@@ -12450,17 +12646,19 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
UK_Count = UK_ModAsSideEffect + 1
};
+ /// Bundle together a sequencing region and the expression corresponding
+ /// to a specific usage. One Usage is stored for each usage kind in UsageInfo.
struct Usage {
- Expr *Use;
+ const Expr *UsageExpr;
SequenceTree::Seq Seq;
- Usage() : Use(nullptr), Seq() {}
+ Usage() : UsageExpr(nullptr), Seq() {}
};
struct UsageInfo {
Usage Uses[UK_Count];
- /// Have we issued a diagnostic for this variable already?
+ /// Have we issued a diagnostic for this object already?
bool Diagnosed;
UsageInfo() : Uses(), Diagnosed(false) {}
@@ -12484,7 +12682,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
/// Expressions to check later. We defer checking these to reduce
/// stack usage.
- SmallVectorImpl<Expr *> &WorkList;
+ SmallVectorImpl<const Expr *> &WorkList;
/// RAII object wrapping the visitation of a sequenced subexpression of an
/// expression. At the end of this process, the side-effects of the evaluation
@@ -12498,10 +12696,13 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
}
~SequencedSubexpression() {
- for (auto &M : llvm::reverse(ModAsSideEffect)) {
- UsageInfo &U = Self.UsageMap[M.first];
- auto &SideEffectUsage = U.Uses[UK_ModAsSideEffect];
- Self.addUsage(U, M.first, SideEffectUsage.Use, UK_ModAsValue);
+ for (const std::pair<Object, Usage> &M : llvm::reverse(ModAsSideEffect)) {
+ // Add a new usage with usage kind UK_ModAsValue, and then restore
+ // the previous usage with UK_ModAsSideEffect (thus clearing it if
+ // the previous one was empty).
+ UsageInfo &UI = Self.UsageMap[M.first];
+ auto &SideEffectUsage = UI.Uses[UK_ModAsSideEffect];
+ Self.addUsage(M.first, UI, SideEffectUsage.UsageExpr, UK_ModAsValue);
SideEffectUsage = M.second;
}
Self.ModAsSideEffect = OldModAsSideEffect;
@@ -12545,49 +12746,60 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
/// Find the object which is produced by the specified expression,
/// if any.
- Object getObject(Expr *E, bool Mod) const {
+ Object getObject(const Expr *E, bool Mod) const {
E = E->IgnoreParenCasts();
- if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
+ if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
if (Mod && (UO->getOpcode() == UO_PreInc || UO->getOpcode() == UO_PreDec))
return getObject(UO->getSubExpr(), Mod);
- } else if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ } else if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
if (BO->getOpcode() == BO_Comma)
return getObject(BO->getRHS(), Mod);
if (Mod && BO->isAssignmentOp())
return getObject(BO->getLHS(), Mod);
- } else if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
// FIXME: Check for more interesting cases, like "x.n = ++x.n".
if (isa<CXXThisExpr>(ME->getBase()->IgnoreParenCasts()))
return ME->getMemberDecl();
- } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
+ } else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
// FIXME: If this is a reference, map through to its value.
return DRE->getDecl();
return nullptr;
}
- /// Note that an object was modified or used by an expression.
- void addUsage(UsageInfo &UI, Object O, Expr *Ref, UsageKind UK) {
+ /// Note that an object \p O was modified or used by an expression
+ /// \p UsageExpr with usage kind \p UK. \p UI is the \p UsageInfo for
+ /// the object \p O as obtained via the \p UsageMap.
+ void addUsage(Object O, UsageInfo &UI, const Expr *UsageExpr, UsageKind UK) {
+ // Get the old usage for the given object and usage kind.
Usage &U = UI.Uses[UK];
- if (!U.Use || !Tree.isUnsequenced(Region, U.Seq)) {
+ if (!U.UsageExpr || !Tree.isUnsequenced(Region, U.Seq)) {
+ // If we have a modification as side effect and are in a sequenced
+ // subexpression, save the old Usage so that we can restore it later
+ // in SequencedSubexpression::~SequencedSubexpression.
if (UK == UK_ModAsSideEffect && ModAsSideEffect)
ModAsSideEffect->push_back(std::make_pair(O, U));
- U.Use = Ref;
+ // Then record the new usage with the current sequencing region.
+ U.UsageExpr = UsageExpr;
U.Seq = Region;
}
}
- /// Check whether a modification or use conflicts with a prior usage.
- void checkUsage(Object O, UsageInfo &UI, Expr *Ref, UsageKind OtherKind,
- bool IsModMod) {
+ /// Check whether a modification or use of an object \p O in an expression
+ /// \p UsageExpr conflicts with a prior usage of kind \p OtherKind. \p UI is
+ /// the \p UsageInfo for the object \p O as obtained via the \p UsageMap.
+ /// \p IsModMod is true when we are checking for a mod-mod unsequenced
+ /// usage and false we are checking for a mod-use unsequenced usage.
+ void checkUsage(Object O, UsageInfo &UI, const Expr *UsageExpr,
+ UsageKind OtherKind, bool IsModMod) {
if (UI.Diagnosed)
return;
const Usage &U = UI.Uses[OtherKind];
- if (!U.Use || !Tree.isUnsequenced(Region, U.Seq))
+ if (!U.UsageExpr || !Tree.isUnsequenced(Region, U.Seq))
return;
- Expr *Mod = U.Use;
- Expr *ModOrUse = Ref;
+ const Expr *Mod = U.UsageExpr;
+ const Expr *ModOrUse = UsageExpr;
if (OtherKind == UK_Use)
std::swap(Mod, ModOrUse);
@@ -12599,47 +12811,79 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
UI.Diagnosed = true;
}
- void notePreUse(Object O, Expr *Use) {
- UsageInfo &U = UsageMap[O];
+ // A note on note{Pre, Post}{Use, Mod}:
+ //
+ // (It helps to follow the algorithm with an expression such as
+ // "((++k)++, k) = k" or "k = (k++, k++)". Both contain unsequenced
+ // operations before C++17 and both are well-defined in C++17).
+ //
+ // When visiting a node which uses/modify an object we first call notePreUse
+ // or notePreMod before visiting its sub-expression(s). At this point the
+ // children of the current node have not yet been visited and so the eventual
+ // uses/modifications resulting from the children of the current node have not
+ // been recorded yet.
+ //
+ // We then visit the children of the current node. After that notePostUse or
+ // notePostMod is called. These will 1) detect an unsequenced modification
+ // as side effect (as in "k++ + k") and 2) add a new usage with the
+ // appropriate usage kind.
+ //
+ // We also have to be careful that some operation sequences modification as
+ // side effect as well (for example: || or ,). To account for this we wrap
+ // the visitation of such a sub-expression (for example: the LHS of || or ,)
+ // with SequencedSubexpression. SequencedSubexpression is an RAII object
+ // which record usages which are modifications as side effect, and then
+ // downgrade them (or more accurately restore the previous usage which was a
+ // modification as side effect) when exiting the scope of the sequenced
+ // subexpression.
+
+ void notePreUse(Object O, const Expr *UseExpr) {
+ UsageInfo &UI = UsageMap[O];
// Uses conflict with other modifications.
- checkUsage(O, U, Use, UK_ModAsValue, false);
+ checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_ModAsValue, /*IsModMod=*/false);
}
- void notePostUse(Object O, Expr *Use) {
- UsageInfo &U = UsageMap[O];
- checkUsage(O, U, Use, UK_ModAsSideEffect, false);
- addUsage(U, O, Use, UK_Use);
+ void notePostUse(Object O, const Expr *UseExpr) {
+ UsageInfo &UI = UsageMap[O];
+ checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_ModAsSideEffect,
+ /*IsModMod=*/false);
+ addUsage(O, UI, UseExpr, /*UsageKind=*/UK_Use);
}
- void notePreMod(Object O, Expr *Mod) {
- UsageInfo &U = UsageMap[O];
+ void notePreMod(Object O, const Expr *ModExpr) {
+ UsageInfo &UI = UsageMap[O];
// Modifications conflict with other modifications and with uses.
- checkUsage(O, U, Mod, UK_ModAsValue, true);
- checkUsage(O, U, Mod, UK_Use, false);
+ checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_ModAsValue, /*IsModMod=*/true);
+ checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_Use, /*IsModMod=*/false);
}
- void notePostMod(Object O, Expr *Use, UsageKind UK) {
- UsageInfo &U = UsageMap[O];
- checkUsage(O, U, Use, UK_ModAsSideEffect, true);
- addUsage(U, O, Use, UK);
+ void notePostMod(Object O, const Expr *ModExpr, UsageKind UK) {
+ UsageInfo &UI = UsageMap[O];
+ checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_ModAsSideEffect,
+ /*IsModMod=*/true);
+ addUsage(O, UI, ModExpr, /*UsageKind=*/UK);
}
public:
- SequenceChecker(Sema &S, Expr *E, SmallVectorImpl<Expr *> &WorkList)
+ SequenceChecker(Sema &S, const Expr *E,
+ SmallVectorImpl<const Expr *> &WorkList)
: Base(S.Context), SemaRef(S), Region(Tree.root()), WorkList(WorkList) {
Visit(E);
+ // Silence a -Wunused-private-field since WorkList is now unused.
+ // TODO: Evaluate if it can be used, and if not remove it.
+ (void)this->WorkList;
}
- void VisitStmt(Stmt *S) {
+ void VisitStmt(const Stmt *S) {
// Skip all statements which aren't expressions for now.
}
- void VisitExpr(Expr *E) {
+ void VisitExpr(const Expr *E) {
// By default, just recurse to evaluated subexpressions.
Base::VisitStmt(E);
}
- void VisitCastExpr(CastExpr *E) {
+ void VisitCastExpr(const CastExpr *E) {
Object O = Object();
if (E->getCastKind() == CK_LValueToRValue)
O = getObject(E->getSubExpr(), false);
@@ -12651,7 +12895,8 @@ public:
notePostUse(O, E);
}
- void VisitSequencedExpressions(Expr *SequencedBefore, Expr *SequencedAfter) {
+ void VisitSequencedExpressions(const Expr *SequencedBefore,
+ const Expr *SequencedAfter) {
SequenceTree::Seq BeforeRegion = Tree.allocate(Region);
SequenceTree::Seq AfterRegion = Tree.allocate(Region);
SequenceTree::Seq OldRegion = Region;
@@ -12671,17 +12916,46 @@ public:
Tree.merge(AfterRegion);
}
- void VisitArraySubscriptExpr(ArraySubscriptExpr *ASE) {
+ void VisitArraySubscriptExpr(const ArraySubscriptExpr *ASE) {
// C++17 [expr.sub]p1:
// The expression E1[E2] is identical (by definition) to *((E1)+(E2)). The
// expression E1 is sequenced before the expression E2.
if (SemaRef.getLangOpts().CPlusPlus17)
VisitSequencedExpressions(ASE->getLHS(), ASE->getRHS());
- else
- Base::VisitStmt(ASE);
+ else {
+ Visit(ASE->getLHS());
+ Visit(ASE->getRHS());
+ }
+ }
+
+ void VisitBinPtrMemD(const BinaryOperator *BO) { VisitBinPtrMem(BO); }
+ void VisitBinPtrMemI(const BinaryOperator *BO) { VisitBinPtrMem(BO); }
+ void VisitBinPtrMem(const BinaryOperator *BO) {
+ // C++17 [expr.mptr.oper]p4:
+ // Abbreviating pm-expression.*cast-expression as E1.*E2, [...]
+ // the expression E1 is sequenced before the expression E2.
+ if (SemaRef.getLangOpts().CPlusPlus17)
+ VisitSequencedExpressions(BO->getLHS(), BO->getRHS());
+ else {
+ Visit(BO->getLHS());
+ Visit(BO->getRHS());
+ }
}
- void VisitBinComma(BinaryOperator *BO) {
+ void VisitBinShl(const BinaryOperator *BO) { VisitBinShlShr(BO); }
+ void VisitBinShr(const BinaryOperator *BO) { VisitBinShlShr(BO); }
+ void VisitBinShlShr(const BinaryOperator *BO) {
+ // C++17 [expr.shift]p4:
+ // The expression E1 is sequenced before the expression E2.
+ if (SemaRef.getLangOpts().CPlusPlus17)
+ VisitSequencedExpressions(BO->getLHS(), BO->getRHS());
+ else {
+ Visit(BO->getLHS());
+ Visit(BO->getRHS());
+ }
+ }
+
+ void VisitBinComma(const BinaryOperator *BO) {
// C++11 [expr.comma]p1:
// Every value computation and side effect associated with the left
// expression is sequenced before every value computation and side
@@ -12689,47 +12963,77 @@ public:
VisitSequencedExpressions(BO->getLHS(), BO->getRHS());
}
- void VisitBinAssign(BinaryOperator *BO) {
- // The modification is sequenced after the value computation of the LHS
- // and RHS, so check it before inspecting the operands and update the
+ void VisitBinAssign(const BinaryOperator *BO) {
+ SequenceTree::Seq RHSRegion;
+ SequenceTree::Seq LHSRegion;
+ if (SemaRef.getLangOpts().CPlusPlus17) {
+ RHSRegion = Tree.allocate(Region);
+ LHSRegion = Tree.allocate(Region);
+ } else {
+ RHSRegion = Region;
+ LHSRegion = Region;
+ }
+ SequenceTree::Seq OldRegion = Region;
+
+ // C++11 [expr.ass]p1:
+ // [...] the assignment is sequenced after the value computation
+ // of the right and left operands, [...]
+ //
+ // so check it before inspecting the operands and update the
// map afterwards.
- Object O = getObject(BO->getLHS(), true);
- if (!O)
- return VisitExpr(BO);
+ Object O = getObject(BO->getLHS(), /*Mod=*/true);
+ if (O)
+ notePreMod(O, BO);
- notePreMod(O, BO);
+ if (SemaRef.getLangOpts().CPlusPlus17) {
+ // C++17 [expr.ass]p1:
+ // [...] The right operand is sequenced before the left operand. [...]
+ {
+ SequencedSubexpression SeqBefore(*this);
+ Region = RHSRegion;
+ Visit(BO->getRHS());
+ }
- // C++11 [expr.ass]p7:
- // E1 op= E2 is equivalent to E1 = E1 op E2, except that E1 is evaluated
- // only once.
- //
- // Therefore, for a compound assignment operator, O is considered used
- // everywhere except within the evaluation of E1 itself.
- if (isa<CompoundAssignOperator>(BO))
- notePreUse(O, BO);
+ Region = LHSRegion;
+ Visit(BO->getLHS());
- Visit(BO->getLHS());
+ if (O && isa<CompoundAssignOperator>(BO))
+ notePostUse(O, BO);
- if (isa<CompoundAssignOperator>(BO))
- notePostUse(O, BO);
+ } else {
+ // C++11 does not specify any sequencing between the LHS and RHS.
+ Region = LHSRegion;
+ Visit(BO->getLHS());
+
+ if (O && isa<CompoundAssignOperator>(BO))
+ notePostUse(O, BO);
- Visit(BO->getRHS());
+ Region = RHSRegion;
+ Visit(BO->getRHS());
+ }
// C++11 [expr.ass]p1:
- // the assignment is sequenced [...] before the value computation of the
- // assignment expression.
+ // the assignment is sequenced [...] before the value computation of the
+ // assignment expression.
// C11 6.5.16/3 has no such rule.
- notePostMod(O, BO, SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue
- : UK_ModAsSideEffect);
+ Region = OldRegion;
+ if (O)
+ notePostMod(O, BO,
+ SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue
+ : UK_ModAsSideEffect);
+ if (SemaRef.getLangOpts().CPlusPlus17) {
+ Tree.merge(RHSRegion);
+ Tree.merge(LHSRegion);
+ }
}
- void VisitCompoundAssignOperator(CompoundAssignOperator *CAO) {
+ void VisitCompoundAssignOperator(const CompoundAssignOperator *CAO) {
VisitBinAssign(CAO);
}
- void VisitUnaryPreInc(UnaryOperator *UO) { VisitUnaryPreIncDec(UO); }
- void VisitUnaryPreDec(UnaryOperator *UO) { VisitUnaryPreIncDec(UO); }
- void VisitUnaryPreIncDec(UnaryOperator *UO) {
+ void VisitUnaryPreInc(const UnaryOperator *UO) { VisitUnaryPreIncDec(UO); }
+ void VisitUnaryPreDec(const UnaryOperator *UO) { VisitUnaryPreIncDec(UO); }
+ void VisitUnaryPreIncDec(const UnaryOperator *UO) {
Object O = getObject(UO->getSubExpr(), true);
if (!O)
return VisitExpr(UO);
@@ -12738,13 +13042,14 @@ public:
Visit(UO->getSubExpr());
// C++11 [expr.pre.incr]p1:
// the expression ++x is equivalent to x+=1
- notePostMod(O, UO, SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue
- : UK_ModAsSideEffect);
+ notePostMod(O, UO,
+ SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue
+ : UK_ModAsSideEffect);
}
- void VisitUnaryPostInc(UnaryOperator *UO) { VisitUnaryPostIncDec(UO); }
- void VisitUnaryPostDec(UnaryOperator *UO) { VisitUnaryPostIncDec(UO); }
- void VisitUnaryPostIncDec(UnaryOperator *UO) {
+ void VisitUnaryPostInc(const UnaryOperator *UO) { VisitUnaryPostIncDec(UO); }
+ void VisitUnaryPostDec(const UnaryOperator *UO) { VisitUnaryPostIncDec(UO); }
+ void VisitUnaryPostIncDec(const UnaryOperator *UO) {
Object O = getObject(UO->getSubExpr(), true);
if (!O)
return VisitExpr(UO);
@@ -12754,67 +13059,129 @@ public:
notePostMod(O, UO, UK_ModAsSideEffect);
}
- /// Don't visit the RHS of '&&' or '||' if it might not be evaluated.
- void VisitBinLOr(BinaryOperator *BO) {
- // The side-effects of the LHS of an '&&' are sequenced before the
- // value computation of the RHS, and hence before the value computation
- // of the '&&' itself, unless the LHS evaluates to zero. We treat them
- // as if they were unconditionally sequenced.
+ void VisitBinLOr(const BinaryOperator *BO) {
+ // C++11 [expr.log.or]p2:
+ // If the second expression is evaluated, every value computation and
+ // side effect associated with the first expression is sequenced before
+ // every value computation and side effect associated with the
+ // second expression.
+ SequenceTree::Seq LHSRegion = Tree.allocate(Region);
+ SequenceTree::Seq RHSRegion = Tree.allocate(Region);
+ SequenceTree::Seq OldRegion = Region;
+
EvaluationTracker Eval(*this);
{
SequencedSubexpression Sequenced(*this);
+ Region = LHSRegion;
Visit(BO->getLHS());
}
- bool Result;
- if (Eval.evaluate(BO->getLHS(), Result)) {
- if (!Result)
- Visit(BO->getRHS());
- } else {
- // Check for unsequenced operations in the RHS, treating it as an
- // entirely separate evaluation.
- //
- // FIXME: If there are operations in the RHS which are unsequenced
- // with respect to operations outside the RHS, and those operations
- // are unconditionally evaluated, diagnose them.
- WorkList.push_back(BO->getRHS());
+ // C++11 [expr.log.or]p1:
+ // [...] the second operand is not evaluated if the first operand
+ // evaluates to true.
+ bool EvalResult = false;
+ bool EvalOK = Eval.evaluate(BO->getLHS(), EvalResult);
+ bool ShouldVisitRHS = !EvalOK || (EvalOK && !EvalResult);
+ if (ShouldVisitRHS) {
+ Region = RHSRegion;
+ Visit(BO->getRHS());
}
+
+ Region = OldRegion;
+ Tree.merge(LHSRegion);
+ Tree.merge(RHSRegion);
}
- void VisitBinLAnd(BinaryOperator *BO) {
+
+ void VisitBinLAnd(const BinaryOperator *BO) {
+ // C++11 [expr.log.and]p2:
+ // If the second expression is evaluated, every value computation and
+ // side effect associated with the first expression is sequenced before
+ // every value computation and side effect associated with the
+ // second expression.
+ SequenceTree::Seq LHSRegion = Tree.allocate(Region);
+ SequenceTree::Seq RHSRegion = Tree.allocate(Region);
+ SequenceTree::Seq OldRegion = Region;
+
EvaluationTracker Eval(*this);
{
SequencedSubexpression Sequenced(*this);
+ Region = LHSRegion;
Visit(BO->getLHS());
}
- bool Result;
- if (Eval.evaluate(BO->getLHS(), Result)) {
- if (Result)
- Visit(BO->getRHS());
- } else {
- WorkList.push_back(BO->getRHS());
+ // C++11 [expr.log.and]p1:
+ // [...] the second operand is not evaluated if the first operand is false.
+ bool EvalResult = false;
+ bool EvalOK = Eval.evaluate(BO->getLHS(), EvalResult);
+ bool ShouldVisitRHS = !EvalOK || (EvalOK && EvalResult);
+ if (ShouldVisitRHS) {
+ Region = RHSRegion;
+ Visit(BO->getRHS());
}
+
+ Region = OldRegion;
+ Tree.merge(LHSRegion);
+ Tree.merge(RHSRegion);
}
- // Only visit the condition, unless we can be sure which subexpression will
- // be chosen.
- void VisitAbstractConditionalOperator(AbstractConditionalOperator *CO) {
+ void VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO) {
+ // C++11 [expr.cond]p1:
+ // [...] Every value computation and side effect associated with the first
+ // expression is sequenced before every value computation and side effect
+ // associated with the second or third expression.
+ SequenceTree::Seq ConditionRegion = Tree.allocate(Region);
+
+ // No sequencing is specified between the true and false expression.
+ // However since exactly one of both is going to be evaluated we can
+ // consider them to be sequenced. This is needed to avoid warning on
+ // something like "x ? y+= 1 : y += 2;" in the case where we will visit
+ // both the true and false expressions because we can't evaluate x.
+ // This will still allow us to detect an expression like (pre C++17)
+ // "(x ? y += 1 : y += 2) = y".
+ //
+ // We don't wrap the visitation of the true and false expression with
+ // SequencedSubexpression because we don't want to downgrade modifications
+ // as side effect in the true and false expressions after the visition
+ // is done. (for example in the expression "(x ? y++ : y++) + y" we should
+ // not warn between the two "y++", but we should warn between the "y++"
+ // and the "y".
+ SequenceTree::Seq TrueRegion = Tree.allocate(Region);
+ SequenceTree::Seq FalseRegion = Tree.allocate(Region);
+ SequenceTree::Seq OldRegion = Region;
+
EvaluationTracker Eval(*this);
{
SequencedSubexpression Sequenced(*this);
+ Region = ConditionRegion;
Visit(CO->getCond());
}
- bool Result;
- if (Eval.evaluate(CO->getCond(), Result))
- Visit(Result ? CO->getTrueExpr() : CO->getFalseExpr());
- else {
- WorkList.push_back(CO->getTrueExpr());
- WorkList.push_back(CO->getFalseExpr());
+ // C++11 [expr.cond]p1:
+ // [...] The first expression is contextually converted to bool (Clause 4).
+ // It is evaluated and if it is true, the result of the conditional
+ // expression is the value of the second expression, otherwise that of the
+ // third expression. Only one of the second and third expressions is
+ // evaluated. [...]
+ bool EvalResult = false;
+ bool EvalOK = Eval.evaluate(CO->getCond(), EvalResult);
+ bool ShouldVisitTrueExpr = !EvalOK || (EvalOK && EvalResult);
+ bool ShouldVisitFalseExpr = !EvalOK || (EvalOK && !EvalResult);
+ if (ShouldVisitTrueExpr) {
+ Region = TrueRegion;
+ Visit(CO->getTrueExpr());
+ }
+ if (ShouldVisitFalseExpr) {
+ Region = FalseRegion;
+ Visit(CO->getFalseExpr());
}
+
+ Region = OldRegion;
+ Tree.merge(ConditionRegion);
+ Tree.merge(TrueRegion);
+ Tree.merge(FalseRegion);
}
- void VisitCallExpr(CallExpr *CE) {
+ void VisitCallExpr(const CallExpr *CE) {
// C++11 [intro.execution]p15:
// When calling a function [...], every value computation and side effect
// associated with any argument expression, or with the postfix expression
@@ -12822,12 +13189,13 @@ public:
// expression or statement in the body of the function [and thus before
// the value computation of its result].
SequencedSubexpression Sequenced(*this);
- Base::VisitCallExpr(CE);
+ SemaRef.runWithSufficientStackSpace(CE->getExprLoc(),
+ [&] { Base::VisitCallExpr(CE); });
// FIXME: CXXNewExpr and CXXDeleteExpr implicitly call functions.
}
- void VisitCXXConstructExpr(CXXConstructExpr *CCE) {
+ void VisitCXXConstructExpr(const CXXConstructExpr *CCE) {
// This is a call, so all subexpressions are sequenced before the result.
SequencedSubexpression Sequenced(*this);
@@ -12837,8 +13205,8 @@ public:
// In C++11, list initializations are sequenced.
SmallVector<SequenceTree::Seq, 32> Elts;
SequenceTree::Seq Parent = Region;
- for (CXXConstructExpr::arg_iterator I = CCE->arg_begin(),
- E = CCE->arg_end();
+ for (CXXConstructExpr::const_arg_iterator I = CCE->arg_begin(),
+ E = CCE->arg_end();
I != E; ++I) {
Region = Tree.allocate(Parent);
Elts.push_back(Region);
@@ -12851,7 +13219,7 @@ public:
Tree.merge(Elts[I]);
}
- void VisitInitListExpr(InitListExpr *ILE) {
+ void VisitInitListExpr(const InitListExpr *ILE) {
if (!SemaRef.getLangOpts().CPlusPlus11)
return VisitExpr(ILE);
@@ -12859,8 +13227,9 @@ public:
SmallVector<SequenceTree::Seq, 32> Elts;
SequenceTree::Seq Parent = Region;
for (unsigned I = 0; I < ILE->getNumInits(); ++I) {
- Expr *E = ILE->getInit(I);
- if (!E) continue;
+ const Expr *E = ILE->getInit(I);
+ if (!E)
+ continue;
Region = Tree.allocate(Parent);
Elts.push_back(Region);
Visit(E);
@@ -12875,11 +13244,11 @@ public:
} // namespace
-void Sema::CheckUnsequencedOperations(Expr *E) {
- SmallVector<Expr *, 8> WorkList;
+void Sema::CheckUnsequencedOperations(const Expr *E) {
+ SmallVector<const Expr *, 8> WorkList;
WorkList.push_back(E);
while (!WorkList.empty()) {
- Expr *Item = WorkList.pop_back_val();
+ const Expr *Item = WorkList.pop_back_val();
SequenceChecker(*this, Item, WorkList);
}
}
@@ -14577,6 +14946,8 @@ void Sema::RefersToMemberWithReducedAlignment(
bool AnyIsPacked = false;
do {
QualType BaseType = ME->getBase()->getType();
+ if (BaseType->isDependentType())
+ return;
if (ME->isArrow())
BaseType = BaseType->getPointeeType();
RecordDecl *RD = BaseType->castAs<RecordType>()->getDecl();
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index f24c3b234ff2..7260977c634d 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -692,18 +692,6 @@ getRequiredQualification(ASTContext &Context, const DeclContext *CurContext,
return Result;
}
-/// Determine whether \p Id is a name reserved for the implementation (C99
-/// 7.1.3, C++ [lib.global.names]).
-static bool isReservedName(const IdentifierInfo *Id,
- bool doubleUnderscoreOnly = false) {
- if (Id->getLength() < 2)
- return false;
- const char *Name = Id->getNameStart();
- return Name[0] == '_' &&
- (Name[1] == '_' ||
- (Name[1] >= 'A' && Name[1] <= 'Z' && !doubleUnderscoreOnly));
-}
-
// Some declarations have reserved names that we don't want to ever show.
// Filter out names reserved for the implementation if they come from a
// system header.
@@ -713,13 +701,13 @@ static bool shouldIgnoreDueToReservedName(const NamedDecl *ND, Sema &SemaRef) {
return false;
// Ignore reserved names for compiler provided decls.
- if (isReservedName(Id) && ND->getLocation().isInvalid())
+ if (Id->isReservedName() && ND->getLocation().isInvalid())
return true;
// For system headers ignore only double-underscore names.
// This allows for system headers providing private symbols with a single
// underscore.
- if (isReservedName(Id, /*doubleUnderscoreOnly=*/true) &&
+ if (Id->isReservedName(/*doubleUnderscoreOnly=*/true) &&
SemaRef.SourceMgr.isInSystemHeader(
SemaRef.SourceMgr.getSpellingLoc(ND->getLocation())))
return true;
@@ -1321,7 +1309,7 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
/// Motivating case is const_iterator begin() const vs iterator begin().
auto &OverloadSet = OverloadMap[std::make_pair(
CurContext, Method->getDeclName().getAsOpaqueInteger())];
- for (const DeclIndexPair& Entry : OverloadSet) {
+ for (const DeclIndexPair Entry : OverloadSet) {
Result &Incumbent = Results[Entry.second];
switch (compareOverloads(*Method,
*cast<CXXMethodDecl>(Incumbent.Declaration),
@@ -2324,6 +2312,13 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
Builder.AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Builder.TakeString()));
}
+ // For pointers, suggest 'return nullptr' in C++.
+ if (SemaRef.getLangOpts().CPlusPlus11 &&
+ (ReturnType->isPointerType() || ReturnType->isMemberPointerType())) {
+ Builder.AddTypedTextChunk("return nullptr");
+ Builder.AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Builder.TakeString()));
+ }
}
// goto identifier ;
@@ -2991,7 +2986,11 @@ static void AddTemplateParameterChunks(
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) {
if (TTP->wasDeclaredWithTypename())
PlaceholderStr = "typename";
- else
+ else if (const auto *TC = TTP->getTypeConstraint()) {
+ llvm::raw_string_ostream OS(PlaceholderStr);
+ TC->print(OS, Policy);
+ OS.flush();
+ } else
PlaceholderStr = "class";
if (TTP->getIdentifier()) {
@@ -3327,6 +3326,18 @@ CodeCompletionResult::createCodeCompletionStringForOverride(
return Result.TakeString();
}
+// FIXME: Right now this works well with lambdas. Add support for other functor
+// types like std::function.
+static const NamedDecl *extractFunctorCallOperator(const NamedDecl *ND) {
+ const auto *VD = dyn_cast<VarDecl>(ND);
+ if (!VD)
+ return nullptr;
+ const auto *RecordDecl = VD->getType()->getAsCXXRecordDecl();
+ if (!RecordDecl || !RecordDecl->isLambda())
+ return nullptr;
+ return RecordDecl->getLambdaCallOperator();
+}
+
CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl(
Preprocessor &PP, ASTContext &Ctx, CodeCompletionBuilder &Result,
bool IncludeBriefComments, const CodeCompletionContext &CCContext,
@@ -3351,9 +3362,8 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl(
for (const auto *I : ND->specific_attrs<AnnotateAttr>())
Result.AddAnnotation(Result.getAllocator().CopyString(I->getAnnotation()));
- AddResultTypeChunk(Ctx, Policy, ND, CCContext.getBaseType(), Result);
-
- if (const auto *Function = dyn_cast<FunctionDecl>(ND)) {
+ auto AddFunctionTypeAndResult = [&](const FunctionDecl *Function) {
+ AddResultTypeChunk(Ctx, Policy, Function, CCContext.getBaseType(), Result);
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
Ctx, Policy);
AddTypedNameChunk(Ctx, Policy, ND, Result);
@@ -3361,9 +3371,21 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl(
AddFunctionParameterChunks(PP, Policy, Function, Result);
Result.AddChunk(CodeCompletionString::CK_RightParen);
AddFunctionTypeQualsToCompletionString(Result, Function);
+ };
+
+ if (const auto *Function = dyn_cast<FunctionDecl>(ND)) {
+ AddFunctionTypeAndResult(Function);
+ return Result.TakeString();
+ }
+
+ if (const auto *CallOperator =
+ dyn_cast_or_null<FunctionDecl>(extractFunctorCallOperator(ND))) {
+ AddFunctionTypeAndResult(CallOperator);
return Result.TakeString();
}
+ AddResultTypeChunk(Ctx, Policy, ND, CCContext.getBaseType(), Result);
+
if (const FunctionTemplateDecl *FunTmpl =
dyn_cast<FunctionTemplateDecl>(ND)) {
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
@@ -3429,6 +3451,7 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl(
Result.AddChunk(CodeCompletionString::CK_RightAngle);
return Result.TakeString();
}
+
if (const auto *Method = dyn_cast<ObjCMethodDecl>(ND)) {
Selector Sel = Method->getSelector();
if (Sel.isUnarySelector()) {
@@ -3653,6 +3676,10 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
unsigned CurrentArg, Sema &S, CodeCompletionAllocator &Allocator,
CodeCompletionTUInfo &CCTUInfo, bool IncludeBriefComments) const {
PrintingPolicy Policy = getCompletionPrintingPolicy(S);
+ // Show signatures of constructors as they are declared:
+ // vector(int n) rather than vector<string>(int n)
+ // This is less noisy without being less clear, and avoids tricky cases.
+ Policy.SuppressTemplateArgsInCXXConstructors = true;
// FIXME: Set priority, availability appropriately.
CodeCompletionBuilder Result(Allocator, CCTUInfo, 1,
@@ -4783,7 +4810,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
}
// Add properties from the protocols in a qualified interface.
- for (auto *I : BaseType->getAs<ObjCObjectPointerType>()->quals())
+ for (auto *I : BaseType->castAs<ObjCObjectPointerType>()->quals())
AddObjCProperties(CCContext, I, true, /*AllowNullaryMethods=*/true,
CurContext, AddedProperties, Results,
IsBaseExprStatement, /*IsClassProperty*/ false,
@@ -4796,7 +4823,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
BaseType->getAs<ObjCObjectPointerType>())
Class = ObjCPtr->getInterfaceDecl();
else
- Class = BaseType->getAs<ObjCObjectType>()->getInterface();
+ Class = BaseType->castAs<ObjCObjectType>()->getInterface();
// Add all ivars from this class and its superclasses.
if (Class) {
@@ -5330,18 +5357,21 @@ void Sema::CodeCompleteAfterIf(Scope *S) {
}
void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
- bool EnteringContext, QualType BaseType,
+ bool EnteringContext,
+ bool IsUsingDeclaration, QualType BaseType,
QualType PreferredType) {
if (SS.isEmpty() || !CodeCompleter)
return;
+ CodeCompletionContext CC(CodeCompletionContext::CCC_Symbol, PreferredType);
+ CC.setIsUsingDeclaration(IsUsingDeclaration);
+ CC.setCXXScopeSpecifier(SS);
+
// We want to keep the scope specifier even if it's invalid (e.g. the scope
// "a::b::" is not corresponding to any context/namespace in the AST), since
// it can be useful for global code completion which have information about
// contexts/symbols that are not in the AST.
if (SS.isInvalid()) {
- CodeCompletionContext CC(CodeCompletionContext::CCC_Symbol, PreferredType);
- CC.setCXXScopeSpecifier(SS);
// As SS is invalid, we try to collect accessible contexts from the current
// scope with a dummy lookup so that the completion consumer can try to
// guess what the specified scope is.
@@ -5371,10 +5401,8 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
if (!isDependentScopeSpecifier(SS) && RequireCompleteDeclContext(SS, Ctx))
return;
- ResultBuilder Results(
- *this, CodeCompleter->getAllocator(),
- CodeCompleter->getCodeCompletionTUInfo(),
- CodeCompletionContext(CodeCompletionContext::CCC_Symbol, PreferredType));
+ ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(), CC);
if (!PreferredType.isNull())
Results.setPreferredType(PreferredType);
Results.EnterNewScope();
@@ -5403,23 +5431,21 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
CodeCompleter->loadExternal());
}
- auto CC = Results.getCompletionContext();
- CC.setCXXScopeSpecifier(SS);
-
- HandleCodeCompleteResults(this, CodeCompleter, CC, Results.data(),
- Results.size());
+ HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(),
+ Results.data(), Results.size());
}
void Sema::CodeCompleteUsing(Scope *S) {
if (!CodeCompleter)
return;
+ // This can be both a using alias or using declaration, in the former we
+ // expect a new name and a symbol in the latter case.
+ CodeCompletionContext Context(CodeCompletionContext::CCC_SymbolOrNewName);
+ Context.setIsUsingDeclaration(true);
+
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
- CodeCompleter->getCodeCompletionTUInfo(),
- // This can be both a using alias or using
- // declaration, in the former we expect a new name and a
- // symbol in the latter case.
- CodeCompletionContext::CCC_SymbolOrNewName,
+ CodeCompleter->getCodeCompletionTUInfo(), Context,
&ResultBuilder::IsNestedNameSpecifier);
Results.EnterNewScope();
@@ -7721,8 +7747,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
if (IsInstanceMethod &&
(ReturnType.isNull() ||
(ReturnType->isObjCObjectPointerType() &&
- ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() &&
- ReturnType->getAs<ObjCObjectPointerType>()
+ ReturnType->castAs<ObjCObjectPointerType>()->getInterfaceDecl() &&
+ ReturnType->castAs<ObjCObjectPointerType>()
->getInterfaceDecl()
->getName() == "NSArray"))) {
std::string SelectorName = (Twine(Property->getName()) + "AtIndexes").str();
@@ -8108,8 +8134,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
if (!IsInstanceMethod &&
(ReturnType.isNull() ||
(ReturnType->isObjCObjectPointerType() &&
- ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() &&
- ReturnType->getAs<ObjCObjectPointerType>()
+ ReturnType->castAs<ObjCObjectPointerType>()->getInterfaceDecl() &&
+ ReturnType->castAs<ObjCObjectPointerType>()
->getInterfaceDecl()
->getName() == "NSSet"))) {
std::string SelectorName =
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 848ccf543445..018ac2d7dc9d 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -11,15 +11,24 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Sema/SemaConcept.h"
#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/Template.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/OperatorPrecedence.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/PointerUnion.h"
using namespace clang;
using namespace sema;
-bool Sema::CheckConstraintExpression(Expr *ConstraintExpression) {
+bool
+Sema::CheckConstraintExpression(Expr *ConstraintExpression, Token NextToken,
+ bool *PossibleNonPrimary,
+ bool IsTrailingRequiresClause) {
// C++2a [temp.constr.atomic]p1
// ..E shall be a constant expression of type bool.
@@ -27,99 +36,793 @@ bool Sema::CheckConstraintExpression(Expr *ConstraintExpression) {
if (auto *BinOp = dyn_cast<BinaryOperator>(ConstraintExpression)) {
if (BinOp->getOpcode() == BO_LAnd || BinOp->getOpcode() == BO_LOr)
- return CheckConstraintExpression(BinOp->getLHS()) &&
- CheckConstraintExpression(BinOp->getRHS());
+ return CheckConstraintExpression(BinOp->getLHS(), NextToken,
+ PossibleNonPrimary) &&
+ CheckConstraintExpression(BinOp->getRHS(), NextToken,
+ PossibleNonPrimary);
} else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpression))
- return CheckConstraintExpression(C->getSubExpr());
+ return CheckConstraintExpression(C->getSubExpr(), NextToken,
+ PossibleNonPrimary);
+
+ QualType Type = ConstraintExpression->getType();
+
+ auto CheckForNonPrimary = [&] {
+ if (PossibleNonPrimary)
+ *PossibleNonPrimary =
+ // We have the following case:
+ // template<typename> requires func(0) struct S { };
+ // The user probably isn't aware of the parentheses required around
+ // the function call, and we're only going to parse 'func' as the
+ // primary-expression, and complain that it is of non-bool type.
+ (NextToken.is(tok::l_paren) &&
+ (IsTrailingRequiresClause ||
+ (Type->isDependentType() &&
+ IsDependentFunctionNameExpr(ConstraintExpression)) ||
+ Type->isFunctionType() ||
+ Type->isSpecificBuiltinType(BuiltinType::Overload))) ||
+ // We have the following case:
+ // template<typename T> requires size_<T> == 0 struct S { };
+ // The user probably isn't aware of the parentheses required around
+ // the binary operator, and we're only going to parse 'func' as the
+ // first operand, and complain that it is of non-bool type.
+ getBinOpPrecedence(NextToken.getKind(),
+ /*GreaterThanIsOperator=*/true,
+ getLangOpts().CPlusPlus11) > prec::LogicalAnd;
+ };
// An atomic constraint!
- if (ConstraintExpression->isTypeDependent())
+ if (ConstraintExpression->isTypeDependent()) {
+ CheckForNonPrimary();
return true;
+ }
- QualType Type = ConstraintExpression->getType();
if (!Context.hasSameUnqualifiedType(Type, Context.BoolTy)) {
Diag(ConstraintExpression->getExprLoc(),
diag::err_non_bool_atomic_constraint) << Type
<< ConstraintExpression->getSourceRange();
+ CheckForNonPrimary();
return false;
}
+
+ if (PossibleNonPrimary)
+ *PossibleNonPrimary = false;
return true;
}
-bool
-Sema::CalculateConstraintSatisfaction(ConceptDecl *NamedConcept,
- MultiLevelTemplateArgumentList &MLTAL,
- Expr *ConstraintExpr,
- bool &IsSatisfied) {
+template <typename AtomicEvaluator>
+static bool
+calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
+ ConstraintSatisfaction &Satisfaction,
+ AtomicEvaluator &&Evaluator) {
ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts();
if (auto *BO = dyn_cast<BinaryOperator>(ConstraintExpr)) {
- if (BO->getOpcode() == BO_LAnd) {
- if (CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getLHS(),
- IsSatisfied))
+ if (BO->getOpcode() == BO_LAnd || BO->getOpcode() == BO_LOr) {
+ if (calculateConstraintSatisfaction(S, BO->getLHS(), Satisfaction,
+ Evaluator))
return true;
- if (!IsSatisfied)
+
+ bool IsLHSSatisfied = Satisfaction.IsSatisfied;
+
+ if (BO->getOpcode() == BO_LOr && IsLHSSatisfied)
+ // [temp.constr.op] p3
+ // A disjunction is a constraint taking two operands. To determine if
+ // a disjunction is satisfied, the satisfaction of the first operand
+ // 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;
- return CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getRHS(),
- IsSatisfied);
- } else if (BO->getOpcode() == BO_LOr) {
- if (CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getLHS(),
- IsSatisfied))
- return true;
- if (IsSatisfied)
+
+ if (BO->getOpcode() == BO_LAnd && !IsLHSSatisfied)
+ // [temp.constr.op] p2
+ // A conjunction is a constraint taking two operands. 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. Otherwise, the conjunction is satisfied if and only if
+ // the second operand is satisfied.
return false;
- return CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getRHS(),
- IsSatisfied);
+
+ return calculateConstraintSatisfaction(S, BO->getRHS(), Satisfaction,
+ std::forward<AtomicEvaluator>(Evaluator));
}
}
else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr))
- return CalculateConstraintSatisfaction(NamedConcept, MLTAL, C->getSubExpr(),
- IsSatisfied);
+ return calculateConstraintSatisfaction(S, C->getSubExpr(), Satisfaction,
+ std::forward<AtomicEvaluator>(Evaluator));
- EnterExpressionEvaluationContext ConstantEvaluated(
- *this, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ // An atomic constraint expression
+ ExprResult SubstitutedAtomicExpr = Evaluator(ConstraintExpr);
- // Atomic constraint - substitute arguments and check satisfaction.
- ExprResult E;
- {
- TemplateDeductionInfo Info(ConstraintExpr->getBeginLoc());
- InstantiatingTemplate Inst(*this, ConstraintExpr->getBeginLoc(),
- InstantiatingTemplate::ConstraintSubstitution{},
- NamedConcept, Info,
- ConstraintExpr->getSourceRange());
- if (Inst.isInvalid())
- return true;
- // We do not want error diagnostics escaping here.
- Sema::SFINAETrap Trap(*this);
+ if (SubstitutedAtomicExpr.isInvalid())
+ return true;
+
+ if (!SubstitutedAtomicExpr.isUsable())
+ // Evaluator has decided satisfaction without yielding an expression.
+ return false;
- E = SubstExpr(ConstraintExpr, MLTAL);
- if (E.isInvalid() || Trap.hasErrorOccurred()) {
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ SmallVector<PartialDiagnosticAt, 2> EvaluationDiags;
+ Expr::EvalResult EvalResult;
+ EvalResult.Diag = &EvaluationDiags;
+ if (!SubstitutedAtomicExpr.get()->EvaluateAsRValue(EvalResult, S.Context)) {
// C++2a [temp.constr.atomic]p1
- // ...If substitution results in an invalid type or expression, the
- // constraint is not satisfied.
- IsSatisfied = false;
+ // ...E shall be a constant expression of type bool.
+ S.Diag(SubstitutedAtomicExpr.get()->getBeginLoc(),
+ diag::err_non_constant_constraint_expression)
+ << SubstitutedAtomicExpr.get()->getSourceRange();
+ for (const PartialDiagnosticAt &PDiag : EvaluationDiags)
+ S.Diag(PDiag.first, PDiag.second);
+ return true;
+ }
+
+ Satisfaction.IsSatisfied = EvalResult.Val.getInt().getBoolValue();
+ if (!Satisfaction.IsSatisfied)
+ Satisfaction.Details.emplace_back(ConstraintExpr,
+ SubstitutedAtomicExpr.get());
+
+ return false;
+}
+
+template <typename TemplateDeclT>
+static bool calculateConstraintSatisfaction(
+ Sema &S, TemplateDeclT *Template, ArrayRef<TemplateArgument> TemplateArgs,
+ SourceLocation TemplateNameLoc, MultiLevelTemplateArgumentList &MLTAL,
+ const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) {
+ return calculateConstraintSatisfaction(
+ S, ConstraintExpr, Satisfaction, [&](const Expr *AtomicExpr) {
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+
+ // Atomic constraint - substitute arguments and check satisfaction.
+ ExprResult SubstitutedExpression;
+ {
+ TemplateDeductionInfo Info(TemplateNameLoc);
+ Sema::InstantiatingTemplate Inst(S, AtomicExpr->getBeginLoc(),
+ Sema::InstantiatingTemplate::ConstraintSubstitution{}, Template,
+ Info, AtomicExpr->getSourceRange());
+ if (Inst.isInvalid())
+ return ExprError();
+ // We do not want error diagnostics escaping here.
+ Sema::SFINAETrap Trap(S);
+ SubstitutedExpression = S.SubstExpr(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
+ // constraint is not satisfied.
+ if (!Trap.hasErrorOccurred())
+ // A non-SFINAE error has occured as a result of this
+ // substitution.
+ return ExprError();
+
+ PartialDiagnosticAt SubstDiag{SourceLocation(),
+ PartialDiagnostic::NullDiagnostic()};
+ Info.takeSFINAEDiagnostic(SubstDiag);
+ // FIXME: Concepts: This is an unfortunate consequence of there
+ // being no serialization code for PartialDiagnostics and the fact
+ // that serializing them would likely take a lot more storage than
+ // just storing them as strings. We would still like, in the
+ // future, to serialize the proper PartialDiagnostic as serializing
+ // it as a string defeats the purpose of the diagnostic mechanism.
+ SmallString<128> DiagString;
+ DiagString = ": ";
+ SubstDiag.second.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(
+ AtomicExpr,
+ new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
+ SubstDiag.first, StringRef(Mem, MessageSize)});
+ Satisfaction.IsSatisfied = false;
+ return ExprEmpty();
+ }
+ }
+
+ if (!S.CheckConstraintExpression(SubstitutedExpression.get()))
+ return ExprError();
+
+ return SubstitutedExpression;
+ });
+}
+
+template<typename TemplateDeclT>
+static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template,
+ ArrayRef<const Expr *> ConstraintExprs,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ 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;
}
+
+ Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(),
+ Sema::InstantiatingTemplate::ConstraintsCheck{}, 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))
+ return true;
+ if (!Satisfaction.IsSatisfied)
+ // [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. [...]
+ return false;
}
+ return false;
+}
+
+bool Sema::CheckConstraintSatisfaction(TemplateDecl *Template,
+ ArrayRef<const Expr *> ConstraintExprs,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceRange TemplateIDRange,
+ ConstraintSatisfaction &Satisfaction) {
+ return ::CheckConstraintSatisfaction(*this, Template, ConstraintExprs,
+ TemplateArgs, TemplateIDRange,
+ Satisfaction);
+}
- if (!CheckConstraintExpression(E.get()))
+bool
+Sema::CheckConstraintSatisfaction(ClassTemplatePartialSpecializationDecl* Part,
+ ArrayRef<const Expr *> ConstraintExprs,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceRange TemplateIDRange,
+ ConstraintSatisfaction &Satisfaction) {
+ return ::CheckConstraintSatisfaction(*this, Part, ConstraintExprs,
+ TemplateArgs, TemplateIDRange,
+ Satisfaction);
+}
+
+bool
+Sema::CheckConstraintSatisfaction(VarTemplatePartialSpecializationDecl* Partial,
+ ArrayRef<const Expr *> ConstraintExprs,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceRange TemplateIDRange,
+ ConstraintSatisfaction &Satisfaction) {
+ return ::CheckConstraintSatisfaction(*this, Partial, ConstraintExprs,
+ TemplateArgs, TemplateIDRange,
+ Satisfaction);
+}
+
+bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr,
+ ConstraintSatisfaction &Satisfaction) {
+ return calculateConstraintSatisfaction(
+ *this, ConstraintExpr, Satisfaction,
+ [](const Expr *AtomicExpr) -> ExprResult {
+ return ExprResult(const_cast<Expr *>(AtomicExpr));
+ });
+}
+
+bool Sema::EnsureTemplateArgumentListConstraints(
+ TemplateDecl *TD, ArrayRef<TemplateArgument> TemplateArgs,
+ SourceRange TemplateIDRange) {
+ ConstraintSatisfaction Satisfaction;
+ llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
+ TD->getAssociatedConstraints(AssociatedConstraints);
+ if (CheckConstraintSatisfaction(TD, AssociatedConstraints, TemplateArgs,
+ TemplateIDRange, Satisfaction))
return true;
- SmallVector<PartialDiagnosticAt, 2> EvaluationDiags;
- Expr::EvalResult EvalResult;
- EvalResult.Diag = &EvaluationDiags;
- if (!E.get()->EvaluateAsRValue(EvalResult, Context)) {
- // C++2a [temp.constr.atomic]p1
- // ...E shall be a constant expression of type bool.
- Diag(E.get()->getBeginLoc(),
- diag::err_non_constant_constraint_expression)
- << E.get()->getSourceRange();
- for (const PartialDiagnosticAt &PDiag : EvaluationDiags)
- Diag(PDiag.first, PDiag.second);
+ if (!Satisfaction.IsSatisfied) {
+ SmallString<128> TemplateArgString;
+ TemplateArgString = " ";
+ TemplateArgString += getTemplateArgumentBindingsText(
+ TD->getTemplateParameters(), TemplateArgs.data(), TemplateArgs.size());
+
+ Diag(TemplateIDRange.getBegin(),
+ diag::err_template_arg_list_constraints_not_satisfied)
+ << (int)getTemplateNameKindForDiagnostics(TemplateName(TD)) << TD
+ << TemplateArgString << TemplateIDRange;
+ DiagnoseUnsatisfiedConstraint(Satisfaction);
+ return true;
+ }
+ return false;
+}
+
+static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
+ Expr *SubstExpr,
+ bool First = true) {
+ SubstExpr = SubstExpr->IgnoreParenImpCasts();
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(SubstExpr)) {
+ switch (BO->getOpcode()) {
+ // These two cases will in practice only be reached when using fold
+ // expressions with || and &&, since otherwise the || and && will have been
+ // broken down into atomic constraints during satisfaction checking.
+ case BO_LOr:
+ // Or evaluated to false - meaning both RHS and LHS evaluated to false.
+ diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getLHS(), First);
+ diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getRHS(),
+ /*First=*/false);
+ return;
+ case BO_LAnd:
+ bool LHSSatisfied;
+ BO->getLHS()->EvaluateAsBooleanCondition(LHSSatisfied, S.Context);
+ if (LHSSatisfied) {
+ // LHS is true, so RHS must be false.
+ diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getRHS(), First);
+ return;
+ }
+ // LHS is false
+ diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getLHS(), First);
+
+ // RHS might also be false
+ bool RHSSatisfied;
+ BO->getRHS()->EvaluateAsBooleanCondition(RHSSatisfied, S.Context);
+ if (!RHSSatisfied)
+ diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getRHS(),
+ /*First=*/false);
+ return;
+ case BO_GE:
+ case BO_LE:
+ case BO_GT:
+ case BO_LT:
+ case BO_EQ:
+ case BO_NE:
+ if (BO->getLHS()->getType()->isIntegerType() &&
+ BO->getRHS()->getType()->isIntegerType()) {
+ Expr::EvalResult SimplifiedLHS;
+ Expr::EvalResult SimplifiedRHS;
+ BO->getLHS()->EvaluateAsInt(SimplifiedLHS, S.Context);
+ BO->getRHS()->EvaluateAsInt(SimplifiedRHS, S.Context);
+ if (!SimplifiedLHS.Diag && ! SimplifiedRHS.Diag) {
+ S.Diag(SubstExpr->getBeginLoc(),
+ diag::note_atomic_constraint_evaluated_to_false_elaborated)
+ << (int)First << SubstExpr
+ << SimplifiedLHS.Val.getInt().toString(10)
+ << BinaryOperator::getOpcodeStr(BO->getOpcode())
+ << SimplifiedRHS.Val.getInt().toString(10);
+ return;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else if (auto *CSE = dyn_cast<ConceptSpecializationExpr>(SubstExpr)) {
+ if (CSE->getTemplateArgsAsWritten()->NumTemplateArgs == 1) {
+ S.Diag(
+ CSE->getSourceRange().getBegin(),
+ diag::
+ note_single_arg_concept_specialization_constraint_evaluated_to_false)
+ << (int)First
+ << CSE->getTemplateArgsAsWritten()->arguments()[0].getArgument()
+ << CSE->getNamedConcept();
+ } else {
+ S.Diag(SubstExpr->getSourceRange().getBegin(),
+ diag::note_concept_specialization_constraint_evaluated_to_false)
+ << (int)First << CSE;
+ }
+ S.DiagnoseUnsatisfiedConstraint(CSE->getSatisfaction());
+ return;
+ }
+
+ S.Diag(SubstExpr->getSourceRange().getBegin(),
+ diag::note_atomic_constraint_evaluated_to_false)
+ << (int)First << SubstExpr;
+}
+
+template<typename SubstitutionDiagnostic>
+static void diagnoseUnsatisfiedConstraintExpr(
+ Sema &S, const Expr *E,
+ const llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> &Record,
+ bool First = true) {
+ if (auto *Diag = Record.template dyn_cast<SubstitutionDiagnostic *>()){
+ S.Diag(Diag->first, diag::note_substituted_constraint_expr_is_ill_formed)
+ << Diag->second;
+ return;
+ }
+
+ diagnoseWellFormedUnsatisfiedConstraintExpr(S,
+ Record.template get<Expr *>(), First);
+}
+
+void Sema::DiagnoseUnsatisfiedConstraint(
+ const ConstraintSatisfaction& Satisfaction) {
+ assert(!Satisfaction.IsSatisfied &&
+ "Attempted to diagnose a satisfied constraint");
+ bool First = true;
+ for (auto &Pair : Satisfaction.Details) {
+ diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First);
+ First = false;
+ }
+}
+
+void Sema::DiagnoseUnsatisfiedConstraint(
+ const ASTConstraintSatisfaction &Satisfaction) {
+ assert(!Satisfaction.IsSatisfied &&
+ "Attempted to diagnose a satisfied constraint");
+ bool First = true;
+ for (auto &Pair : Satisfaction) {
+ diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First);
+ First = false;
+ }
+}
+
+const NormalizedConstraint *
+Sema::getNormalizedAssociatedConstraints(
+ NamedDecl *ConstrainedDecl, ArrayRef<const Expr *> AssociatedConstraints) {
+ auto CacheEntry = NormalizationCache.find(ConstrainedDecl);
+ if (CacheEntry == NormalizationCache.end()) {
+ auto Normalized =
+ NormalizedConstraint::fromConstraintExprs(*this, ConstrainedDecl,
+ AssociatedConstraints);
+ CacheEntry =
+ NormalizationCache
+ .try_emplace(ConstrainedDecl,
+ Normalized
+ ? new (Context) NormalizedConstraint(
+ std::move(*Normalized))
+ : nullptr)
+ .first;
+ }
+ return CacheEntry->second;
+}
+
+static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
+ ConceptDecl *Concept, ArrayRef<TemplateArgument> TemplateArgs,
+ const ASTTemplateArgumentListInfo *ArgsAsWritten) {
+ if (!N.isAtomic()) {
+ if (substituteParameterMappings(S, N.getLHS(), Concept, TemplateArgs,
+ ArgsAsWritten))
+ return true;
+ return substituteParameterMappings(S, N.getRHS(), Concept, TemplateArgs,
+ 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()));
+ 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],
+ // Here we assume we do not support things like
+ // template<typename A, typename B>
+ // concept C = ...;
+ //
+ // template<typename... Ts> requires C<Ts...>
+ // 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()));
+ }
+ Sema::InstantiatingTemplate Inst(
+ S, ArgsAsWritten->arguments().front().getSourceRange().getBegin(),
+ Sema::InstantiatingTemplate::ParameterMappingSubstitution{}, Concept,
+ SourceRange(ArgsAsWritten->arguments()[0].getSourceRange().getBegin(),
+ ArgsAsWritten->arguments().back().getSourceRange().getEnd()));
+ if (S.SubstTemplateArguments(*Atomic.ParameterMapping, MLTAL, SubstArgs))
+ return true;
+ std::copy(SubstArgs.arguments().begin(), SubstArgs.arguments().end(),
+ N.getAtomicConstraint()->ParameterMapping->begin());
+ return false;
+}
+
+Optional<NormalizedConstraint>
+NormalizedConstraint::fromConstraintExprs(Sema &S, NamedDecl *D,
+ ArrayRef<const Expr *> E) {
+ assert(E.size() != 0);
+ auto First = fromConstraintExpr(S, D, E[0]);
+ if (E.size() == 1)
+ return First;
+ auto Second = fromConstraintExpr(S, D, E[1]);
+ if (!Second)
+ return None;
+ llvm::Optional<NormalizedConstraint> Conjunction;
+ Conjunction.emplace(S.Context, std::move(*First), std::move(*Second),
+ CCK_Conjunction);
+ for (unsigned I = 2; I < E.size(); ++I) {
+ auto Next = fromConstraintExpr(S, D, E[I]);
+ if (!Next)
+ return llvm::Optional<NormalizedConstraint>{};
+ NormalizedConstraint NewConjunction(S.Context, std::move(*Conjunction),
+ std::move(*Next), CCK_Conjunction);
+ *Conjunction = std::move(NewConjunction);
+ }
+ return Conjunction;
+}
+
+llvm::Optional<NormalizedConstraint>
+NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) {
+ assert(E != nullptr);
+
+ // C++ [temp.constr.normal]p1.1
+ // [...]
+ // - The normal form of an expression (E) is the normal form of E.
+ // [...]
+ E = E->IgnoreParenImpCasts();
+ if (auto *BO = dyn_cast<const BinaryOperator>(E)) {
+ if (BO->getOpcode() == BO_LAnd || BO->getOpcode() == BO_LOr) {
+ auto LHS = fromConstraintExpr(S, D, BO->getLHS());
+ if (!LHS)
+ return None;
+ auto RHS = fromConstraintExpr(S, D, BO->getRHS());
+ if (!RHS)
+ return None;
+
+ return NormalizedConstraint(
+ S.Context, std::move(*LHS), std::move(*RHS),
+ BO->getOpcode() == BO_LAnd ? CCK_Conjunction : CCK_Disjunction);
+ }
+ } else if (auto *CSE = dyn_cast<const ConceptSpecializationExpr>(E)) {
+ const NormalizedConstraint *SubNF;
+ {
+ Sema::InstantiatingTemplate Inst(
+ S, CSE->getExprLoc(),
+ Sema::InstantiatingTemplate::ConstraintNormalization{}, D,
+ CSE->getSourceRange());
+ // C++ [temp.constr.normal]p1.1
+ // [...]
+ // The normal form of an id-expression of the form C<A1, A2, ..., AN>,
+ // where C names a concept, is the normal form of the
+ // constraint-expression of C, after substituting A1, A2, ..., AN for C’s
+ // respective template parameters in the parameter mappings in each atomic
+ // constraint. If any such substitution results in an invalid type or
+ // expression, the program is ill-formed; no diagnostic is required.
+ // [...]
+ ConceptDecl *CD = CSE->getNamedConcept();
+ SubNF = S.getNormalizedAssociatedConstraints(CD,
+ {CD->getConstraintExpr()});
+ if (!SubNF)
+ return None;
+ }
+
+ Optional<NormalizedConstraint> New;
+ New.emplace(S.Context, *SubNF);
+
+ if (substituteParameterMappings(
+ S, *New, CSE->getNamedConcept(),
+ CSE->getTemplateArguments(), CSE->getTemplateArgsAsWritten()))
+ return None;
+
+ return New;
+ }
+ return NormalizedConstraint{new (S.Context) AtomicConstraint(S, E)};
+}
+
+using NormalForm =
+ llvm::SmallVector<llvm::SmallVector<AtomicConstraint *, 2>, 4>;
+
+static NormalForm makeCNF(const NormalizedConstraint &Normalized) {
+ if (Normalized.isAtomic())
+ return {{Normalized.getAtomicConstraint()}};
+
+ NormalForm LCNF = makeCNF(Normalized.getLHS());
+ NormalForm RCNF = makeCNF(Normalized.getRHS());
+ if (Normalized.getCompoundKind() == NormalizedConstraint::CCK_Conjunction) {
+ LCNF.reserve(LCNF.size() + RCNF.size());
+ while (!RCNF.empty())
+ LCNF.push_back(RCNF.pop_back_val());
+ return LCNF;
+ }
+
+ // Disjunction
+ NormalForm Res;
+ Res.reserve(LCNF.size() * RCNF.size());
+ for (auto &LDisjunction : LCNF)
+ for (auto &RDisjunction : RCNF) {
+ NormalForm::value_type Combined;
+ Combined.reserve(LDisjunction.size() + RDisjunction.size());
+ std::copy(LDisjunction.begin(), LDisjunction.end(),
+ std::back_inserter(Combined));
+ std::copy(RDisjunction.begin(), RDisjunction.end(),
+ std::back_inserter(Combined));
+ Res.emplace_back(Combined);
+ }
+ return Res;
+}
+
+static NormalForm makeDNF(const NormalizedConstraint &Normalized) {
+ if (Normalized.isAtomic())
+ return {{Normalized.getAtomicConstraint()}};
+
+ NormalForm LDNF = makeDNF(Normalized.getLHS());
+ NormalForm RDNF = makeDNF(Normalized.getRHS());
+ if (Normalized.getCompoundKind() == NormalizedConstraint::CCK_Disjunction) {
+ LDNF.reserve(LDNF.size() + RDNF.size());
+ while (!RDNF.empty())
+ LDNF.push_back(RDNF.pop_back_val());
+ return LDNF;
+ }
+
+ // Conjunction
+ NormalForm Res;
+ Res.reserve(LDNF.size() * RDNF.size());
+ for (auto &LConjunction : LDNF) {
+ for (auto &RConjunction : RDNF) {
+ NormalForm::value_type Combined;
+ Combined.reserve(LConjunction.size() + RConjunction.size());
+ std::copy(LConjunction.begin(), LConjunction.end(),
+ std::back_inserter(Combined));
+ std::copy(RConjunction.begin(), RConjunction.end(),
+ std::back_inserter(Combined));
+ Res.emplace_back(Combined);
+ }
+ }
+ return Res;
+}
+
+template<typename AtomicSubsumptionEvaluator>
+static bool subsumes(NormalForm PDNF, NormalForm QCNF,
+ AtomicSubsumptionEvaluator E) {
+ // C++ [temp.constr.order] p2
+ // Then, P subsumes Q if and only if, for every disjunctive clause Pi in the
+ // disjunctive normal form of P, Pi subsumes every conjunctive clause Qj in
+ // the conjuctive normal form of Q, where [...]
+ for (const auto &Pi : PDNF) {
+ for (const auto &Qj : QCNF) {
+ // C++ [temp.constr.order] p2
+ // - [...] a disjunctive clause Pi subsumes a conjunctive clause Qj if
+ // and only if there exists an atomic constraint Pia in Pi for which
+ // there exists an atomic constraint, Qjb, in Qj such that Pia
+ // subsumes Qjb.
+ bool Found = false;
+ for (const AtomicConstraint *Pia : Pi) {
+ for (const AtomicConstraint *Qjb : Qj) {
+ if (E(*Pia, *Qjb)) {
+ Found = true;
+ break;
+ }
+ }
+ if (Found)
+ break;
+ }
+ if (!Found)
+ return false;
+ }
+ }
+ return true;
+}
+
+template<typename AtomicSubsumptionEvaluator>
+static bool subsumes(Sema &S, NamedDecl *DP, ArrayRef<const Expr *> P,
+ NamedDecl *DQ, ArrayRef<const Expr *> Q, bool &Subsumes,
+ AtomicSubsumptionEvaluator E) {
+ // C++ [temp.constr.order] p2
+ // In order to determine if a constraint P subsumes a constraint Q, P is
+ // transformed into disjunctive normal form, and Q is transformed into
+ // conjunctive normal form. [...]
+ auto *PNormalized = S.getNormalizedAssociatedConstraints(DP, P);
+ if (!PNormalized)
+ return true;
+ const NormalForm PDNF = makeDNF(*PNormalized);
+
+ auto *QNormalized = S.getNormalizedAssociatedConstraints(DQ, Q);
+ if (!QNormalized)
return true;
+ const NormalForm QCNF = makeCNF(*QNormalized);
+
+ Subsumes = subsumes(PDNF, QCNF, E);
+ return false;
+}
+
+bool Sema::IsAtLeastAsConstrained(NamedDecl *D1, ArrayRef<const Expr *> AC1,
+ NamedDecl *D2, ArrayRef<const Expr *> AC2,
+ bool &Result) {
+ if (AC1.empty()) {
+ Result = AC2.empty();
+ return false;
+ }
+ if (AC2.empty()) {
+ // TD1 has associated constraints and TD2 does not.
+ Result = true;
+ return false;
}
- IsSatisfied = EvalResult.Val.getInt().getBoolValue();
+ std::pair<NamedDecl *, NamedDecl *> Key{D1, D2};
+ auto CacheEntry = SubsumptionCache.find(Key);
+ if (CacheEntry != SubsumptionCache.end()) {
+ Result = CacheEntry->second;
+ return false;
+ }
+ if (subsumes(*this, D1, AC1, D2, AC2, Result,
+ [this] (const AtomicConstraint &A, const AtomicConstraint &B) {
+ return A.subsumes(Context, B);
+ }))
+ return true;
+ SubsumptionCache.try_emplace(Key, Result);
return false;
-} \ No newline at end of file
+}
+
+bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic(NamedDecl *D1,
+ ArrayRef<const Expr *> AC1, NamedDecl *D2, ArrayRef<const Expr *> AC2) {
+ if (isSFINAEContext())
+ // No need to work here because our notes would be discarded.
+ return false;
+
+ if (AC1.empty() || AC2.empty())
+ return false;
+
+ auto NormalExprEvaluator =
+ [this] (const AtomicConstraint &A, const AtomicConstraint &B) {
+ return A.subsumes(Context, B);
+ };
+
+ const Expr *AmbiguousAtomic1 = nullptr, *AmbiguousAtomic2 = nullptr;
+ auto IdenticalExprEvaluator =
+ [&] (const AtomicConstraint &A, const AtomicConstraint &B) {
+ if (!A.hasMatchingParameterMapping(Context, B))
+ return false;
+ const Expr *EA = A.ConstraintExpr, *EB = B.ConstraintExpr;
+ if (EA == EB)
+ return true;
+
+ // Not the same source level expression - are the expressions
+ // identical?
+ llvm::FoldingSetNodeID IDA, IDB;
+ EA->Profile(IDA, Context, /*Cannonical=*/true);
+ EB->Profile(IDB, Context, /*Cannonical=*/true);
+ if (IDA != IDB)
+ return false;
+
+ AmbiguousAtomic1 = EA;
+ AmbiguousAtomic2 = EB;
+ return true;
+ };
+
+ {
+ // The subsumption checks might cause diagnostics
+ SFINAETrap Trap(*this);
+ auto *Normalized1 = getNormalizedAssociatedConstraints(D1, AC1);
+ if (!Normalized1)
+ return false;
+ const NormalForm DNF1 = makeDNF(*Normalized1);
+ const NormalForm CNF1 = makeCNF(*Normalized1);
+
+ auto *Normalized2 = getNormalizedAssociatedConstraints(D2, AC2);
+ if (!Normalized2)
+ return false;
+ const NormalForm DNF2 = makeDNF(*Normalized2);
+ const NormalForm CNF2 = makeCNF(*Normalized2);
+
+ bool Is1AtLeastAs2Normally = subsumes(DNF1, CNF2, NormalExprEvaluator);
+ bool Is2AtLeastAs1Normally = subsumes(DNF2, CNF1, NormalExprEvaluator);
+ bool Is1AtLeastAs2 = subsumes(DNF1, CNF2, IdenticalExprEvaluator);
+ bool Is2AtLeastAs1 = subsumes(DNF2, CNF1, IdenticalExprEvaluator);
+ if (Is1AtLeastAs2 == Is1AtLeastAs2Normally &&
+ Is2AtLeastAs1 == Is2AtLeastAs1Normally)
+ // Same result - no ambiguity was caused by identical atomic expressions.
+ return false;
+ }
+
+ // A different result! Some ambiguous atomic constraint(s) caused a difference
+ assert(AmbiguousAtomic1 && AmbiguousAtomic2);
+
+ Diag(AmbiguousAtomic1->getBeginLoc(), diag::note_ambiguous_atomic_constraints)
+ << AmbiguousAtomic1->getSourceRange();
+ Diag(AmbiguousAtomic2->getBeginLoc(),
+ diag::note_ambiguous_atomic_constraints_similar_expression)
+ << AmbiguousAtomic2->getSourceRange();
+ return true;
+}
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index fd2fd35921ce..6dc9e342beb9 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/Basic/Builtins.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Overload.h"
@@ -1227,7 +1228,7 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
return false;
if (RequiresNoThrowAlloc) {
- const auto *FT = OperatorNew->getType()->getAs<FunctionProtoType>();
+ const auto *FT = OperatorNew->getType()->castAs<FunctionProtoType>();
if (!FT->isNothrow(/*ResultIfDependent*/ false)) {
S.Diag(OperatorNew->getLocation(),
diag::err_coroutine_promise_new_requires_nothrow)
@@ -1280,7 +1281,7 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
// Check if we need to pass the size.
const auto *OpDeleteType =
- OpDeleteQualType.getTypePtr()->getAs<FunctionProtoType>();
+ OpDeleteQualType.getTypePtr()->castAs<FunctionProtoType>();
if (OpDeleteType->getNumParams() > 1)
DeleteArgs.push_back(FrameSize);
@@ -1526,8 +1527,8 @@ bool Sema::buildCoroutineParameterMoves(SourceLocation Loc) {
auto *FD = cast<FunctionDecl>(CurContext);
auto *ScopeInfo = getCurFunction();
- assert(ScopeInfo->CoroutineParameterMoves.empty() &&
- "Should not build parameter moves twice");
+ if (!ScopeInfo->CoroutineParameterMoves.empty())
+ return false;
for (auto *PD : FD->parameters()) {
if (PD->getType()->isDependentType())
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 62ec83967bff..507e4a6cd436 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -867,6 +867,9 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
LookupParsedName(Result, S, &SS, !CurMethod);
+ if (SS.isInvalid())
+ return NameClassification::Error();
+
// For unqualified lookup in a class template in MSVC mode, look into
// dependent base classes where the primary class template is known.
if (Result.empty() && SS.isEmpty() && getLangOpts().MSVCCompat) {
@@ -879,7 +882,7 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
// synthesized instance variables), if we're in an Objective-C method.
// FIXME: This lookup really, really needs to be folded in to the normal
// unqualified lookup mechanism.
- if (!SS.isSet() && CurMethod && !isResultTypeOrTemplate(Result, NextToken)) {
+ if (SS.isEmpty() && CurMethod && !isResultTypeOrTemplate(Result, NextToken)) {
DeclResult Ivar = LookupIvarInObjCMethod(Result, S, Name);
if (Ivar.isInvalid())
return NameClassification::Error();
@@ -899,7 +902,7 @@ Corrected:
case LookupResult::NotFound:
// If an unqualified-id is followed by a '(', then we have a function
// call.
- if (!SS.isSet() && NextToken.is(tok::l_paren)) {
+ if (SS.isEmpty() && NextToken.is(tok::l_paren)) {
// In C++, this is an ADL-only call.
// FIXME: Reference?
if (getLangOpts().CPlusPlus)
@@ -921,7 +924,7 @@ Corrected:
return NameClassification::NonType(D);
}
- if (getLangOpts().CPlusPlus2a && !SS.isSet() && NextToken.is(tok::less)) {
+ if (getLangOpts().CPlusPlus2a && SS.isEmpty() && NextToken.is(tok::less)) {
// In C++20 onwards, this could be an ADL-only call to a function
// template, and we're required to assume that this is a template name.
//
@@ -1063,7 +1066,7 @@ Corrected:
hasAnyAcceptableTemplateNames(
Result, /*AllowFunctionTemplates=*/true,
/*AllowDependent=*/false,
- /*AllowNonTemplateFunctions*/ !SS.isSet() &&
+ /*AllowNonTemplateFunctions*/ SS.isEmpty() &&
getLangOpts().CPlusPlus2a))) {
// C++ [temp.names]p3:
// After name lookup (3.4) finds that a name is a template-name or that
@@ -1092,7 +1095,7 @@ Corrected:
IsFunctionTemplate = isa<FunctionTemplateDecl>(TD);
IsVarTemplate = isa<VarTemplateDecl>(TD);
- if (SS.isSet() && !SS.isInvalid())
+ if (SS.isNotEmpty())
Template =
Context.getQualifiedTemplateName(SS.getScopeRep(),
/*TemplateKeyword=*/false, TD);
@@ -1802,6 +1805,13 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
(VD->getInit()->isValueDependent() || !VD->evaluateValue()))
return false;
}
+
+ // Suppress the warning if we don't know how this is constructed, and
+ // it could possibly be non-trivial constructor.
+ if (Init->isTypeDependent())
+ for (const CXXConstructorDecl *Ctor : RD->ctors())
+ if (!Ctor->isTrivial())
+ return false;
}
}
}
@@ -2549,7 +2559,7 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
NewAttr = S.mergeCodeSegAttr(D, *CSA, CSA->getName());
else if (const auto *IA = dyn_cast<MSInheritanceAttr>(Attr))
NewAttr = S.mergeMSInheritanceAttr(D, *IA, IA->getBestCase(),
- IA->getSemanticSpelling());
+ IA->getInheritanceModel());
else if (const auto *AA = dyn_cast<AlwaysInlineAttr>(Attr))
NewAttr = S.mergeAlwaysInlineAttr(D, *AA,
&S.Context.Idents.get(AA->getSpelling()));
@@ -2675,6 +2685,10 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
// C's _Noreturn is allowed to be added to a function after it is defined.
++I;
continue;
+ } else if (isa<UuidAttr>(NewAttribute)) {
+ // msvc will allow a subsequent definition to add an uuid to a class
+ ++I;
+ continue;
} else if (const AlignedAttr *AA = dyn_cast<AlignedAttr>(NewAttribute)) {
if (AA->isAlignas()) {
// C++11 [dcl.align]p6:
@@ -2993,28 +3007,6 @@ struct GNUCompatibleParamWarning {
} // end anonymous namespace
-/// getSpecialMember - get the special member enum for a method.
-Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) {
- if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) {
- if (Ctor->isDefaultConstructor())
- return Sema::CXXDefaultConstructor;
-
- if (Ctor->isCopyConstructor())
- return Sema::CXXCopyConstructor;
-
- if (Ctor->isMoveConstructor())
- return Sema::CXXMoveConstructor;
- } else if (isa<CXXDestructorDecl>(MD)) {
- return Sema::CXXDestructor;
- } else if (MD->isCopyAssignmentOperator()) {
- return Sema::CXXCopyAssignment;
- } else if (MD->isMoveAssignmentOperator()) {
- return Sema::CXXMoveAssignment;
- }
-
- return Sema::CXXInvalid;
-}
-
// Determine whether the previous declaration was a definition, implicit
// declaration, or a declaration.
template <typename T>
@@ -3668,6 +3660,11 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld);
}
+ // Check if the function types are compatible when pointer size address
+ // spaces are ignored.
+ if (Context.hasSameFunctionTypeIgnoringPtrSizes(OldQType, NewQType))
+ return false;
+
// GNU C permits a K&R definition to follow a prototype declaration
// if the declared types of the parameters in the K&R definition
// match the types in the prototype declaration, even when the
@@ -5032,6 +5029,8 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
/*BitWidth=*/nullptr, /*Mutable=*/false,
/*InitStyle=*/ICIS_NoInit);
Anon->setAccess(AS);
+ ProcessDeclAttributes(S, Anon, Dc);
+
if (getLangOpts().CPlusPlus)
FieldCollector->Add(cast<FieldDecl>(Anon));
} else {
@@ -5045,6 +5044,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
SC = SC_None;
}
+ assert(DS.getAttributes().empty() && "No attribute expected");
Anon = VarDecl::Create(Context, Owner, DS.getBeginLoc(),
Record->getLocation(), /*IdentifierInfo=*/nullptr,
Context.getTypeDeclType(Record), TInfo, SC);
@@ -6139,6 +6139,41 @@ bool Sema::inferObjCARCLifetime(ValueDecl *decl) {
return false;
}
+void Sema::deduceOpenCLAddressSpace(ValueDecl *Decl) {
+ if (Decl->getType().hasAddressSpace())
+ return;
+ if (VarDecl *Var = dyn_cast<VarDecl>(Decl)) {
+ QualType Type = Var->getType();
+ if (Type->isSamplerT() || Type->isVoidType())
+ return;
+ LangAS ImplAS = LangAS::opencl_private;
+ if ((getLangOpts().OpenCLCPlusPlus || getLangOpts().OpenCLVersion >= 200) &&
+ Var->hasGlobalStorage())
+ ImplAS = LangAS::opencl_global;
+ // If the original type from a decayed type is an array type and that array
+ // type has no address space yet, deduce it now.
+ if (auto DT = dyn_cast<DecayedType>(Type)) {
+ auto OrigTy = DT->getOriginalType();
+ if (!OrigTy.hasAddressSpace() && OrigTy->isArrayType()) {
+ // Add the address space to the original array type and then propagate
+ // that to the element type through `getAsArrayType`.
+ OrigTy = Context.getAddrSpaceQualType(OrigTy, ImplAS);
+ OrigTy = QualType(Context.getAsArrayType(OrigTy), 0);
+ // Re-generate the decayed type.
+ Type = Context.getDecayedType(OrigTy);
+ }
+ }
+ Type = Context.getAddrSpaceQualType(Type, ImplAS);
+ // Apply any qualifiers (including address space) from the array type to
+ // the element type. This implements C99 6.7.3p8: "If the specification of
+ // an array type includes any type qualifiers, the element type is so
+ // qualified, not the array type."
+ if (Type->isArrayType())
+ Type = QualType(Context.getAsArrayType(Type), 0);
+ Decl->setType(Type);
+ }
+}
+
static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) {
// Ensure that an auto decl is deduced otherwise the checks below might cache
// the wrong linkage.
@@ -6496,6 +6531,105 @@ static bool isDeclExternC(const Decl *D) {
llvm_unreachable("Unknown type of decl!");
}
+/// Returns true if there hasn't been any invalid type diagnosed.
+static bool diagnoseOpenCLTypes(Scope *S, Sema &Se, Declarator &D,
+ DeclContext *DC, QualType R) {
+ // OpenCL v2.0 s6.9.b - Image type can only be used as a function argument.
+ // OpenCL v2.0 s6.13.16.1 - Pipe type can only be used as a function
+ // argument.
+ if (R->isImageType() || R->isPipeType()) {
+ Se.Diag(D.getIdentifierLoc(),
+ diag::err_opencl_type_can_only_be_used_as_function_parameter)
+ << R;
+ D.setInvalidType();
+ return false;
+ }
+
+ // OpenCL v1.2 s6.9.r:
+ // The event type cannot be used to declare a program scope variable.
+ // OpenCL v2.0 s6.9.q:
+ // The clk_event_t and reserve_id_t types cannot be declared in program
+ // scope.
+ if (NULL == S->getParent()) {
+ if (R->isReserveIDT() || R->isClkEventT() || R->isEventT()) {
+ Se.Diag(D.getIdentifierLoc(),
+ diag::err_invalid_type_for_program_scope_var)
+ << R;
+ D.setInvalidType();
+ return false;
+ }
+ }
+
+ // OpenCL v1.0 s6.8.a.3: Pointers to functions are not allowed.
+ QualType NR = R;
+ while (NR->isPointerType()) {
+ if (NR->isFunctionPointerType()) {
+ Se.Diag(D.getIdentifierLoc(), diag::err_opencl_function_pointer);
+ D.setInvalidType();
+ return false;
+ }
+ NR = NR->getPointeeType();
+ }
+
+ if (!Se.getOpenCLOptions().isEnabled("cl_khr_fp16")) {
+ // OpenCL v1.2 s6.1.1.1: reject declaring variables of the half and
+ // half array type (unless the cl_khr_fp16 extension is enabled).
+ if (Se.Context.getBaseElementType(R)->isHalfType()) {
+ Se.Diag(D.getIdentifierLoc(), diag::err_opencl_half_declaration) << R;
+ D.setInvalidType();
+ return false;
+ }
+ }
+
+ // OpenCL v1.2 s6.9.r:
+ // The event type cannot be used with the __local, __constant and __global
+ // address space qualifiers.
+ if (R->isEventT()) {
+ if (R.getAddressSpace() != LangAS::opencl_private) {
+ Se.Diag(D.getBeginLoc(), diag::err_event_t_addr_space_qual);
+ D.setInvalidType();
+ return false;
+ }
+ }
+
+ // C++ for OpenCL does not allow the thread_local storage qualifier.
+ // OpenCL C does not support thread_local either, and
+ // also reject all other thread storage class specifiers.
+ DeclSpec::TSCS TSC = D.getDeclSpec().getThreadStorageClassSpec();
+ if (TSC != TSCS_unspecified) {
+ bool IsCXX = Se.getLangOpts().OpenCLCPlusPlus;
+ Se.Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
+ diag::err_opencl_unknown_type_specifier)
+ << IsCXX << Se.getLangOpts().getOpenCLVersionTuple().getAsString()
+ << DeclSpec::getSpecifierName(TSC) << 1;
+ D.setInvalidType();
+ return false;
+ }
+
+ if (R->isSamplerT()) {
+ // OpenCL v1.2 s6.9.b p4:
+ // The sampler type cannot be used with the __local and __global address
+ // space qualifiers.
+ if (R.getAddressSpace() == LangAS::opencl_local ||
+ R.getAddressSpace() == LangAS::opencl_global) {
+ Se.Diag(D.getIdentifierLoc(), diag::err_wrong_sampler_addressspace);
+ D.setInvalidType();
+ }
+
+ // OpenCL v1.2 s6.12.14.1:
+ // A global sampler must be declared with either the constant address
+ // space qualifier or with the const qualifier.
+ if (DC->isTranslationUnit() &&
+ !(R.getAddressSpace() == LangAS::opencl_constant ||
+ R.isConstQualified())) {
+ Se.Diag(D.getIdentifierLoc(), diag::err_opencl_nonconst_global_sampler);
+ D.setInvalidType();
+ }
+ if (D.isInvalidType())
+ return false;
+ }
+ return true;
+}
NamedDecl *Sema::ActOnVariableDeclarator(
Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo,
@@ -6519,95 +6653,6 @@ NamedDecl *Sema::ActOnVariableDeclarator(
return nullptr;
}
- if (getLangOpts().OpenCL) {
- // OpenCL v2.0 s6.9.b - Image type can only be used as a function argument.
- // OpenCL v2.0 s6.13.16.1 - Pipe type can only be used as a function
- // argument.
- if (R->isImageType() || R->isPipeType()) {
- Diag(D.getIdentifierLoc(),
- diag::err_opencl_type_can_only_be_used_as_function_parameter)
- << R;
- D.setInvalidType();
- return nullptr;
- }
-
- // OpenCL v1.2 s6.9.r:
- // The event type cannot be used to declare a program scope variable.
- // OpenCL v2.0 s6.9.q:
- // The clk_event_t and reserve_id_t types cannot be declared in program scope.
- if (NULL == S->getParent()) {
- if (R->isReserveIDT() || R->isClkEventT() || R->isEventT()) {
- Diag(D.getIdentifierLoc(),
- diag::err_invalid_type_for_program_scope_var) << R;
- D.setInvalidType();
- return nullptr;
- }
- }
-
- // OpenCL v1.0 s6.8.a.3: Pointers to functions are not allowed.
- QualType NR = R;
- while (NR->isPointerType()) {
- if (NR->isFunctionPointerType()) {
- Diag(D.getIdentifierLoc(), diag::err_opencl_function_pointer);
- D.setInvalidType();
- break;
- }
- NR = NR->getPointeeType();
- }
-
- if (!getOpenCLOptions().isEnabled("cl_khr_fp16")) {
- // OpenCL v1.2 s6.1.1.1: reject declaring variables of the half and
- // half array type (unless the cl_khr_fp16 extension is enabled).
- if (Context.getBaseElementType(R)->isHalfType()) {
- Diag(D.getIdentifierLoc(), diag::err_opencl_half_declaration) << R;
- D.setInvalidType();
- }
- }
-
- if (R->isSamplerT()) {
- // OpenCL v1.2 s6.9.b p4:
- // The sampler type cannot be used with the __local and __global address
- // space qualifiers.
- if (R.getAddressSpace() == LangAS::opencl_local ||
- R.getAddressSpace() == LangAS::opencl_global) {
- Diag(D.getIdentifierLoc(), diag::err_wrong_sampler_addressspace);
- }
-
- // OpenCL v1.2 s6.12.14.1:
- // A global sampler must be declared with either the constant address
- // space qualifier or with the const qualifier.
- if (DC->isTranslationUnit() &&
- !(R.getAddressSpace() == LangAS::opencl_constant ||
- R.isConstQualified())) {
- Diag(D.getIdentifierLoc(), diag::err_opencl_nonconst_global_sampler);
- D.setInvalidType();
- }
- }
-
- // OpenCL v1.2 s6.9.r:
- // The event type cannot be used with the __local, __constant and __global
- // address space qualifiers.
- if (R->isEventT()) {
- if (R.getAddressSpace() != LangAS::opencl_private) {
- Diag(D.getBeginLoc(), diag::err_event_t_addr_space_qual);
- D.setInvalidType();
- }
- }
-
- // C++ for OpenCL does not allow the thread_local storage qualifier.
- // OpenCL C does not support thread_local either, and
- // also reject all other thread storage class specifiers.
- DeclSpec::TSCS TSC = D.getDeclSpec().getThreadStorageClassSpec();
- if (TSC != TSCS_unspecified) {
- bool IsCXX = getLangOpts().OpenCLCPlusPlus;
- Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
- diag::err_opencl_unknown_type_specifier)
- << IsCXX << getLangOpts().getOpenCLVersionTuple().getAsString()
- << DeclSpec::getSpecifierName(TSC) << 1;
- D.setInvalidType();
- return nullptr;
- }
- }
DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec();
StorageClass SC = StorageClassSpecToVarDeclStorageClass(D.getDeclSpec());
@@ -6964,6 +7009,13 @@ NamedDecl *Sema::ActOnVariableDeclarator(
}
}
+ if (getLangOpts().OpenCL) {
+
+ deduceOpenCLAddressSpace(NewVD);
+
+ diagnoseOpenCLTypes(S, *this, D, DC, NewVD->getType());
+ }
+
// Handle attributes prior to checking for duplicates in MergeVarDecl
ProcessDeclAttributes(S, NewVD, D);
@@ -7039,8 +7091,9 @@ NamedDecl *Sema::ActOnVariableDeclarator(
}
}
- NewVD->addAttr(::new (Context) AsmLabelAttr(
- Context, SE->getStrTokenLoc(0), Label, /*IsLiteralLabel=*/true));
+ NewVD->addAttr(AsmLabelAttr::Create(Context, Label,
+ /*IsLiteralLabel=*/true,
+ SE->getStrTokenLoc(0)));
} else if (!ExtnameUndeclaredIdentifiers.empty()) {
llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I =
ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier());
@@ -7842,7 +7895,13 @@ struct FindOverriddenMethod {
Path.Decls = Path.Decls.slice(1)) {
NamedDecl *D = Path.Decls.front();
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
- if (MD->isVirtual() && !S->IsOverload(Method, MD, false))
+ if (MD->isVirtual() &&
+ !S->IsOverload(
+ Method, MD, /*UseMemberUsingDeclRules=*/false,
+ /*ConsiderCudaAttrs=*/true,
+ // C++2a [class.virtual]p2 does not consider requires clauses
+ // when overriding.
+ /*ConsiderRequiresClauses=*/false))
return true;
}
}
@@ -8187,7 +8246,8 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
NewFD = FunctionDecl::Create(SemaRef.Context, DC, D.getBeginLoc(), NameInfo,
R, TInfo, SC, isInline, HasPrototype,
- CSK_unspecified);
+ CSK_unspecified,
+ /*TrailingRequiresClause=*/nullptr);
if (D.isInvalidType())
NewFD->setInvalidDecl();
@@ -8204,6 +8264,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
ConstexprKind = CSK_unspecified;
D.getMutableDeclSpec().ClearConstexprSpec();
}
+ Expr *TrailingRequiresClause = D.getTrailingRequiresClause();
// Check that the return type is not an abstract class type.
// For record types, this is done by the AbstractClassUsageDiagnoser once
@@ -8223,7 +8284,8 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
return CXXConstructorDecl::Create(
SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
TInfo, ExplicitSpecifier, isInline,
- /*isImplicitlyDeclared=*/false, ConstexprKind);
+ /*isImplicitlyDeclared=*/false, ConstexprKind, InheritedConstructor(),
+ TrailingRequiresClause);
} else if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
// This is a C++ destructor declaration.
@@ -8232,8 +8294,8 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
CXXDestructorDecl *NewDD = CXXDestructorDecl::Create(
SemaRef.Context, Record, D.getBeginLoc(), NameInfo, R, TInfo,
- isInline,
- /*isImplicitlyDeclared=*/false, ConstexprKind);
+ isInline, /*isImplicitlyDeclared=*/false, ConstexprKind,
+ TrailingRequiresClause);
// If the destructor needs an implicit exception specification, set it
// now. FIXME: It'd be nice to be able to create the right type to start
@@ -8253,7 +8315,8 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
return FunctionDecl::Create(SemaRef.Context, DC, D.getBeginLoc(),
D.getIdentifierLoc(), Name, R, TInfo, SC,
isInline,
- /*hasPrototype=*/true, ConstexprKind);
+ /*hasPrototype=*/true, ConstexprKind,
+ TrailingRequiresClause);
}
} else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) {
@@ -8270,9 +8333,14 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
IsVirtualOkay = true;
return CXXConversionDecl::Create(
SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
- TInfo, isInline, ExplicitSpecifier, ConstexprKind, SourceLocation());
+ TInfo, isInline, ExplicitSpecifier, ConstexprKind, SourceLocation(),
+ TrailingRequiresClause);
} else if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) {
+ if (TrailingRequiresClause)
+ SemaRef.Diag(TrailingRequiresClause->getBeginLoc(),
+ diag::err_trailing_requires_clause_on_deduction_guide)
+ << TrailingRequiresClause->getSourceRange();
SemaRef.CheckDeductionGuideDeclarator(D, R, SC);
return CXXDeductionGuideDecl::Create(SemaRef.Context, DC, D.getBeginLoc(),
@@ -8294,7 +8362,8 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
// This is a C++ method declaration.
CXXMethodDecl *Ret = CXXMethodDecl::Create(
SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
- TInfo, SC, isInline, ConstexprKind, SourceLocation());
+ TInfo, SC, isInline, ConstexprKind, SourceLocation(),
+ TrailingRequiresClause);
IsVirtualOkay = !Ret->isStatic();
return Ret;
} else {
@@ -8308,7 +8377,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
// - we're in C++ (where every function has a prototype),
return FunctionDecl::Create(SemaRef.Context, DC, D.getBeginLoc(), NameInfo,
R, TInfo, SC, isInline, true /*HasPrototype*/,
- ConstexprKind);
+ ConstexprKind, TrailingRequiresClause);
}
}
@@ -8332,7 +8401,7 @@ static bool isOpenCLSizeDependentType(ASTContext &C, QualType Ty) {
QualType DesugaredTy = Ty;
do {
ArrayRef<StringRef> Names(SizeTypeNames);
- auto Match = llvm::find(Names, DesugaredTy.getAsString());
+ auto Match = llvm::find(Names, DesugaredTy.getUnqualifiedType().getAsString());
if (Names.end() != Match)
return true;
@@ -8943,9 +9012,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (Expr *E = (Expr*) D.getAsmLabel()) {
// The parser guarantees this is a string.
StringLiteral *SE = cast<StringLiteral>(E);
- NewFD->addAttr(::new (Context)
- AsmLabelAttr(Context, SE->getStrTokenLoc(0),
- SE->getString(), /*IsLiteralLabel=*/true));
+ NewFD->addAttr(AsmLabelAttr::Create(Context, SE->getString(),
+ /*IsLiteralLabel=*/true,
+ SE->getStrTokenLoc(0)));
} else if (!ExtnameUndeclaredIdentifiers.empty()) {
llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I =
ExtnameUndeclaredIdentifiers.find(NewFD->getIdentifier());
@@ -9551,6 +9620,29 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
+ // Diagnose no_builtin attribute on function declaration that are not a
+ // definition.
+ // FIXME: We should really be doing this in
+ // SemaDeclAttr.cpp::handleNoBuiltinAttr, unfortunately we only have access to
+ // the FunctionDecl and at this point of the code
+ // FunctionDecl::isThisDeclarationADefinition() which always returns `false`
+ // because Sema::ActOnStartOfFunctionDef has not been called yet.
+ if (const auto *NBA = NewFD->getAttr<NoBuiltinAttr>())
+ switch (D.getFunctionDefinitionKind()) {
+ case FDK_Defaulted:
+ case FDK_Deleted:
+ Diag(NBA->getLocation(),
+ diag::err_attribute_no_builtin_on_defaulted_deleted_function)
+ << NBA->getSpelling();
+ break;
+ case FDK_Declaration:
+ Diag(NBA->getLocation(), diag::err_attribute_no_builtin_on_non_definition)
+ << NBA->getSpelling();
+ break;
+ case FDK_Definition:
+ break;
+ }
+
return NewFD;
}
@@ -9687,7 +9779,7 @@ bool Sema::shouldLinkDependentDeclWithPrevious(Decl *D, Decl *PrevDecl) {
static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) {
const auto *TA = FD->getAttr<TargetAttr>();
assert(TA && "MultiVersion Candidate requires a target attribute");
- TargetAttr::ParsedTargetAttr ParseInfo = TA->parse();
+ ParsedTargetAttr ParseInfo = TA->parse();
const TargetInfo &TargetInfo = S.Context.getTargetInfo();
enum ErrType { Feature = 0, Architecture = 1 };
@@ -9764,13 +9856,15 @@ bool Sema::areMultiversionVariantFunctionsCompatible(
Linkage = 5,
};
- if (OldFD && !OldFD->getType()->getAs<FunctionProtoType>()) {
+ if (NoProtoDiagID.getDiagID() != 0 && OldFD &&
+ !OldFD->getType()->getAs<FunctionProtoType>()) {
Diag(OldFD->getLocation(), NoProtoDiagID);
Diag(NoteCausedDiagIDAt.first, NoteCausedDiagIDAt.second);
return true;
}
- if (!NewFD->getType()->getAs<FunctionProtoType>())
+ if (NoProtoDiagID.getDiagID() != 0 &&
+ !NewFD->getType()->getAs<FunctionProtoType>())
return Diag(NewFD->getLocation(), NoProtoDiagID);
if (!TemplatesSupported &&
@@ -9938,7 +10032,7 @@ static bool CheckTargetCausesMultiVersioning(
bool &Redeclaration, NamedDecl *&OldDecl, bool &MergeTypeWithPrevious,
LookupResult &Previous) {
const auto *OldTA = OldFD->getAttr<TargetAttr>();
- TargetAttr::ParsedTargetAttr NewParsed = NewTA->parse();
+ ParsedTargetAttr NewParsed = NewTA->parse();
// Sort order doesn't matter, it just needs to be consistent.
llvm::sort(NewParsed.Features);
@@ -9982,8 +10076,7 @@ static bool CheckTargetCausesMultiVersioning(
return true;
}
- TargetAttr::ParsedTargetAttr OldParsed =
- OldTA->parse(std::less<std::string>());
+ ParsedTargetAttr OldParsed = OldTA->parse(std::less<std::string>());
if (OldParsed == NewParsed) {
S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate);
@@ -10036,7 +10129,7 @@ static bool CheckMultiVersionAdditionalDecl(
return true;
}
- TargetAttr::ParsedTargetAttr NewParsed;
+ ParsedTargetAttr NewParsed;
if (NewTA) {
NewParsed = NewTA->parse();
llvm::sort(NewParsed.Features);
@@ -10063,8 +10156,7 @@ static bool CheckMultiVersionAdditionalDecl(
return false;
}
- TargetAttr::ParsedTargetAttr CurParsed =
- CurTA->parse(std::less<std::string>());
+ ParsedTargetAttr CurParsed = CurTA->parse(std::less<std::string>());
if (CurParsed == NewParsed) {
S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate);
S.Diag(CurFD->getLocation(), diag::note_previous_declaration);
@@ -10496,6 +10588,11 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
}
}
}
+ if (Method->isVirtual() && NewFD->getTrailingRequiresClause())
+ // C++2a [class.virtual]p6
+ // A virtual method shall not have a requires-clause.
+ Diag(NewFD->getTrailingRequiresClause()->getBeginLoc(),
+ diag::err_constrained_virtual_method);
if (Method->isStatic())
checkThisInStaticMemberFunctionType(Method);
@@ -11281,6 +11378,9 @@ bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit,
if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(VDecl))
VDecl->setInvalidDecl();
+ if (getLangOpts().OpenCL)
+ deduceOpenCLAddressSpace(VDecl);
+
// If this is a redeclaration, check that the type we just deduced matches
// the previously declared type.
if (VarDecl *Old = VDecl->getPreviousDecl()) {
@@ -12145,6 +12245,10 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
Diag(Var->getLocation(), diag::note_private_extern);
}
+ if (Context.getTargetInfo().allowDebugInfoForExternalVar() &&
+ !Var->isInvalidDecl() && !getLangOpts().CPlusPlus)
+ ExternalDeclarations.push_back(Var);
+
return;
case VarDecl::TentativeDefinition:
@@ -13103,6 +13207,10 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
if (New->hasAttr<BlocksAttr>()) {
Diag(New->getLocation(), diag::err_block_on_nonlocal);
}
+
+ if (getLangOpts().OpenCL)
+ deduceOpenCLAddressSpace(New);
+
return New;
}
@@ -13315,8 +13423,10 @@ ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
return false;
// Don't warn about 'main'.
- if (FD->isMain())
- return false;
+ if (isa<TranslationUnitDecl>(FD->getDeclContext()->getRedeclContext()))
+ if (IdentifierInfo *II = FD->getIdentifier())
+ if (II->isStr("main"))
+ return false;
// Don't warn about inline functions.
if (FD->isInlined())
@@ -13826,8 +13936,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
LSI->ReturnType.isNull() ? Context.VoidTy : LSI->ReturnType;
// Update the return type to the deduced type.
- const FunctionProtoType *Proto =
- FD->getType()->getAs<FunctionProtoType>();
+ const auto *Proto = FD->getType()->castAs<FunctionProtoType>();
FD->setType(Context.getFunctionType(RetType, Proto->getParamTypes(),
Proto->getExtProtoInfo()));
}
@@ -16031,7 +16140,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
}
// TR 18037 does not allow fields to be declared with address space
- if (T.getQualifiers().hasAddressSpace() || T->isDependentAddressSpaceType() ||
+ if (T.hasAddressSpace() || T->isDependentAddressSpaceType() ||
T->getBaseElementTypeUnsafe()->isDependentAddressSpaceType()) {
Diag(Loc, diag::err_field_with_address_space);
Record->setInvalidDecl();
@@ -16754,7 +16863,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
if (const MSInheritanceAttr *IA = Record->getAttr<MSInheritanceAttr>())
checkMSInheritanceAttrOnDefinition(cast<CXXRecordDecl>(Record),
IA->getRange(), IA->getBestCase(),
- IA->getSemanticSpelling());
+ IA->getInheritanceModel());
}
// Check if the structure/union declaration is a type that can have zero
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index b2be6245a814..5c51b0f9b8cb 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -23,6 +23,7 @@
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/DeclSpec.h"
@@ -1068,6 +1069,56 @@ static void handleDiagnoseIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
S.Context, AL, Cond, Msg, DiagType, ArgDependent, cast<NamedDecl>(D)));
}
+static void handleNoBuiltinAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ static constexpr const StringRef kWildcard = "*";
+
+ llvm::SmallVector<StringRef, 16> Names;
+ bool HasWildcard = false;
+
+ const auto AddBuiltinName = [&Names, &HasWildcard](StringRef Name) {
+ if (Name == kWildcard)
+ HasWildcard = true;
+ Names.push_back(Name);
+ };
+
+ // Add previously defined attributes.
+ if (const auto *NBA = D->getAttr<NoBuiltinAttr>())
+ for (StringRef BuiltinName : NBA->builtinNames())
+ AddBuiltinName(BuiltinName);
+
+ // Add current attributes.
+ if (AL.getNumArgs() == 0)
+ AddBuiltinName(kWildcard);
+ else
+ for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
+ StringRef BuiltinName;
+ SourceLocation LiteralLoc;
+ if (!S.checkStringLiteralArgumentAttr(AL, I, BuiltinName, &LiteralLoc))
+ return;
+
+ if (Builtin::Context::isBuiltinFunc(BuiltinName))
+ AddBuiltinName(BuiltinName);
+ else
+ S.Diag(LiteralLoc, diag::warn_attribute_no_builtin_invalid_builtin_name)
+ << BuiltinName << AL.getAttrName()->getName();
+ }
+
+ // Repeating the same attribute is fine.
+ llvm::sort(Names);
+ Names.erase(std::unique(Names.begin(), Names.end()), Names.end());
+
+ // Empty no_builtin must be on its own.
+ if (HasWildcard && Names.size() > 1)
+ S.Diag(D->getLocation(),
+ diag::err_attribute_no_builtin_wildcard_or_builtin_name)
+ << AL.getAttrName()->getName();
+
+ if (D->hasAttr<NoBuiltinAttr>())
+ D->dropAttr<NoBuiltinAttr>();
+ D->addAttr(::new (S.Context)
+ NoBuiltinAttr(S.Context, AL, Names.data(), Names.size()));
+}
+
static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (D->hasAttr<PassObjectSizeAttr>()) {
S.Diag(D->getBeginLoc(), diag::err_attribute_only_once_per_parameter) << AL;
@@ -2549,6 +2600,29 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const ParsedAttr &AL,
D->addAttr(newAttr);
}
+static void handleObjCDirectAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ // objc_direct cannot be set on methods declared in the context of a protocol
+ if (isa<ObjCProtocolDecl>(D->getDeclContext())) {
+ S.Diag(AL.getLoc(), diag::err_objc_direct_on_protocol) << false;
+ return;
+ }
+
+ if (S.getLangOpts().ObjCRuntime.allowsDirectDispatch()) {
+ handleSimpleAttribute<ObjCDirectAttr>(S, D, AL);
+ } else {
+ S.Diag(AL.getLoc(), diag::warn_objc_direct_ignored) << AL;
+ }
+}
+
+static void handleObjCDirectMembersAttr(Sema &S, Decl *D,
+ const ParsedAttr &AL) {
+ if (S.getLangOpts().ObjCRuntime.allowsDirectDispatch()) {
+ handleSimpleAttribute<ObjCDirectMembersAttr>(S, D, AL);
+ } else {
+ S.Diag(AL.getLoc(), diag::warn_objc_direct_ignored) << AL;
+ }
+}
+
static void handleObjCMethodFamilyAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
const auto *M = cast<ObjCMethodDecl>(D);
if (!AL.isArgIdent(0)) {
@@ -2839,7 +2913,7 @@ static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!ParmType->isExtVectorType() && !ParmType->isFloatingType() &&
(ParmType->isBooleanType() ||
!ParmType->isIntegralType(S.getASTContext()))) {
- S.Diag(AL.getLoc(), diag::err_attribute_invalid_argument) << 3 << AL;
+ S.Diag(AL.getLoc(), diag::err_attribute_invalid_argument) << 2 << AL;
return;
}
@@ -2972,7 +3046,7 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
<< Unsupported << None << Str;
- TargetAttr::ParsedTargetAttr ParsedAttrs = TargetAttr::parse(AttrStr);
+ ParsedTargetAttr ParsedAttrs = TargetAttr::parse(AttrStr);
if (!ParsedAttrs.Architecture.empty() &&
!Context.getTargetInfo().isValidCPUName(ParsedAttrs.Architecture))
@@ -2990,6 +3064,19 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
<< Unsupported << None << CurFeature;
}
+ TargetInfo::BranchProtectionInfo BPI;
+ StringRef Error;
+ if (!ParsedAttrs.BranchProtection.empty() &&
+ !Context.getTargetInfo().validateBranchProtection(
+ ParsedAttrs.BranchProtection, BPI, Error)) {
+ if (Error.empty())
+ return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
+ << Unsupported << None << "branch-protection";
+ else
+ return Diag(LiteralLoc, diag::err_invalid_branch_protection_spec)
+ << Error;
+ }
+
return false;
}
@@ -3798,7 +3885,7 @@ void Sema::CheckAlignasUnderalignment(Decl *D) {
bool Sema::checkMSInheritanceAttrOnDefinition(
CXXRecordDecl *RD, SourceRange Range, bool BestCase,
- MSInheritanceAttr::Spelling SemanticSpelling) {
+ MSInheritanceModel ExplicitModel) {
assert(RD->hasDefinition() && "RD has no definition!");
// We may not have seen base specifiers or any virtual methods yet. We will
@@ -3807,14 +3894,14 @@ bool Sema::checkMSInheritanceAttrOnDefinition(
return false;
// The unspecified model never matches what a definition could need.
- if (SemanticSpelling == MSInheritanceAttr::Keyword_unspecified_inheritance)
+ if (ExplicitModel == MSInheritanceModel::Unspecified)
return false;
if (BestCase) {
- if (RD->calculateInheritanceModel() == SemanticSpelling)
+ if (RD->calculateInheritanceModel() == ExplicitModel)
return false;
} else {
- if (RD->calculateInheritanceModel() <= SemanticSpelling)
+ if (RD->calculateInheritanceModel() <= ExplicitModel)
return false;
}
@@ -4367,12 +4454,10 @@ static void handleLifetimeCategoryAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
ParmType = S.GetTypeFromParser(AL.getTypeArg(), &DerefTypeLoc);
unsigned SelectIdx = ~0U;
- if (ParmType->isVoidType())
+ if (ParmType->isReferenceType())
SelectIdx = 0;
- else if (ParmType->isReferenceType())
- SelectIdx = 1;
else if (ParmType->isArrayType())
- SelectIdx = 2;
+ SelectIdx = 1;
if (SelectIdx != ~0U) {
S.Diag(AL.getLoc(), diag::err_attribute_invalid_argument)
@@ -4830,6 +4915,54 @@ static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
XRayLogArgsAttr(S.Context, AL, ArgCount.getSourceIndex()));
}
+static void handlePatchableFunctionEntryAttr(Sema &S, Decl *D,
+ const ParsedAttr &AL) {
+ uint32_t Count = 0, Offset = 0;
+ if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), Count, 0, true))
+ return;
+ if (AL.getNumArgs() == 2) {
+ Expr *Arg = AL.getArgAsExpr(1);
+ if (!checkUInt32Argument(S, AL, Arg, Offset, 1, true))
+ return;
+ if (Offset) {
+ S.Diag(getAttrLoc(AL), diag::err_attribute_argument_out_of_range)
+ << &AL << 0 << 0 << Arg->getBeginLoc();
+ return;
+ }
+ }
+ D->addAttr(::new (S.Context)
+ PatchableFunctionEntryAttr(S.Context, AL, Count, Offset));
+}
+
+static bool ArmMveAliasValid(unsigned BuiltinID, StringRef AliasName) {
+ if (AliasName.startswith("__arm_"))
+ AliasName = AliasName.substr(6);
+ switch (BuiltinID) {
+#include "clang/Basic/arm_mve_builtin_aliases.inc"
+ default:
+ return false;
+ }
+}
+
+static void handleArmMveAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ if (!AL.isArgIdent(0)) {
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
+ << AL << 1 << AANT_ArgumentIdentifier;
+ return;
+ }
+
+ IdentifierInfo *Ident = AL.getArgAsIdent(0)->Ident;
+ unsigned BuiltinID = Ident->getBuiltinID();
+
+ if (!ArmMveAliasValid(BuiltinID,
+ cast<FunctionDecl>(D)->getIdentifier()->getName())) {
+ S.Diag(AL.getLoc(), diag::err_attribute_arm_mve_alias);
+ return;
+ }
+
+ D->addAttr(::new (S.Context) ArmMveAliasAttr(S.Context, AL, Ident));
+}
+
//===----------------------------------------------------------------------===//
// Checker-specific attribute handlers.
//===----------------------------------------------------------------------===//
@@ -5278,9 +5411,11 @@ UuidAttr *Sema::mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI,
if (const auto *UA = D->getAttr<UuidAttr>()) {
if (UA->getGuid().equals_lower(Uuid))
return nullptr;
- Diag(UA->getLocation(), diag::err_mismatched_uuid);
- Diag(CI.getLoc(), diag::note_previous_uuid);
- D->dropAttr<UuidAttr>();
+ if (!UA->getGuid().empty()) {
+ Diag(UA->getLocation(), diag::err_mismatched_uuid);
+ Diag(CI.getLoc(), diag::note_previous_uuid);
+ D->dropAttr<UuidAttr>();
+ }
}
return ::new (Context) UuidAttr(Context, CI, Uuid);
@@ -5342,8 +5477,7 @@ static void handleMSInheritanceAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
MSInheritanceAttr *IA = S.mergeMSInheritanceAttr(
- D, AL, /*BestCase=*/true,
- (MSInheritanceAttr::Spelling)AL.getSemanticSpelling());
+ D, AL, /*BestCase=*/true, (MSInheritanceModel)AL.getSemanticSpelling());
if (IA) {
D->addAttr(IA);
S.Consumer.AssignInheritanceModel(cast<CXXRecordDecl>(D));
@@ -5620,6 +5754,47 @@ static void handleAVRSignalAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
handleSimpleAttribute<AVRSignalAttr>(S, D, AL);
}
+static void handleBPFPreserveAIRecord(Sema &S, RecordDecl *RD) {
+ // Add preserve_access_index attribute to all fields and inner records.
+ for (auto D : RD->decls()) {
+ if (D->hasAttr<BPFPreserveAccessIndexAttr>())
+ continue;
+
+ D->addAttr(BPFPreserveAccessIndexAttr::CreateImplicit(S.Context));
+ if (auto *Rec = dyn_cast<RecordDecl>(D))
+ handleBPFPreserveAIRecord(S, Rec);
+ }
+}
+
+static void handleBPFPreserveAccessIndexAttr(Sema &S, Decl *D,
+ const ParsedAttr &AL) {
+ auto *Rec = cast<RecordDecl>(D);
+ handleBPFPreserveAIRecord(S, Rec);
+ Rec->addAttr(::new (S.Context) BPFPreserveAccessIndexAttr(S.Context, AL));
+}
+
+static void handleWebAssemblyExportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ if (!isFunctionOrMethod(D)) {
+ S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
+ << "'export_name'" << ExpectedFunction;
+ return;
+ }
+
+ auto *FD = cast<FunctionDecl>(D);
+ if (FD->isThisDeclarationADefinition()) {
+ S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0;
+ return;
+ }
+
+ StringRef Str;
+ SourceLocation ArgLoc;
+ if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
+ return;
+
+ D->addAttr(::new (S.Context) WebAssemblyExportNameAttr(S.Context, AL, Str));
+ D->addAttr(UsedAttr::CreateImplicit(S.Context));
+}
+
static void handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!isFunctionOrMethod(D)) {
S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
@@ -5977,9 +6152,9 @@ static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) {
MSInheritanceAttr *
Sema::mergeMSInheritanceAttr(Decl *D, const AttributeCommonInfo &CI,
bool BestCase,
- MSInheritanceAttr::Spelling SemanticSpelling) {
+ MSInheritanceModel Model) {
if (MSInheritanceAttr *IA = D->getAttr<MSInheritanceAttr>()) {
- if (IA->getSemanticSpelling() == SemanticSpelling)
+ if (IA->getInheritanceModel() == Model)
return nullptr;
Diag(IA->getLocation(), diag::err_mismatched_ms_inheritance)
<< 1 /*previous declaration*/;
@@ -5990,7 +6165,7 @@ Sema::mergeMSInheritanceAttr(Decl *D, const AttributeCommonInfo &CI,
auto *RD = cast<CXXRecordDecl>(D);
if (RD->hasDefinition()) {
if (checkMSInheritanceAttrOnDefinition(RD, CI.getRange(), BestCase,
- SemanticSpelling)) {
+ Model)) {
return nullptr;
}
} else {
@@ -6278,6 +6453,45 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(::new (S.Context) OpenCLAccessAttr(S.Context, AL));
}
+static void handleSYCLKernelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ // The 'sycl_kernel' attribute applies only to function templates.
+ const auto *FD = cast<FunctionDecl>(D);
+ const FunctionTemplateDecl *FT = FD->getDescribedFunctionTemplate();
+ assert(FT && "Function template is expected");
+
+ // Function template must have at least two template parameters.
+ const TemplateParameterList *TL = FT->getTemplateParameters();
+ if (TL->size() < 2) {
+ S.Diag(FT->getLocation(), diag::warn_sycl_kernel_num_of_template_params);
+ return;
+ }
+
+ // Template parameters must be typenames.
+ for (unsigned I = 0; I < 2; ++I) {
+ const NamedDecl *TParam = TL->getParam(I);
+ if (isa<NonTypeTemplateParmDecl>(TParam)) {
+ S.Diag(FT->getLocation(),
+ diag::warn_sycl_kernel_invalid_template_param_type);
+ return;
+ }
+ }
+
+ // Function must have at least one argument.
+ if (getFunctionOrMethodNumParams(D) != 1) {
+ S.Diag(FT->getLocation(), diag::warn_sycl_kernel_num_of_function_params);
+ return;
+ }
+
+ // Function must return void.
+ QualType RetTy = getFunctionOrMethodResultType(D);
+ if (!RetTy->isVoidType()) {
+ S.Diag(FT->getLocation(), diag::warn_sycl_kernel_return_type);
+ return;
+ }
+
+ handleSimpleAttribute<SYCLKernelAttr>(S, D, AL);
+}
+
static void handleDestroyAttr(Sema &S, Decl *D, const ParsedAttr &A) {
if (!cast<VarDecl>(D)->hasGlobalStorage()) {
S.Diag(D->getLocation(), diag::err_destroy_attr_on_non_static_var)
@@ -6406,6 +6620,50 @@ static void handleMSAllocatorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
handleSimpleAttribute<MSAllocatorAttr>(S, D, AL);
}
+static void handeAcquireHandleAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ if (AL.isUsedAsTypeAttr())
+ return;
+ // Warn if the parameter is definitely not an output parameter.
+ if (const auto *PVD = dyn_cast<ParmVarDecl>(D)) {
+ if (PVD->getType()->isIntegerType()) {
+ S.Diag(AL.getLoc(), diag::err_attribute_output_parameter)
+ << AL.getRange();
+ return;
+ }
+ }
+ StringRef Argument;
+ if (!S.checkStringLiteralArgumentAttr(AL, 0, Argument))
+ return;
+ D->addAttr(AcquireHandleAttr::Create(S.Context, Argument, AL));
+}
+
+template<typename Attr>
+static void handleHandleAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ StringRef Argument;
+ if (!S.checkStringLiteralArgumentAttr(AL, 0, Argument))
+ return;
+ D->addAttr(Attr::Create(S.Context, Argument, AL));
+}
+
+static void handleCFGuardAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ // The guard attribute takes a single identifier argument.
+
+ if (!AL.isArgIdent(0)) {
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
+ << AL << AANT_ArgumentIdentifier;
+ return;
+ }
+
+ CFGuardAttr::GuardArg Arg;
+ IdentifierInfo *II = AL.getArgAsIdent(0)->Ident;
+ if (!CFGuardAttr::ConvertStrToGuardArg(II->getName(), Arg)) {
+ S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) CFGuardAttr(S.Context, AL, Arg));
+}
+
//===----------------------------------------------------------------------===//
// Top Level Sema Entry Points
//===----------------------------------------------------------------------===//
@@ -6496,6 +6754,12 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_AVRSignal:
handleAVRSignalAttr(S, D, AL);
break;
+ case ParsedAttr::AT_BPFPreserveAccessIndex:
+ handleBPFPreserveAccessIndexAttr(S, D, AL);
+ break;
+ case ParsedAttr::AT_WebAssemblyExportName:
+ handleWebAssemblyExportNameAttr(S, D, AL);
+ break;
case ParsedAttr::AT_WebAssemblyImportModule:
handleWebAssemblyImportModuleAttr(S, D, AL);
break;
@@ -6578,6 +6842,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_DiagnoseIf:
handleDiagnoseIfAttr(S, D, AL);
break;
+ case ParsedAttr::AT_NoBuiltin:
+ handleNoBuiltinAttr(S, D, AL);
+ break;
case ParsedAttr::AT_ExtVectorType:
handleExtVectorTypeAttr(S, D, AL);
break;
@@ -6599,6 +6866,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_Flatten:
handleSimpleAttribute<FlattenAttr>(S, D, AL);
break;
+ case ParsedAttr::AT_SYCLKernel:
+ handleSYCLKernelAttr(S, D, AL);
+ break;
case ParsedAttr::AT_Format:
handleFormatAttr(S, D, AL);
break;
@@ -6826,6 +7096,13 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_ObjCRootClass:
handleSimpleAttribute<ObjCRootClassAttr>(S, D, AL);
break;
+ case ParsedAttr::AT_ObjCDirect:
+ handleObjCDirectAttr(S, D, AL);
+ break;
+ case ParsedAttr::AT_ObjCDirectMembers:
+ handleObjCDirectMembersAttr(S, D, AL);
+ handleSimpleAttribute<ObjCDirectMembersAttr>(S, D, AL);
+ break;
case ParsedAttr::AT_ObjCNonLazyClass:
handleSimpleAttribute<ObjCNonLazyClassAttr>(S, D, AL);
break;
@@ -7015,6 +7292,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_AbiTag:
handleAbiTagAttr(S, D, AL);
break;
+ case ParsedAttr::AT_CFGuard:
+ handleCFGuardAttr(S, D, AL);
+ break;
// Thread safety attributes:
case ParsedAttr::AT_AssertExclusiveLock:
@@ -7135,6 +7415,10 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleXRayLogArgsAttr(S, D, AL);
break;
+ case ParsedAttr::AT_PatchableFunctionEntry:
+ handlePatchableFunctionEntryAttr(S, D, AL);
+ break;
+
// Move semantics attribute.
case ParsedAttr::AT_Reinitializes:
handleSimpleAttribute<ReinitializesAttr>(S, D, AL);
@@ -7160,6 +7444,22 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_MSAllocator:
handleMSAllocatorAttr(S, D, AL);
break;
+
+ case ParsedAttr::AT_ArmMveAlias:
+ handleArmMveAliasAttr(S, D, AL);
+ break;
+
+ case ParsedAttr::AT_AcquireHandle:
+ handeAcquireHandleAttr(S, D, AL);
+ break;
+
+ case ParsedAttr::AT_ReleaseHandle:
+ handleHandleAttr<ReleaseHandleAttr>(S, D, AL);
+ break;
+
+ case ParsedAttr::AT_UseHandle:
+ handleHandleAttr<UseHandleAttr>(S, D, AL);
+ break;
}
}
@@ -7238,7 +7538,8 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D,
}
}
-// Helper for delayed processing TransparentUnion attribute.
+// Helper for delayed processing TransparentUnion or BPFPreserveAccessIndexAttr
+// attribute.
void Sema::ProcessDeclAttributeDelayed(Decl *D,
const ParsedAttributesView &AttrList) {
for (const ParsedAttr &AL : AttrList)
@@ -7246,6 +7547,11 @@ void Sema::ProcessDeclAttributeDelayed(Decl *D,
handleTransparentUnionAttr(*this, D, AL);
break;
}
+
+ // For BPFPreserveAccessIndexAttr, we want to populate the attributes
+ // to fields and inner records as well.
+ if (D && D->hasAttr<BPFPreserveAccessIndexAttr>())
+ handleBPFPreserveAIRecord(*this, cast<RecordDecl>(D));
}
// Annotation attributes are the only attributes allowed after an access
@@ -7308,7 +7614,8 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II,
NewFD = FunctionDecl::Create(
FD->getASTContext(), FD->getDeclContext(), Loc, Loc,
DeclarationName(II), FD->getType(), FD->getTypeSourceInfo(), SC_None,
- false /*isInlineSpecified*/, FD->hasPrototype(), CSK_unspecified);
+ false /*isInlineSpecified*/, FD->hasPrototype(), CSK_unspecified,
+ FD->getTrailingRequiresClause());
NewD = NewFD;
if (FD->getQualifier())
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index ff90b9548e29..9916d3be77e1 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -217,8 +217,8 @@ Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc,
Exceptions.push_back(E);
}
-void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) {
- if (!E || ComputedEST == EST_MSAny)
+void Sema::ImplicitExceptionSpecification::CalledStmt(Stmt *S) {
+ if (!S || ComputedEST == EST_MSAny)
return;
// FIXME:
@@ -242,7 +242,7 @@ void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) {
// implicit definition. For now, we assume that any non-nothrow expression can
// throw any exception.
- if (Self->canThrow(E))
+ if (Self->canThrow(S))
ComputedEST = EST_None;
}
@@ -1501,13 +1501,13 @@ void Sema::MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old) {
// as pointers to member functions.
if (const ReferenceType *R = NewType->getAs<ReferenceType>()) {
NewType = R->getPointeeType();
- OldType = OldType->getAs<ReferenceType>()->getPointeeType();
+ OldType = OldType->castAs<ReferenceType>()->getPointeeType();
} else if (const PointerType *P = NewType->getAs<PointerType>()) {
NewType = P->getPointeeType();
- OldType = OldType->getAs<PointerType>()->getPointeeType();
+ OldType = OldType->castAs<PointerType>()->getPointeeType();
} else if (const MemberPointerType *M = NewType->getAs<MemberPointerType>()) {
NewType = M->getPointeeType();
- OldType = OldType->getAs<MemberPointerType>()->getPointeeType();
+ OldType = OldType->castAs<MemberPointerType>()->getPointeeType();
}
if (!NewType->isFunctionProtoType())
@@ -1627,14 +1627,13 @@ static bool CheckConstexprDestructorSubobjects(Sema &SemaRef,
return true;
}
-// CheckConstexprParameterTypes - Check whether a function's parameter types
-// are all literal types. If so, return true. If not, produce a suitable
-// diagnostic and return false.
+/// Check whether a function's parameter types are all literal types. If so,
+/// return true. If not, produce a suitable diagnostic and return false.
static bool CheckConstexprParameterTypes(Sema &SemaRef,
const FunctionDecl *FD,
Sema::CheckConstexprKind Kind) {
unsigned ArgIndex = 0;
- const FunctionProtoType *FT = FD->getType()->getAs<FunctionProtoType>();
+ const auto *FT = FD->getType()->castAs<FunctionProtoType>();
for (FunctionProtoType::param_type_iterator i = FT->param_type_begin(),
e = FT->param_type_end();
i != e; ++i, ++ArgIndex) {
@@ -1649,6 +1648,17 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef,
return true;
}
+/// Check whether a function's return type is a literal type. If so, return
+/// true. If not, produce a suitable diagnostic and return false.
+static bool CheckConstexprReturnType(Sema &SemaRef, const FunctionDecl *FD,
+ Sema::CheckConstexprKind Kind) {
+ if (CheckLiteralType(SemaRef, Kind, FD->getLocation(), FD->getReturnType(),
+ diag::err_constexpr_non_literal_return,
+ FD->isConsteval()))
+ return false;
+ return true;
+}
+
/// Get diagnostic %select index for tag kind for
/// record diagnostic message.
/// WARNING: Indexes apply to particular diagnostics only!
@@ -1729,10 +1739,7 @@ bool Sema::CheckConstexprFunctionDefinition(const FunctionDecl *NewFD,
}
// - its return type shall be a literal type;
- QualType RT = NewFD->getReturnType();
- if (CheckLiteralType(*this, Kind, NewFD->getLocation(), RT,
- diag::err_constexpr_non_literal_return,
- NewFD->isConsteval()))
+ if (!CheckConstexprReturnType(*this, NewFD, Kind))
return false;
}
@@ -3800,7 +3807,7 @@ namespace {
const CXXRecordDecl *RD = Constructor->getParent();
- if (RD->getDescribedClassTemplate())
+ if (RD->isDependentContext())
return;
// Holds fields that are uninitialized.
@@ -3861,6 +3868,26 @@ void Sema::ActOnStartCXXInClassMemberInitializer() {
PushFunctionScope();
}
+void Sema::ActOnStartTrailingRequiresClause(Scope *S, Declarator &D) {
+ if (!D.isFunctionDeclarator())
+ return;
+ auto &FTI = D.getFunctionTypeInfo();
+ if (!FTI.Params)
+ return;
+ for (auto &Param : ArrayRef<DeclaratorChunk::ParamInfo>(FTI.Params,
+ FTI.NumParams)) {
+ auto *ParamDecl = cast<NamedDecl>(Param.Param);
+ if (ParamDecl->getDeclName())
+ PushOnScopeChains(ParamDecl, S, /*AddToContext=*/false);
+ }
+}
+
+ExprResult Sema::ActOnFinishTrailingRequiresClause(ExprResult ConstraintExpr) {
+ if (ConstraintExpr.isInvalid())
+ return ExprError();
+ return CorrectDelayedTyposInExpr(ConstraintExpr);
+}
+
/// 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.
@@ -6084,6 +6111,67 @@ void Sema::propagateDLLAttrToBaseClassTemplate(
}
}
+/// Determine the kind of defaulting that would be done for a given function.
+///
+/// If the function is both a default constructor and a copy / move constructor
+/// (due to having a default argument for the first parameter), this picks
+/// CXXDefaultConstructor.
+///
+/// FIXME: Check that case is properly handled by all callers.
+Sema::DefaultedFunctionKind
+Sema::getDefaultedFunctionKind(const FunctionDecl *FD) {
+ if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(FD)) {
+ if (Ctor->isDefaultConstructor())
+ return Sema::CXXDefaultConstructor;
+
+ if (Ctor->isCopyConstructor())
+ return Sema::CXXCopyConstructor;
+
+ if (Ctor->isMoveConstructor())
+ return Sema::CXXMoveConstructor;
+ }
+
+ if (MD->isCopyAssignmentOperator())
+ return Sema::CXXCopyAssignment;
+
+ if (MD->isMoveAssignmentOperator())
+ return Sema::CXXMoveAssignment;
+
+ if (isa<CXXDestructorDecl>(FD))
+ return Sema::CXXDestructor;
+ }
+
+ switch (FD->getDeclName().getCXXOverloadedOperator()) {
+ case OO_EqualEqual:
+ return DefaultedComparisonKind::Equal;
+
+ case OO_ExclaimEqual:
+ return DefaultedComparisonKind::NotEqual;
+
+ case OO_Spaceship:
+ // No point allowing this if <=> doesn't exist in the current language mode.
+ if (!getLangOpts().CPlusPlus2a)
+ break;
+ return DefaultedComparisonKind::ThreeWay;
+
+ case OO_Less:
+ case OO_LessEqual:
+ case OO_Greater:
+ case OO_GreaterEqual:
+ // No point allowing this if <=> doesn't exist in the current language mode.
+ if (!getLangOpts().CPlusPlus2a)
+ break;
+ return DefaultedComparisonKind::Relational;
+
+ default:
+ break;
+ }
+
+ // Not defaultable.
+ return DefaultedFunctionKind();
+}
+
static void DefineImplicitSpecialMember(Sema &S, CXXMethodDecl *MD,
SourceLocation DefaultLoc) {
switch (S.getSpecialMember(MD)) {
@@ -6228,7 +6316,11 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D,
/// Perform semantic checks on a class definition that has been
/// completing, introducing implicitly-declared members, checking for
/// abstract types, etc.
-void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
+///
+/// \param S The scope in which the class was parsed. Null if we didn't just
+/// parse a class definition.
+/// \param Record The completed class.
+void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
if (!Record)
return;
@@ -6330,10 +6422,30 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
if (HasTrivialABI)
Record->setHasTrivialSpecialMemberForCall();
+ // Explicitly-defaulted secondary comparison functions (!=, <, <=, >, >=).
+ // We check these last because they can depend on the properties of the
+ // primary comparison functions (==, <=>).
+ llvm::SmallVector<FunctionDecl*, 5> DefaultedSecondaryComparisons;
+
+ auto CheckForDefaultedFunction = [&](FunctionDecl *FD) {
+ if (!FD || FD->isInvalidDecl() || !FD->isExplicitlyDefaulted())
+ return;
+
+ DefaultedFunctionKind DFK = getDefaultedFunctionKind(FD);
+ if (DFK.asComparison() == DefaultedComparisonKind::NotEqual ||
+ DFK.asComparison() == DefaultedComparisonKind::Relational)
+ DefaultedSecondaryComparisons.push_back(FD);
+ else
+ CheckExplicitlyDefaultedFunction(S, FD);
+ };
+
auto CompleteMemberFunction = [&](CXXMethodDecl *M) {
- // Check whether the explicitly-defaulted special members are valid.
- if (!M->isInvalidDecl() && M->isExplicitlyDefaulted())
- CheckExplicitlyDefaultedSpecialMember(M);
+ // Check whether the explicitly-defaulted members are valid.
+ CheckForDefaultedFunction(M);
+
+ // Skip the rest of the checks for a member of a dependent class.
+ if (Record->isDependentType())
+ return;
// For an explicitly defaulted or deleted special member, we defer
// determining triviality until the class is complete. That time is now!
@@ -6379,40 +6491,52 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
DefineImplicitSpecialMember(*this, M, M->getLocation());
};
+ // Check the destructor before any other member function. We need to
+ // determine whether it's trivial in order to determine whether the claas
+ // type is a literal type, which is a prerequisite for determining whether
+ // other special member functions are valid and whether they're implicitly
+ // 'constexpr'.
+ if (CXXDestructorDecl *Dtor = Record->getDestructor())
+ CompleteMemberFunction(Dtor);
+
bool HasMethodWithOverrideControl = false,
HasOverridingMethodWithoutOverrideControl = false;
- if (!Record->isDependentType()) {
- // Check the destructor before any other member function. We need to
- // determine whether it's trivial in order to determine whether the claas
- // type is a literal type, which is a prerequisite for determining whether
- // other special member functions are valid and whether they're implicitly
- // 'constexpr'.
- if (CXXDestructorDecl *Dtor = Record->getDestructor())
- CompleteMemberFunction(Dtor);
-
- for (auto *M : Record->methods()) {
- // See if a method overloads virtual methods in a base
- // class without overriding any.
- if (!M->isStatic())
- DiagnoseHiddenVirtualMethods(M);
- if (M->hasAttr<OverrideAttr>())
- HasMethodWithOverrideControl = true;
- else if (M->size_overridden_methods() > 0)
- HasOverridingMethodWithoutOverrideControl = true;
+ for (auto *D : Record->decls()) {
+ if (auto *M = dyn_cast<CXXMethodDecl>(D)) {
+ // FIXME: We could do this check for dependent types with non-dependent
+ // bases.
+ if (!Record->isDependentType()) {
+ // See if a method overloads virtual methods in a base
+ // class without overriding any.
+ if (!M->isStatic())
+ DiagnoseHiddenVirtualMethods(M);
+ if (M->hasAttr<OverrideAttr>())
+ HasMethodWithOverrideControl = true;
+ else if (M->size_overridden_methods() > 0)
+ HasOverridingMethodWithoutOverrideControl = true;
+ }
if (!isa<CXXDestructorDecl>(M))
CompleteMemberFunction(M);
+ } else if (auto *F = dyn_cast<FriendDecl>(D)) {
+ CheckForDefaultedFunction(
+ dyn_cast_or_null<FunctionDecl>(F->getFriendDecl()));
}
}
if (HasMethodWithOverrideControl &&
HasOverridingMethodWithoutOverrideControl) {
// At least one method has the 'override' control declared.
- // Diagnose all other overridden methods which do not have 'override' specified on them.
+ // Diagnose all other overridden methods which do not have 'override'
+ // specified on them.
for (auto *M : Record->methods())
DiagnoseAbsenceOfOverrideControl(M);
}
+ // Check the defaulted secondary comparisons after any other member functions.
+ for (FunctionDecl *FD : DefaultedSecondaryComparisons)
+ CheckExplicitlyDefaultedFunction(S, FD);
+
// ms_struct is a request to use the same ABI rules as MSVC. Check
// whether this class uses any C++ features that are implemented
// completely differently in MSVC, and if so, emit a diagnostic.
@@ -6710,20 +6834,50 @@ static bool defaultedSpecialMemberIsConstexpr(
return true;
}
+namespace {
+/// RAII object to register a defaulted function as having its exception
+/// specification computed.
+struct ComputingExceptionSpec {
+ Sema &S;
+
+ ComputingExceptionSpec(Sema &S, FunctionDecl *FD, SourceLocation Loc)
+ : S(S) {
+ Sema::CodeSynthesisContext Ctx;
+ Ctx.Kind = Sema::CodeSynthesisContext::ExceptionSpecEvaluation;
+ Ctx.PointOfInstantiation = Loc;
+ Ctx.Entity = FD;
+ S.pushCodeSynthesisContext(Ctx);
+ }
+ ~ComputingExceptionSpec() {
+ S.popCodeSynthesisContext();
+ }
+};
+}
+
static Sema::ImplicitExceptionSpecification
ComputeDefaultedSpecialMemberExceptionSpec(
Sema &S, SourceLocation Loc, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM,
Sema::InheritedConstructorInfo *ICI);
static Sema::ImplicitExceptionSpecification
-computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, CXXMethodDecl *MD) {
- auto CSM = S.getSpecialMember(MD);
- if (CSM != Sema::CXXInvalid)
- return ComputeDefaultedSpecialMemberExceptionSpec(S, Loc, MD, CSM, nullptr);
+ComputeDefaultedComparisonExceptionSpec(Sema &S, SourceLocation Loc,
+ FunctionDecl *FD,
+ Sema::DefaultedComparisonKind DCK);
+
+static Sema::ImplicitExceptionSpecification
+computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, FunctionDecl *FD) {
+ auto DFK = S.getDefaultedFunctionKind(FD);
+ if (DFK.isSpecialMember())
+ return ComputeDefaultedSpecialMemberExceptionSpec(
+ S, Loc, cast<CXXMethodDecl>(FD), DFK.asSpecialMember(), nullptr);
+ if (DFK.isComparison())
+ return ComputeDefaultedComparisonExceptionSpec(S, Loc, FD,
+ DFK.asComparison());
- auto *CD = cast<CXXConstructorDecl>(MD);
+ auto *CD = cast<CXXConstructorDecl>(FD);
assert(CD->getInheritedConstructor() &&
- "only special members have implicit exception specs");
+ "only defaulted functions and inherited constructors have implicit "
+ "exception specs");
Sema::InheritedConstructorInfo ICI(
S, Loc, CD->getInheritedConstructor().getShadowDecl());
return ComputeDefaultedSpecialMemberExceptionSpec(
@@ -6745,34 +6899,46 @@ static FunctionProtoType::ExtProtoInfo getImplicitMethodEPI(Sema &S,
return EPI;
}
-void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD) {
- const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
+void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, FunctionDecl *FD) {
+ const FunctionProtoType *FPT = FD->getType()->castAs<FunctionProtoType>();
if (FPT->getExceptionSpecType() != EST_Unevaluated)
return;
// Evaluate the exception specification.
- auto IES = computeImplicitExceptionSpec(*this, Loc, MD);
+ auto IES = computeImplicitExceptionSpec(*this, Loc, FD);
auto ESI = IES.getExceptionSpec();
// Update the type of the special member to use it.
- UpdateExceptionSpec(MD, ESI);
+ UpdateExceptionSpec(FD, ESI);
+}
+
+void Sema::CheckExplicitlyDefaultedFunction(Scope *S, FunctionDecl *FD) {
+ assert(FD->isExplicitlyDefaulted() && "not explicitly-defaulted");
- // A user-provided destructor can be defined outside the class. When that
- // happens, be sure to update the exception specification on both
- // declarations.
- const FunctionProtoType *CanonicalFPT =
- MD->getCanonicalDecl()->getType()->castAs<FunctionProtoType>();
- if (CanonicalFPT->getExceptionSpecType() == EST_Unevaluated)
- UpdateExceptionSpec(MD->getCanonicalDecl(), ESI);
+ DefaultedFunctionKind DefKind = getDefaultedFunctionKind(FD);
+ if (!DefKind) {
+ assert(FD->getDeclContext()->isDependentContext());
+ return;
+ }
+
+ if (DefKind.isSpecialMember()
+ ? CheckExplicitlyDefaultedSpecialMember(cast<CXXMethodDecl>(FD),
+ DefKind.asSpecialMember())
+ : CheckExplicitlyDefaultedComparison(S, FD, DefKind.asComparison()))
+ FD->setInvalidDecl();
}
-void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
+bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
+ CXXSpecialMember CSM) {
CXXRecordDecl *RD = MD->getParent();
- CXXSpecialMember CSM = getSpecialMember(MD);
assert(MD->isExplicitlyDefaulted() && CSM != CXXInvalid &&
"not an explicitly-defaulted special member");
+ // Defer all checking for special members of a dependent type.
+ if (RD->isDependentType())
+ return false;
+
// Whether this was the first-declared instance of the constructor.
// This affects whether we implicitly add an exception spec and constexpr.
bool First = MD == MD->getCanonicalDecl();
@@ -6781,7 +6947,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
// C++11 [dcl.fct.def.default]p1:
// A function that is explicitly defaulted shall
- // -- be a special member function (checked elsewhere),
+ // -- be a special member function [...] (checked elsewhere),
// -- have the same type (except for ref-qualifiers, and except that a
// copy operation can take a non-const reference) as an implicit
// declaration, and
@@ -6960,8 +7126,1124 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
}
}
- if (HadError)
- MD->setInvalidDecl();
+ return HadError;
+}
+
+namespace {
+/// Helper class for building and checking a defaulted comparison.
+///
+/// Defaulted functions are built in two phases:
+///
+/// * First, the set of operations that the function will perform are
+/// identified, and some of them are checked. If any of the checked
+/// operations is invalid in certain ways, the comparison function is
+/// defined as deleted and no body is built.
+/// * Then, if the function is not defined as deleted, the body is built.
+///
+/// This is accomplished by performing two visitation steps over the eventual
+/// body of the function.
+template<typename Derived, typename ResultList, typename Result,
+ typename Subobject>
+class DefaultedComparisonVisitor {
+public:
+ using DefaultedComparisonKind = Sema::DefaultedComparisonKind;
+
+ DefaultedComparisonVisitor(Sema &S, CXXRecordDecl *RD, FunctionDecl *FD,
+ DefaultedComparisonKind DCK)
+ : S(S), RD(RD), FD(FD), DCK(DCK) {
+ if (auto *Info = FD->getDefaultedFunctionInfo()) {
+ // FIXME: Change CreateOverloadedBinOp to take an ArrayRef instead of an
+ // UnresolvedSet to avoid this copy.
+ Fns.assign(Info->getUnqualifiedLookups().begin(),
+ Info->getUnqualifiedLookups().end());
+ }
+ }
+
+ ResultList visit() {
+ // The type of an lvalue naming a parameter of this function.
+ QualType ParamLvalType =
+ FD->getParamDecl(0)->getType().getNonReferenceType();
+
+ ResultList Results;
+
+ switch (DCK) {
+ case DefaultedComparisonKind::None:
+ llvm_unreachable("not a defaulted comparison");
+
+ case DefaultedComparisonKind::Equal:
+ case DefaultedComparisonKind::ThreeWay:
+ getDerived().visitSubobjects(Results, RD, ParamLvalType.getQualifiers());
+ return Results;
+
+ case DefaultedComparisonKind::NotEqual:
+ case DefaultedComparisonKind::Relational:
+ Results.add(getDerived().visitExpandedSubobject(
+ ParamLvalType, getDerived().getCompleteObject()));
+ return Results;
+ }
+ llvm_unreachable("");
+ }
+
+protected:
+ Derived &getDerived() { return static_cast<Derived&>(*this); }
+
+ /// Visit the expanded list of subobjects of the given type, as specified in
+ /// C++2a [class.compare.default].
+ ///
+ /// \return \c true if the ResultList object said we're done, \c false if not.
+ bool visitSubobjects(ResultList &Results, CXXRecordDecl *Record,
+ Qualifiers Quals) {
+ // C++2a [class.compare.default]p4:
+ // The direct base class subobjects of C
+ for (CXXBaseSpecifier &Base : Record->bases())
+ if (Results.add(getDerived().visitSubobject(
+ S.Context.getQualifiedType(Base.getType(), Quals),
+ getDerived().getBase(&Base))))
+ return true;
+
+ // followed by the non-static data members of C
+ for (FieldDecl *Field : Record->fields()) {
+ // Recursively expand anonymous structs.
+ if (Field->isAnonymousStructOrUnion()) {
+ if (visitSubobjects(Results, Field->getType()->getAsCXXRecordDecl(),
+ Quals))
+ return true;
+ continue;
+ }
+
+ // Figure out the type of an lvalue denoting this field.
+ Qualifiers FieldQuals = Quals;
+ if (Field->isMutable())
+ FieldQuals.removeConst();
+ QualType FieldType =
+ S.Context.getQualifiedType(Field->getType(), FieldQuals);
+
+ if (Results.add(getDerived().visitSubobject(
+ FieldType, getDerived().getField(Field))))
+ return true;
+ }
+
+ // form a list of subobjects.
+ return false;
+ }
+
+ Result visitSubobject(QualType Type, Subobject Subobj) {
+ // In that list, any subobject of array type is recursively expanded
+ const ArrayType *AT = S.Context.getAsArrayType(Type);
+ if (auto *CAT = dyn_cast_or_null<ConstantArrayType>(AT))
+ return getDerived().visitSubobjectArray(CAT->getElementType(),
+ CAT->getSize(), Subobj);
+ return getDerived().visitExpandedSubobject(Type, Subobj);
+ }
+
+ Result visitSubobjectArray(QualType Type, const llvm::APInt &Size,
+ Subobject Subobj) {
+ return getDerived().visitSubobject(Type, Subobj);
+ }
+
+protected:
+ Sema &S;
+ CXXRecordDecl *RD;
+ FunctionDecl *FD;
+ DefaultedComparisonKind DCK;
+ UnresolvedSet<16> Fns;
+};
+
+/// Information about a defaulted comparison, as determined by
+/// DefaultedComparisonAnalyzer.
+struct DefaultedComparisonInfo {
+ bool Deleted = false;
+ bool Constexpr = true;
+ ComparisonCategoryType Category = ComparisonCategoryType::StrongOrdering;
+
+ static DefaultedComparisonInfo deleted() {
+ DefaultedComparisonInfo Deleted;
+ Deleted.Deleted = true;
+ return Deleted;
+ }
+
+ bool add(const DefaultedComparisonInfo &R) {
+ Deleted |= R.Deleted;
+ Constexpr &= R.Constexpr;
+ Category = commonComparisonType(Category, R.Category);
+ return Deleted;
+ }
+};
+
+/// An element in the expanded list of subobjects of a defaulted comparison, as
+/// specified in C++2a [class.compare.default]p4.
+struct DefaultedComparisonSubobject {
+ enum { CompleteObject, Member, Base } Kind;
+ NamedDecl *Decl;
+ SourceLocation Loc;
+};
+
+/// A visitor over the notional body of a defaulted comparison that determines
+/// whether that body would be deleted or constexpr.
+class DefaultedComparisonAnalyzer
+ : public DefaultedComparisonVisitor<DefaultedComparisonAnalyzer,
+ DefaultedComparisonInfo,
+ DefaultedComparisonInfo,
+ DefaultedComparisonSubobject> {
+public:
+ enum DiagnosticKind { NoDiagnostics, ExplainDeleted, ExplainConstexpr };
+
+private:
+ DiagnosticKind Diagnose;
+
+public:
+ using Base = DefaultedComparisonVisitor;
+ using Result = DefaultedComparisonInfo;
+ using Subobject = DefaultedComparisonSubobject;
+
+ friend Base;
+
+ DefaultedComparisonAnalyzer(Sema &S, CXXRecordDecl *RD, FunctionDecl *FD,
+ DefaultedComparisonKind DCK,
+ DiagnosticKind Diagnose = NoDiagnostics)
+ : Base(S, RD, FD, DCK), Diagnose(Diagnose) {}
+
+ Result visit() {
+ if ((DCK == DefaultedComparisonKind::Equal ||
+ DCK == DefaultedComparisonKind::ThreeWay) &&
+ RD->hasVariantMembers()) {
+ // C++2a [class.compare.default]p2 [P2002R0]:
+ // A defaulted comparison operator function for class C is defined as
+ // deleted if [...] C has variant members.
+ if (Diagnose == ExplainDeleted) {
+ S.Diag(FD->getLocation(), diag::note_defaulted_comparison_union)
+ << FD << RD->isUnion() << RD;
+ }
+ return Result::deleted();
+ }
+
+ return Base::visit();
+ }
+
+private:
+ Subobject getCompleteObject() {
+ return Subobject{Subobject::CompleteObject, nullptr, FD->getLocation()};
+ }
+
+ Subobject getBase(CXXBaseSpecifier *Base) {
+ return Subobject{Subobject::Base, Base->getType()->getAsCXXRecordDecl(),
+ Base->getBaseTypeLoc()};
+ }
+
+ Subobject getField(FieldDecl *Field) {
+ return Subobject{Subobject::Member, Field, Field->getLocation()};
+ }
+
+ Result visitExpandedSubobject(QualType Type, Subobject Subobj) {
+ // C++2a [class.compare.default]p2 [P2002R0]:
+ // A defaulted <=> or == operator function for class C is defined as
+ // deleted if any non-static data member of C is of reference type
+ if (Type->isReferenceType()) {
+ if (Diagnose == ExplainDeleted) {
+ S.Diag(Subobj.Loc, diag::note_defaulted_comparison_reference_member)
+ << FD << RD;
+ }
+ return Result::deleted();
+ }
+
+ // [...] Let xi be an lvalue denoting the ith element [...]
+ OpaqueValueExpr Xi(FD->getLocation(), Type, VK_LValue);
+ Expr *Args[] = {&Xi, &Xi};
+
+ // All operators start by trying to apply that same operator recursively.
+ OverloadedOperatorKind OO = FD->getOverloadedOperator();
+ assert(OO != OO_None && "not an overloaded operator!");
+ return visitBinaryOperator(OO, Args, Subobj);
+ }
+
+ Result
+ visitBinaryOperator(OverloadedOperatorKind OO, ArrayRef<Expr *> Args,
+ Subobject Subobj,
+ OverloadCandidateSet *SpaceshipCandidates = nullptr) {
+ // Note that there is no need to consider rewritten candidates here if
+ // we've already found there is no viable 'operator<=>' candidate (and are
+ // considering synthesizing a '<=>' from '==' and '<').
+ OverloadCandidateSet CandidateSet(
+ FD->getLocation(), OverloadCandidateSet::CSK_Operator,
+ OverloadCandidateSet::OperatorRewriteInfo(
+ OO, /*AllowRewrittenCandidates=*/!SpaceshipCandidates));
+
+ /// C++2a [class.compare.default]p1 [P2002R0]:
+ /// [...] the defaulted function itself is never a candidate for overload
+ /// resolution [...]
+ CandidateSet.exclude(FD);
+
+ S.LookupOverloadedBinOp(CandidateSet, OO, Fns, Args);
+
+ Result R;
+
+ OverloadCandidateSet::iterator Best;
+ switch (CandidateSet.BestViableFunction(S, FD->getLocation(), Best)) {
+ case OR_Success: {
+ // C++2a [class.compare.secondary]p2 [P2002R0]:
+ // The operator function [...] is defined as deleted if [...] the
+ // candidate selected by overload resolution is not a rewritten
+ // candidate.
+ if ((DCK == DefaultedComparisonKind::NotEqual ||
+ DCK == DefaultedComparisonKind::Relational) &&
+ !Best->RewriteKind) {
+ if (Diagnose == ExplainDeleted) {
+ S.Diag(Best->Function->getLocation(),
+ diag::note_defaulted_comparison_not_rewritten_callee)
+ << FD;
+ }
+ return Result::deleted();
+ }
+
+ // Throughout C++2a [class.compare]: if overload resolution does not
+ // result in a usable function, the candidate function is defined as
+ // deleted. This requires that we selected an accessible function.
+ //
+ // Note that this only considers the access of the function when named
+ // within the type of the subobject, and not the access path for any
+ // derived-to-base conversion.
+ CXXRecordDecl *ArgClass = Args[0]->getType()->getAsCXXRecordDecl();
+ if (ArgClass && Best->FoundDecl.getDecl() &&
+ Best->FoundDecl.getDecl()->isCXXClassMember()) {
+ QualType ObjectType = Subobj.Kind == Subobject::Member
+ ? Args[0]->getType()
+ : S.Context.getRecordType(RD);
+ if (!S.isMemberAccessibleForDeletion(
+ ArgClass, Best->FoundDecl, ObjectType, Subobj.Loc,
+ Diagnose == ExplainDeleted
+ ? S.PDiag(diag::note_defaulted_comparison_inaccessible)
+ << FD << Subobj.Kind << Subobj.Decl
+ : S.PDiag()))
+ return Result::deleted();
+ }
+
+ // C++2a [class.compare.default]p3 [P2002R0]:
+ // A defaulted comparison function is constexpr-compatible if [...]
+ // no overlod resolution performed [...] results in a non-constexpr
+ // function.
+ if (FunctionDecl *BestFD = Best->Function) {
+ assert(!BestFD->isDeleted() && "wrong overload resolution result");
+ // If it's not constexpr, explain why not.
+ if (Diagnose == ExplainConstexpr && !BestFD->isConstexpr()) {
+ if (Subobj.Kind != Subobject::CompleteObject)
+ S.Diag(Subobj.Loc, diag::note_defaulted_comparison_not_constexpr)
+ << Subobj.Kind << Subobj.Decl;
+ S.Diag(BestFD->getLocation(),
+ diag::note_defaulted_comparison_not_constexpr_here);
+ // Bail out after explaining; we don't want any more notes.
+ return Result::deleted();
+ }
+ R.Constexpr &= BestFD->isConstexpr();
+ }
+
+ if (OO == OO_Spaceship && FD->getReturnType()->isUndeducedAutoType()) {
+ if (auto *BestFD = Best->Function) {
+ if (auto *Info = S.Context.CompCategories.lookupInfoForType(
+ BestFD->getCallResultType())) {
+ R.Category = Info->Kind;
+ } else {
+ if (Diagnose == ExplainDeleted) {
+ S.Diag(Subobj.Loc, diag::note_defaulted_comparison_cannot_deduce)
+ << Subobj.Kind << Subobj.Decl
+ << BestFD->getCallResultType().withoutLocalFastQualifiers();
+ S.Diag(BestFD->getLocation(),
+ diag::note_defaulted_comparison_cannot_deduce_callee)
+ << Subobj.Kind << Subobj.Decl;
+ }
+ return Result::deleted();
+ }
+ } else {
+ Optional<ComparisonCategoryType> Cat =
+ getComparisonCategoryForBuiltinCmp(Args[0]->getType());
+ assert(Cat && "no category for builtin comparison?");
+ R.Category = *Cat;
+ }
+ }
+
+ // Note that we might be rewriting to a different operator. That call is
+ // not considered until we come to actually build the comparison function.
+ break;
+ }
+
+ case OR_Ambiguous:
+ if (Diagnose == ExplainDeleted) {
+ unsigned Kind = 0;
+ if (FD->getOverloadedOperator() == OO_Spaceship && OO != OO_Spaceship)
+ Kind = OO == OO_EqualEqual ? 1 : 2;
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(
+ Subobj.Loc, S.PDiag(diag::note_defaulted_comparison_ambiguous)
+ << FD << Kind << Subobj.Kind << Subobj.Decl),
+ S, OCD_AmbiguousCandidates, Args);
+ }
+ R = Result::deleted();
+ break;
+
+ case OR_Deleted:
+ if (Diagnose == ExplainDeleted) {
+ if ((DCK == DefaultedComparisonKind::NotEqual ||
+ DCK == DefaultedComparisonKind::Relational) &&
+ !Best->RewriteKind) {
+ S.Diag(Best->Function->getLocation(),
+ diag::note_defaulted_comparison_not_rewritten_callee)
+ << FD;
+ } else {
+ S.Diag(Subobj.Loc,
+ diag::note_defaulted_comparison_calls_deleted)
+ << FD << Subobj.Kind << Subobj.Decl;
+ S.NoteDeletedFunction(Best->Function);
+ }
+ }
+ R = Result::deleted();
+ break;
+
+ case OR_No_Viable_Function:
+ // If there's no usable candidate, we're done unless we can rewrite a
+ // '<=>' in terms of '==' and '<'.
+ if (OO == OO_Spaceship &&
+ S.Context.CompCategories.lookupInfoForType(FD->getReturnType())) {
+ // For any kind of comparison category return type, we need a usable
+ // '==' and a usable '<'.
+ if (!R.add(visitBinaryOperator(OO_EqualEqual, Args, Subobj,
+ &CandidateSet)))
+ R.add(visitBinaryOperator(OO_Less, Args, Subobj, &CandidateSet));
+ break;
+ }
+
+ if (Diagnose == ExplainDeleted) {
+ S.Diag(Subobj.Loc, diag::note_defaulted_comparison_no_viable_function)
+ << FD << Subobj.Kind << Subobj.Decl;
+
+ // For a three-way comparison, list both the candidates for the
+ // original operator and the candidates for the synthesized operator.
+ if (SpaceshipCandidates) {
+ SpaceshipCandidates->NoteCandidates(
+ S, Args,
+ SpaceshipCandidates->CompleteCandidates(S, OCD_AllCandidates,
+ Args, FD->getLocation()));
+ S.Diag(Subobj.Loc,
+ diag::note_defaulted_comparison_no_viable_function_synthesized)
+ << (OO == OO_EqualEqual ? 0 : 1);
+ }
+
+ CandidateSet.NoteCandidates(
+ S, Args,
+ CandidateSet.CompleteCandidates(S, OCD_AllCandidates, Args,
+ FD->getLocation()));
+ }
+ R = Result::deleted();
+ break;
+ }
+
+ return R;
+ }
+};
+
+/// A list of statements.
+struct StmtListResult {
+ bool IsInvalid = false;
+ llvm::SmallVector<Stmt*, 16> Stmts;
+
+ bool add(const StmtResult &S) {
+ IsInvalid |= S.isInvalid();
+ if (IsInvalid)
+ return true;
+ Stmts.push_back(S.get());
+ return false;
+ }
+};
+
+/// A visitor over the notional body of a defaulted comparison that synthesizes
+/// the actual body.
+class DefaultedComparisonSynthesizer
+ : public DefaultedComparisonVisitor<DefaultedComparisonSynthesizer,
+ StmtListResult, StmtResult,
+ std::pair<ExprResult, ExprResult>> {
+ SourceLocation Loc;
+ unsigned ArrayDepth = 0;
+
+public:
+ using Base = DefaultedComparisonVisitor;
+ using ExprPair = std::pair<ExprResult, ExprResult>;
+
+ friend Base;
+
+ DefaultedComparisonSynthesizer(Sema &S, CXXRecordDecl *RD, FunctionDecl *FD,
+ DefaultedComparisonKind DCK,
+ SourceLocation BodyLoc)
+ : Base(S, RD, FD, DCK), Loc(BodyLoc) {}
+
+ /// Build a suitable function body for this defaulted comparison operator.
+ StmtResult build() {
+ Sema::CompoundScopeRAII CompoundScope(S);
+
+ StmtListResult Stmts = visit();
+ if (Stmts.IsInvalid)
+ return StmtError();
+
+ ExprResult RetVal;
+ switch (DCK) {
+ case DefaultedComparisonKind::None:
+ llvm_unreachable("not a defaulted comparison");
+
+ case DefaultedComparisonKind::Equal: {
+ // C++2a [class.eq]p3:
+ // [...] compar[e] the corresponding elements [...] until the first
+ // index i where xi == yi yields [...] false. If no such index exists,
+ // V is true. Otherwise, V is false.
+ //
+ // Join the comparisons with '&&'s and return the result. Use a right
+ // fold (traversing the conditions right-to-left), because that
+ // short-circuits more naturally.
+ auto OldStmts = std::move(Stmts.Stmts);
+ Stmts.Stmts.clear();
+ ExprResult CmpSoFar;
+ // Finish a particular comparison chain.
+ auto FinishCmp = [&] {
+ if (Expr *Prior = CmpSoFar.get()) {
+ // Convert the last expression to 'return ...;'
+ if (RetVal.isUnset() && Stmts.Stmts.empty())
+ RetVal = CmpSoFar;
+ // Convert any prior comparison to 'if (!(...)) return false;'
+ else if (Stmts.add(buildIfNotCondReturnFalse(Prior)))
+ return true;
+ CmpSoFar = ExprResult();
+ }
+ return false;
+ };
+ for (Stmt *EAsStmt : llvm::reverse(OldStmts)) {
+ Expr *E = dyn_cast<Expr>(EAsStmt);
+ if (!E) {
+ // Found an array comparison.
+ if (FinishCmp() || Stmts.add(EAsStmt))
+ return StmtError();
+ continue;
+ }
+
+ if (CmpSoFar.isUnset()) {
+ CmpSoFar = E;
+ continue;
+ }
+ CmpSoFar = S.CreateBuiltinBinOp(Loc, BO_LAnd, E, CmpSoFar.get());
+ if (CmpSoFar.isInvalid())
+ return StmtError();
+ }
+ if (FinishCmp())
+ return StmtError();
+ std::reverse(Stmts.Stmts.begin(), Stmts.Stmts.end());
+ // If no such index exists, V is true.
+ if (RetVal.isUnset())
+ RetVal = S.ActOnCXXBoolLiteral(Loc, tok::kw_true);
+ break;
+ }
+
+ case DefaultedComparisonKind::ThreeWay: {
+ // Per C++2a [class.spaceship]p3, as a fallback add:
+ // return static_cast<R>(std::strong_ordering::equal);
+ QualType StrongOrdering = S.CheckComparisonCategoryType(
+ ComparisonCategoryType::StrongOrdering, Loc,
+ Sema::ComparisonCategoryUsage::DefaultedOperator);
+ if (StrongOrdering.isNull())
+ return StmtError();
+ VarDecl *EqualVD = S.Context.CompCategories.getInfoForType(StrongOrdering)
+ .getValueInfo(ComparisonCategoryResult::Equal)
+ ->VD;
+ RetVal = getDecl(EqualVD);
+ if (RetVal.isInvalid())
+ return StmtError();
+ RetVal = buildStaticCastToR(RetVal.get());
+ break;
+ }
+
+ case DefaultedComparisonKind::NotEqual:
+ case DefaultedComparisonKind::Relational:
+ RetVal = cast<Expr>(Stmts.Stmts.pop_back_val());
+ break;
+ }
+
+ // Build the final return statement.
+ if (RetVal.isInvalid())
+ return StmtError();
+ StmtResult ReturnStmt = S.BuildReturnStmt(Loc, RetVal.get());
+ if (ReturnStmt.isInvalid())
+ return StmtError();
+ Stmts.Stmts.push_back(ReturnStmt.get());
+
+ return S.ActOnCompoundStmt(Loc, Loc, Stmts.Stmts, /*IsStmtExpr=*/false);
+ }
+
+private:
+ ExprResult getDecl(ValueDecl *VD) {
+ return S.BuildDeclarationNameExpr(
+ CXXScopeSpec(), DeclarationNameInfo(VD->getDeclName(), Loc), VD);
+ }
+
+ ExprResult getParam(unsigned I) {
+ ParmVarDecl *PD = FD->getParamDecl(I);
+ return getDecl(PD);
+ }
+
+ ExprPair getCompleteObject() {
+ unsigned Param = 0;
+ ExprResult LHS;
+ if (isa<CXXMethodDecl>(FD)) {
+ // LHS is '*this'.
+ LHS = S.ActOnCXXThis(Loc);
+ if (!LHS.isInvalid())
+ LHS = S.CreateBuiltinUnaryOp(Loc, UO_Deref, LHS.get());
+ } else {
+ LHS = getParam(Param++);
+ }
+ ExprResult RHS = getParam(Param++);
+ assert(Param == FD->getNumParams());
+ return {LHS, RHS};
+ }
+
+ ExprPair getBase(CXXBaseSpecifier *Base) {
+ ExprPair Obj = getCompleteObject();
+ if (Obj.first.isInvalid() || Obj.second.isInvalid())
+ return {ExprError(), ExprError()};
+ CXXCastPath Path = {Base};
+ return {S.ImpCastExprToType(Obj.first.get(), Base->getType(),
+ CK_DerivedToBase, VK_LValue, &Path),
+ S.ImpCastExprToType(Obj.second.get(), Base->getType(),
+ CK_DerivedToBase, VK_LValue, &Path)};
+ }
+
+ ExprPair getField(FieldDecl *Field) {
+ ExprPair Obj = getCompleteObject();
+ if (Obj.first.isInvalid() || Obj.second.isInvalid())
+ return {ExprError(), ExprError()};
+
+ DeclAccessPair Found = DeclAccessPair::make(Field, Field->getAccess());
+ DeclarationNameInfo NameInfo(Field->getDeclName(), Loc);
+ return {S.BuildFieldReferenceExpr(Obj.first.get(), /*IsArrow=*/false, Loc,
+ CXXScopeSpec(), Field, Found, NameInfo),
+ S.BuildFieldReferenceExpr(Obj.second.get(), /*IsArrow=*/false, Loc,
+ CXXScopeSpec(), Field, Found, NameInfo)};
+ }
+
+ // FIXME: When expanding a subobject, register a note in the code synthesis
+ // stack to say which subobject we're comparing.
+
+ StmtResult buildIfNotCondReturnFalse(ExprResult Cond) {
+ if (Cond.isInvalid())
+ return StmtError();
+
+ ExprResult NotCond = S.CreateBuiltinUnaryOp(Loc, UO_LNot, Cond.get());
+ if (NotCond.isInvalid())
+ return StmtError();
+
+ ExprResult False = S.ActOnCXXBoolLiteral(Loc, tok::kw_false);
+ assert(!False.isInvalid() && "should never fail");
+ StmtResult ReturnFalse = S.BuildReturnStmt(Loc, False.get());
+ if (ReturnFalse.isInvalid())
+ return StmtError();
+
+ return S.ActOnIfStmt(Loc, false, nullptr,
+ S.ActOnCondition(nullptr, Loc, NotCond.get(),
+ Sema::ConditionKind::Boolean),
+ ReturnFalse.get(), SourceLocation(), nullptr);
+ }
+
+ StmtResult visitSubobjectArray(QualType Type, llvm::APInt Size,
+ ExprPair Subobj) {
+ QualType SizeType = S.Context.getSizeType();
+ Size = Size.zextOrTrunc(S.Context.getTypeSize(SizeType));
+
+ // Build 'size_t i$n = 0'.
+ IdentifierInfo *IterationVarName = nullptr;
+ {
+ SmallString<8> Str;
+ llvm::raw_svector_ostream OS(Str);
+ OS << "i" << ArrayDepth;
+ IterationVarName = &S.Context.Idents.get(OS.str());
+ }
+ VarDecl *IterationVar = VarDecl::Create(
+ S.Context, S.CurContext, Loc, Loc, IterationVarName, SizeType,
+ S.Context.getTrivialTypeSourceInfo(SizeType, Loc), SC_None);
+ llvm::APInt Zero(S.Context.getTypeSize(SizeType), 0);
+ IterationVar->setInit(
+ IntegerLiteral::Create(S.Context, Zero, SizeType, Loc));
+ Stmt *Init = new (S.Context) DeclStmt(DeclGroupRef(IterationVar), Loc, Loc);
+
+ auto IterRef = [&] {
+ ExprResult Ref = S.BuildDeclarationNameExpr(
+ CXXScopeSpec(), DeclarationNameInfo(IterationVarName, Loc),
+ IterationVar);
+ assert(!Ref.isInvalid() && "can't reference our own variable?");
+ return Ref.get();
+ };
+
+ // Build 'i$n != Size'.
+ ExprResult Cond = S.CreateBuiltinBinOp(
+ Loc, BO_NE, IterRef(),
+ IntegerLiteral::Create(S.Context, Size, SizeType, Loc));
+ assert(!Cond.isInvalid() && "should never fail");
+
+ // Build '++i$n'.
+ ExprResult Inc = S.CreateBuiltinUnaryOp(Loc, UO_PreInc, IterRef());
+ assert(!Inc.isInvalid() && "should never fail");
+
+ // Build 'a[i$n]' and 'b[i$n]'.
+ auto Index = [&](ExprResult E) {
+ if (E.isInvalid())
+ return ExprError();
+ return S.CreateBuiltinArraySubscriptExpr(E.get(), Loc, IterRef(), Loc);
+ };
+ Subobj.first = Index(Subobj.first);
+ Subobj.second = Index(Subobj.second);
+
+ // Compare the array elements.
+ ++ArrayDepth;
+ StmtResult Substmt = visitSubobject(Type, Subobj);
+ --ArrayDepth;
+
+ if (Substmt.isInvalid())
+ return StmtError();
+
+ // For the inner level of an 'operator==', build 'if (!cmp) return false;'.
+ // For outer levels or for an 'operator<=>' we already have a suitable
+ // statement that returns as necessary.
+ if (Expr *ElemCmp = dyn_cast<Expr>(Substmt.get())) {
+ assert(DCK == DefaultedComparisonKind::Equal &&
+ "should have non-expression statement");
+ Substmt = buildIfNotCondReturnFalse(ElemCmp);
+ if (Substmt.isInvalid())
+ return StmtError();
+ }
+
+ // Build 'for (...) ...'
+ return S.ActOnForStmt(Loc, Loc, Init,
+ S.ActOnCondition(nullptr, Loc, Cond.get(),
+ Sema::ConditionKind::Boolean),
+ S.MakeFullDiscardedValueExpr(Inc.get()), Loc,
+ Substmt.get());
+ }
+
+ StmtResult visitExpandedSubobject(QualType Type, ExprPair Obj) {
+ if (Obj.first.isInvalid() || Obj.second.isInvalid())
+ return StmtError();
+
+ OverloadedOperatorKind OO = FD->getOverloadedOperator();
+ ExprResult Op = S.CreateOverloadedBinOp(
+ Loc, BinaryOperator::getOverloadedOpcode(OO), Fns,
+ Obj.first.get(), Obj.second.get(), /*PerformADL=*/true,
+ /*AllowRewrittenCandidates=*/true, FD);
+ if (Op.isInvalid())
+ return StmtError();
+
+ switch (DCK) {
+ case DefaultedComparisonKind::None:
+ llvm_unreachable("not a defaulted comparison");
+
+ case DefaultedComparisonKind::Equal:
+ // Per C++2a [class.eq]p2, each comparison is individually contextually
+ // converted to bool.
+ Op = S.PerformContextuallyConvertToBool(Op.get());
+ if (Op.isInvalid())
+ return StmtError();
+ return Op.get();
+
+ case DefaultedComparisonKind::ThreeWay: {
+ // Per C++2a [class.spaceship]p3, form:
+ // if (R cmp = static_cast<R>(op); cmp != 0)
+ // return cmp;
+ QualType R = FD->getReturnType();
+ Op = buildStaticCastToR(Op.get());
+ if (Op.isInvalid())
+ return StmtError();
+
+ // R cmp = ...;
+ IdentifierInfo *Name = &S.Context.Idents.get("cmp");
+ VarDecl *VD =
+ VarDecl::Create(S.Context, S.CurContext, Loc, Loc, Name, R,
+ S.Context.getTrivialTypeSourceInfo(R, Loc), SC_None);
+ S.AddInitializerToDecl(VD, Op.get(), /*DirectInit=*/false);
+ Stmt *InitStmt = new (S.Context) DeclStmt(DeclGroupRef(VD), Loc, Loc);
+
+ // cmp != 0
+ ExprResult VDRef = getDecl(VD);
+ if (VDRef.isInvalid())
+ return StmtError();
+ llvm::APInt ZeroVal(S.Context.getIntWidth(S.Context.IntTy), 0);
+ Expr *Zero =
+ IntegerLiteral::Create(S.Context, ZeroVal, S.Context.IntTy, Loc);
+ ExprResult Comp = S.CreateOverloadedBinOp(Loc, BO_NE, Fns, VDRef.get(),
+ Zero, true, true, FD);
+ if (Comp.isInvalid())
+ return StmtError();
+ Sema::ConditionResult Cond = S.ActOnCondition(
+ nullptr, Loc, Comp.get(), Sema::ConditionKind::Boolean);
+ if (Cond.isInvalid())
+ return StmtError();
+
+ // return cmp;
+ VDRef = getDecl(VD);
+ if (VDRef.isInvalid())
+ return StmtError();
+ StmtResult ReturnStmt = S.BuildReturnStmt(Loc, VDRef.get());
+ if (ReturnStmt.isInvalid())
+ return StmtError();
+
+ // if (...)
+ return S.ActOnIfStmt(Loc, /*IsConstexpr=*/false, InitStmt, Cond,
+ ReturnStmt.get(), /*ElseLoc=*/SourceLocation(),
+ /*Else=*/nullptr);
+ }
+
+ case DefaultedComparisonKind::NotEqual:
+ case DefaultedComparisonKind::Relational:
+ // C++2a [class.compare.secondary]p2:
+ // Otherwise, the operator function yields x @ y.
+ return Op.get();
+ }
+ llvm_unreachable("");
+ }
+
+ /// Build "static_cast<R>(E)".
+ ExprResult buildStaticCastToR(Expr *E) {
+ QualType R = FD->getReturnType();
+ assert(!R->isUndeducedType() && "type should have been deduced already");
+
+ // Don't bother forming a no-op cast in the common case.
+ if (E->isRValue() && S.Context.hasSameType(E->getType(), R))
+ return E;
+ return S.BuildCXXNamedCast(Loc, tok::kw_static_cast,
+ S.Context.getTrivialTypeSourceInfo(R, Loc), E,
+ SourceRange(Loc, Loc), SourceRange(Loc, Loc));
+ }
+};
+}
+
+/// Perform the unqualified lookups that might be needed to form a defaulted
+/// comparison function for the given operator.
+static void lookupOperatorsForDefaultedComparison(Sema &Self, Scope *S,
+ UnresolvedSetImpl &Operators,
+ OverloadedOperatorKind Op) {
+ auto Lookup = [&](OverloadedOperatorKind OO) {
+ Self.LookupOverloadedOperatorName(OO, S, QualType(), QualType(), Operators);
+ };
+
+ // Every defaulted operator looks up itself.
+ Lookup(Op);
+ // ... and the rewritten form of itself, if any.
+ if (OverloadedOperatorKind ExtraOp = getRewrittenOverloadedOperator(Op))
+ Lookup(ExtraOp);
+
+ // For 'operator<=>', we also form a 'cmp != 0' expression, and might
+ // synthesize a three-way comparison from '<' and '=='. In a dependent
+ // context, we also need to look up '==' in case we implicitly declare a
+ // defaulted 'operator=='.
+ if (Op == OO_Spaceship) {
+ Lookup(OO_ExclaimEqual);
+ Lookup(OO_Less);
+ Lookup(OO_EqualEqual);
+ }
+}
+
+bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD,
+ DefaultedComparisonKind DCK) {
+ assert(DCK != DefaultedComparisonKind::None && "not a defaulted comparison");
+
+ CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(FD->getLexicalDeclContext());
+ assert(RD && "defaulted comparison is not defaulted in a class");
+
+ // Perform any unqualified lookups we're going to need to default this
+ // function.
+ if (S) {
+ UnresolvedSet<32> Operators;
+ lookupOperatorsForDefaultedComparison(*this, S, Operators,
+ FD->getOverloadedOperator());
+ FD->setDefaultedFunctionInfo(FunctionDecl::DefaultedFunctionInfo::Create(
+ Context, Operators.pairs()));
+ }
+
+ // C++2a [class.compare.default]p1:
+ // A defaulted comparison operator function for some class C shall be a
+ // non-template function declared in the member-specification of C that is
+ // -- a non-static const member of C having one parameter of type
+ // const C&, or
+ // -- a friend of C having two parameters of type const C& or two
+ // parameters of type C.
+ QualType ExpectedParmType1 = Context.getRecordType(RD);
+ QualType ExpectedParmType2 =
+ Context.getLValueReferenceType(ExpectedParmType1.withConst());
+ if (isa<CXXMethodDecl>(FD))
+ ExpectedParmType1 = ExpectedParmType2;
+ for (const ParmVarDecl *Param : FD->parameters()) {
+ if (!Param->getType()->isDependentType() &&
+ !Context.hasSameType(Param->getType(), ExpectedParmType1) &&
+ !Context.hasSameType(Param->getType(), ExpectedParmType2)) {
+ // Don't diagnose an implicit 'operator=='; we will have diagnosed the
+ // corresponding defaulted 'operator<=>' already.
+ if (!FD->isImplicit()) {
+ Diag(FD->getLocation(), diag::err_defaulted_comparison_param)
+ << (int)DCK << Param->getType() << ExpectedParmType1
+ << !isa<CXXMethodDecl>(FD)
+ << ExpectedParmType2 << Param->getSourceRange();
+ }
+ return true;
+ }
+ }
+ if (FD->getNumParams() == 2 &&
+ !Context.hasSameType(FD->getParamDecl(0)->getType(),
+ FD->getParamDecl(1)->getType())) {
+ if (!FD->isImplicit()) {
+ Diag(FD->getLocation(), diag::err_defaulted_comparison_param_mismatch)
+ << (int)DCK
+ << FD->getParamDecl(0)->getType()
+ << FD->getParamDecl(0)->getSourceRange()
+ << FD->getParamDecl(1)->getType()
+ << FD->getParamDecl(1)->getSourceRange();
+ }
+ return true;
+ }
+
+ // ... non-static const member ...
+ if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ assert(!MD->isStatic() && "comparison function cannot be a static member");
+ if (!MD->isConst()) {
+ SourceLocation InsertLoc;
+ if (FunctionTypeLoc Loc = MD->getFunctionTypeLoc())
+ InsertLoc = getLocForEndOfToken(Loc.getRParenLoc());
+ // Don't diagnose an implicit 'operator=='; we will have diagnosed the
+ // corresponding defaulted 'operator<=>' already.
+ if (!MD->isImplicit()) {
+ Diag(MD->getLocation(), diag::err_defaulted_comparison_non_const)
+ << (int)DCK << FixItHint::CreateInsertion(InsertLoc, " const");
+ }
+
+ // Add the 'const' to the type to recover.
+ const auto *FPT = MD->getType()->castAs<FunctionProtoType>();
+ FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
+ EPI.TypeQuals.addConst();
+ MD->setType(Context.getFunctionType(FPT->getReturnType(),
+ FPT->getParamTypes(), EPI));
+ }
+ } else {
+ // A non-member function declared in a class must be a friend.
+ assert(FD->getFriendObjectKind() && "expected a friend declaration");
+ }
+
+ // C++2a [class.eq]p1, [class.rel]p1:
+ // A [defaulted comparison other than <=>] shall have a declared return
+ // type bool.
+ if (DCK != DefaultedComparisonKind::ThreeWay &&
+ !FD->getDeclaredReturnType()->isDependentType() &&
+ !Context.hasSameType(FD->getDeclaredReturnType(), Context.BoolTy)) {
+ Diag(FD->getLocation(), diag::err_defaulted_comparison_return_type_not_bool)
+ << (int)DCK << FD->getDeclaredReturnType() << Context.BoolTy
+ << FD->getReturnTypeSourceRange();
+ return true;
+ }
+ // 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())) {
+ Diag(FD->getLocation(),
+ diag::err_defaulted_comparison_deduced_return_type_not_auto)
+ << (int)DCK << FD->getDeclaredReturnType() << Context.AutoDeductTy
+ << FD->getReturnTypeSourceRange();
+ return true;
+ }
+
+ // For a defaulted function in a dependent class, defer all remaining checks
+ // until instantiation.
+ if (RD->isDependentType())
+ return false;
+
+ // Determine whether the function should be defined as deleted.
+ DefaultedComparisonInfo Info =
+ DefaultedComparisonAnalyzer(*this, RD, FD, DCK).visit();
+
+ 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) {
+ // 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.
+ //
+ // This is really just a consequence of the general rule that you can
+ // only delete a function on its first declaration.
+ Diag(FD->getLocation(), diag::err_non_first_default_compare_deletes)
+ << FD->isImplicit() << (int)DCK;
+ DefaultedComparisonAnalyzer(*this, RD, FD, DCK,
+ DefaultedComparisonAnalyzer::ExplainDeleted)
+ .visit();
+ return true;
+ }
+
+ SetDeclDeleted(FD, FD->getLocation());
+ if (!inTemplateInstantiation() && !FD->isImplicit()) {
+ Diag(FD->getLocation(), diag::warn_defaulted_comparison_deleted)
+ << (int)DCK;
+ DefaultedComparisonAnalyzer(*this, RD, FD, DCK,
+ DefaultedComparisonAnalyzer::ExplainDeleted)
+ .visit();
+ }
+ return false;
+ }
+
+ // C++2a [class.spaceship]p2:
+ // The return type is deduced as the common comparison type of R0, R1, ...
+ if (DCK == DefaultedComparisonKind::ThreeWay &&
+ FD->getDeclaredReturnType()->isUndeducedAutoType()) {
+ SourceLocation RetLoc = FD->getReturnTypeSourceRange().getBegin();
+ if (RetLoc.isInvalid())
+ RetLoc = FD->getBeginLoc();
+ // FIXME: Should we really care whether we have the complete type and the
+ // 'enumerator' constants here? A forward declaration seems sufficient.
+ QualType Cat = CheckComparisonCategoryType(
+ Info.Category, RetLoc, ComparisonCategoryUsage::DefaultedOperator);
+ if (Cat.isNull())
+ return true;
+ Context.adjustDeducedFunctionResultType(
+ FD, SubstAutoType(FD->getDeclaredReturnType(), Cat));
+ }
+
+ // C++2a [dcl.fct.def.default]p3 [P2002R0]:
+ // An explicitly-defaulted function that is not defined as deleted may be
+ // declared constexpr or consteval only if it is constexpr-compatible.
+ // C++2a [class.compare.default]p3 [P2002R0]:
+ // A defaulted comparison function is constexpr-compatible if it satisfies
+ // the requirements for a constexpr function [...]
+ // The only relevant requirements are that the parameter and return types are
+ // literal types. The remaining conditions are checked by the analyzer.
+ if (FD->isConstexpr()) {
+ if (CheckConstexprReturnType(*this, FD, CheckConstexprKind::Diagnose) &&
+ CheckConstexprParameterTypes(*this, FD, CheckConstexprKind::Diagnose) &&
+ !Info.Constexpr) {
+ Diag(FD->getBeginLoc(),
+ diag::err_incorrect_defaulted_comparison_constexpr)
+ << FD->isImplicit() << (int)DCK << FD->isConsteval();
+ DefaultedComparisonAnalyzer(*this, RD, FD, DCK,
+ DefaultedComparisonAnalyzer::ExplainConstexpr)
+ .visit();
+ }
+ }
+
+ // C++2a [dcl.fct.def.default]p3 [P2002R0]:
+ // If a constexpr-compatible function is explicitly defaulted on its first
+ // declaration, it is implicitly considered to be constexpr.
+ // FIXME: Only applying this to the first declaration seems problematic, as
+ // simple reorderings can affect the meaning of the program.
+ if (First && !FD->isConstexpr() && Info.Constexpr)
+ FD->setConstexprKind(CSK_constexpr);
+
+ // C++2a [except.spec]p3:
+ // If a declaration of a function does not have a noexcept-specifier
+ // [and] is defaulted on its first declaration, [...] the exception
+ // specification is as specified below
+ if (FD->getExceptionSpecType() == EST_None) {
+ auto *FPT = FD->getType()->castAs<FunctionProtoType>();
+ FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
+ EPI.ExceptionSpec.Type = EST_Unevaluated;
+ EPI.ExceptionSpec.SourceDecl = FD;
+ FD->setType(Context.getFunctionType(FPT->getReturnType(),
+ FPT->getParamTypes(), EPI));
+ }
+
+ return false;
+}
+
+void Sema::DeclareImplicitEqualityComparison(CXXRecordDecl *RD,
+ FunctionDecl *Spaceship) {
+ Sema::CodeSynthesisContext Ctx;
+ Ctx.Kind = Sema::CodeSynthesisContext::DeclaringImplicitEqualityComparison;
+ Ctx.PointOfInstantiation = Spaceship->getEndLoc();
+ Ctx.Entity = Spaceship;
+ pushCodeSynthesisContext(Ctx);
+
+ if (FunctionDecl *EqualEqual = SubstSpaceshipAsEqualEqual(RD, Spaceship))
+ EqualEqual->setImplicit();
+
+ popCodeSynthesisContext();
+}
+
+void Sema::DefineDefaultedComparison(SourceLocation UseLoc, FunctionDecl *FD,
+ DefaultedComparisonKind DCK) {
+ assert(FD->isDefaulted() && !FD->isDeleted() &&
+ !FD->doesThisDeclarationHaveABody());
+ if (FD->willHaveBody() || FD->isInvalidDecl())
+ return;
+
+ SynthesizedFunctionScope Scope(*this, FD);
+
+ // Add a context note for diagnostics produced after this point.
+ Scope.addContextNote(UseLoc);
+
+ {
+ // Build and set up the function body.
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(FD->getLexicalParent());
+ SourceLocation BodyLoc =
+ FD->getEndLoc().isValid() ? FD->getEndLoc() : FD->getLocation();
+ StmtResult Body =
+ DefaultedComparisonSynthesizer(*this, RD, FD, DCK, BodyLoc).build();
+ if (Body.isInvalid()) {
+ FD->setInvalidDecl();
+ return;
+ }
+ FD->setBody(Body.get());
+ FD->markUsed(Context);
+ }
+
+ // The exception specification is needed because we are defining the
+ // function. Note that this will reuse the body we just built.
+ ResolveExceptionSpec(UseLoc, FD->getType()->castAs<FunctionProtoType>());
+
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->CompletedImplicitDefinition(FD);
+}
+
+static Sema::ImplicitExceptionSpecification
+ComputeDefaultedComparisonExceptionSpec(Sema &S, SourceLocation Loc,
+ FunctionDecl *FD,
+ Sema::DefaultedComparisonKind DCK) {
+ ComputingExceptionSpec CES(S, FD, Loc);
+ Sema::ImplicitExceptionSpecification ExceptSpec(S);
+
+ if (FD->isInvalidDecl())
+ return ExceptSpec;
+
+ // The common case is that we just defined the comparison function. In that
+ // case, just look at whether the body can throw.
+ if (FD->hasBody()) {
+ ExceptSpec.CalledStmt(FD->getBody());
+ } else {
+ // Otherwise, build a body so we can check it. This should ideally only
+ // happen when we're not actually marking the function referenced. (This is
+ // only really important for efficiency: we don't want to build and throw
+ // away bodies for comparison functions more than we strictly need to.)
+
+ // Pretend to synthesize the function body in an unevaluated context.
+ // Note that we can't actually just go ahead and define the function here:
+ // we are not permitted to mark its callees as referenced.
+ Sema::SynthesizedFunctionScope Scope(S, FD);
+ EnterExpressionEvaluationContext Context(
+ S, Sema::ExpressionEvaluationContext::Unevaluated);
+
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(FD->getLexicalParent());
+ SourceLocation BodyLoc =
+ FD->getEndLoc().isValid() ? FD->getEndLoc() : FD->getLocation();
+ StmtResult Body =
+ DefaultedComparisonSynthesizer(S, RD, FD, DCK, BodyLoc).build();
+ if (!Body.isInvalid())
+ ExceptSpec.CalledStmt(Body.get());
+
+ // FIXME: Can we hold onto this body and just transform it to potentially
+ // evaluated when we're asked to define the function rather than rebuilding
+ // it? Either that, or we should only build the bits of the body that we
+ // need (the expressions, not the statements).
+ }
+
+ return ExceptSpec;
}
void Sema::CheckDelayedMemberExceptionSpecs() {
@@ -7157,7 +8439,8 @@ bool SpecialMemberDeletionInfo::isAccessible(Subobject Subobj,
objectTy = S.Context.getTypeDeclType(target->getParent());
}
- return S.isSpecialMemberAccessibleForDeletion(target, access, objectTy);
+ return S.isMemberAccessibleForDeletion(
+ target->getParent(), DeclAccessPair::make(target, access), objectTy);
}
/// Check whether we should delete a special member due to the implicit
@@ -7568,6 +8851,22 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
return false;
}
+void Sema::DiagnoseDeletedDefaultedFunction(FunctionDecl *FD) {
+ DefaultedFunctionKind DFK = getDefaultedFunctionKind(FD);
+ assert(DFK && "not a defaultable function");
+ assert(FD->isDefaulted() && FD->isDeleted() && "not defaulted and deleted");
+
+ if (DFK.isSpecialMember()) {
+ ShouldDeleteSpecialMember(cast<CXXMethodDecl>(FD), DFK.asSpecialMember(),
+ nullptr, /*Diagnose=*/true);
+ } else {
+ DefaultedComparisonAnalyzer(
+ *this, cast<CXXRecordDecl>(FD->getLexicalDeclContext()), FD,
+ DFK.asComparison(), DefaultedComparisonAnalyzer::ExplainDeleted)
+ .visit();
+ }
+}
+
/// Perform lookup for a special member of the specified kind, and determine
/// whether it is trivial. If the triviality can be determined without the
/// lookup, skip it. This is intended for use when determining whether a
@@ -8187,7 +9486,45 @@ void Sema::ActOnFinishCXXMemberSpecification(
reinterpret_cast<Decl**>(FieldCollector->getCurFields()),
FieldCollector->getCurNumFields()), LBrac, RBrac, AttrList);
- CheckCompletedCXXClass(cast<CXXRecordDecl>(TagDecl));
+ CheckCompletedCXXClass(S, cast<CXXRecordDecl>(TagDecl));
+}
+
+/// Find the equality comparison functions that should be implicitly declared
+/// in a given class definition, per C++2a [class.compare.default]p3.
+static void findImplicitlyDeclaredEqualityComparisons(
+ ASTContext &Ctx, CXXRecordDecl *RD,
+ llvm::SmallVectorImpl<FunctionDecl *> &Spaceships) {
+ DeclarationName EqEq = Ctx.DeclarationNames.getCXXOperatorName(OO_EqualEqual);
+ if (!RD->lookup(EqEq).empty())
+ // Member operator== explicitly declared: no implicit operator==s.
+ return;
+
+ // Traverse friends looking for an '==' or a '<=>'.
+ for (FriendDecl *Friend : RD->friends()) {
+ FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Friend->getFriendDecl());
+ if (!FD) continue;
+
+ if (FD->getOverloadedOperator() == OO_EqualEqual) {
+ // Friend operator== explicitly declared: no implicit operator==s.
+ Spaceships.clear();
+ return;
+ }
+
+ if (FD->getOverloadedOperator() == OO_Spaceship &&
+ FD->isExplicitlyDefaulted())
+ Spaceships.push_back(FD);
+ }
+
+ // Look for members named 'operator<=>'.
+ DeclarationName Cmp = Ctx.DeclarationNames.getCXXOperatorName(OO_Spaceship);
+ for (NamedDecl *ND : RD->lookup(Cmp)) {
+ // Note that we could find a non-function here (either a function template
+ // or a using-declaration). Neither case results in an implicit
+ // 'operator=='.
+ if (auto *FD = dyn_cast<FunctionDecl>(ND))
+ if (FD->isExplicitlyDefaulted())
+ Spaceships.push_back(FD);
+ }
}
/// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared
@@ -8267,6 +9604,20 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
ClassDecl->needsOverloadResolutionForDestructor())
DeclareImplicitDestructor(ClassDecl);
}
+
+ // C++2a [class.compare.default]p3:
+ // If the member-specification does not explicitly declare any member or
+ // friend named operator==, an == operator function is declared implicitly
+ // for each defaulted three-way comparison operator function defined in the
+ // member-specification
+ // FIXME: Consider doing this lazily.
+ if (getLangOpts().CPlusPlus2a) {
+ llvm::SmallVector<FunctionDecl*, 4> DefaultedSpaceships;
+ findImplicitlyDeclaredEqualityComparisons(Context, ClassDecl,
+ DefaultedSpaceships);
+ for (auto *FD : DefaultedSpaceships)
+ DeclareImplicitEqualityComparison(ClassDecl, FD);
+ }
}
unsigned Sema::ActOnReenterTemplateScope(Scope *S, Decl *D) {
@@ -8478,7 +9829,7 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
// Rebuild the function type "R" without any type qualifiers (in
// case any of the errors above fired) and with "void" as the
// return type, since constructors don't have return types.
- const FunctionProtoType *Proto = R->getAs<FunctionProtoType>();
+ const FunctionProtoType *Proto = R->castAs<FunctionProtoType>();
if (Proto->getReturnType() == Context.VoidTy && !D.isInvalidType())
return R;
@@ -8676,7 +10027,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
if (!D.isInvalidType())
return R;
- const FunctionProtoType *Proto = R->getAs<FunctionProtoType>();
+ const FunctionProtoType *Proto = R->castAs<FunctionProtoType>();
FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
EPI.Variadic = false;
EPI.TypeQuals = Qualifiers();
@@ -8750,7 +10101,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
D.setInvalidType();
}
- const FunctionProtoType *Proto = R->getAs<FunctionProtoType>();
+ const auto *Proto = R->castAs<FunctionProtoType>();
// Make sure we don't have any parameters.
if (Proto->getNumParams() > 0) {
@@ -9334,22 +10685,37 @@ struct InvalidSTLDiagnoser {
} // namespace
QualType Sema::CheckComparisonCategoryType(ComparisonCategoryType Kind,
- SourceLocation Loc) {
+ SourceLocation Loc,
+ ComparisonCategoryUsage Usage) {
assert(getLangOpts().CPlusPlus &&
"Looking for comparison category type outside of C++.");
+ // Use an elaborated type for diagnostics which has a name containing the
+ // prepended 'std' namespace but not any inline namespace names.
+ auto TyForDiags = [&](ComparisonCategoryInfo *Info) {
+ auto *NNS =
+ NestedNameSpecifier::Create(Context, nullptr, getStdNamespace());
+ return Context.getElaboratedType(ETK_None, NNS, Info->getType());
+ };
+
// Check if we've already successfully checked the comparison category type
// before. If so, skip checking it again.
ComparisonCategoryInfo *Info = Context.CompCategories.lookupInfo(Kind);
- if (Info && FullyCheckedComparisonCategories[static_cast<unsigned>(Kind)])
+ if (Info && FullyCheckedComparisonCategories[static_cast<unsigned>(Kind)]) {
+ // The only thing we need to check is that the type has a reachable
+ // definition in the current context.
+ if (RequireCompleteType(Loc, TyForDiags(Info), diag::err_incomplete_type))
+ return QualType();
+
return Info->getType();
+ }
// If lookup failed
if (!Info) {
std::string NameForDiags = "std::";
NameForDiags += ComparisonCategories::getCategoryString(Kind);
Diag(Loc, diag::err_implied_comparison_category_type_not_found)
- << NameForDiags;
+ << NameForDiags << (int)Usage;
return QualType();
}
@@ -9361,18 +10727,10 @@ QualType Sema::CheckComparisonCategoryType(ComparisonCategoryType Kind,
if (Info->Record->hasDefinition())
Info->Record = Info->Record->getDefinition();
- // Use an elaborated type for diagnostics which has a name containing the
- // prepended 'std' namespace but not any inline namespace names.
- QualType TyForDiags = [&]() {
- auto *NNS =
- NestedNameSpecifier::Create(Context, nullptr, getStdNamespace());
- return Context.getElaboratedType(ETK_None, NNS, Info->getType());
- }();
-
- if (RequireCompleteType(Loc, TyForDiags, diag::err_incomplete_type))
+ if (RequireCompleteType(Loc, TyForDiags(Info), diag::err_incomplete_type))
return QualType();
- InvalidSTLDiagnoser UnsupportedSTLError{*this, Loc, TyForDiags};
+ InvalidSTLDiagnoser UnsupportedSTLError{*this, Loc, TyForDiags(Info)};
if (!Info->Record->isTriviallyCopyable())
return UnsupportedSTLError(USS_NonTrivial);
@@ -11070,25 +12428,6 @@ void SpecialMemberExceptionSpecInfo::visitSubobjectCall(
ExceptSpec.CalledDecl(getSubobjectLoc(Subobj), MD);
}
-namespace {
-/// RAII object to register a special member as being currently declared.
-struct ComputingExceptionSpec {
- Sema &S;
-
- ComputingExceptionSpec(Sema &S, CXXMethodDecl *MD, SourceLocation Loc)
- : S(S) {
- Sema::CodeSynthesisContext Ctx;
- Ctx.Kind = Sema::CodeSynthesisContext::ExceptionSpecEvaluation;
- Ctx.PointOfInstantiation = Loc;
- Ctx.Entity = MD;
- S.pushCodeSynthesisContext(Ctx);
- }
- ~ComputingExceptionSpec() {
- S.popCodeSynthesisContext();
- }
-};
-}
-
bool Sema::tryResolveExplicitSpecifier(ExplicitSpecifier &ExplicitSpec) {
llvm::APSInt Result;
ExprResult Converted = CheckConvertedConstantExpression(
@@ -11222,10 +12561,9 @@ void Sema::setupImplicitSpecialMemberType(CXXMethodDecl *SpecialMem,
// Build an exception specification pointing back at this constructor.
FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, SpecialMem);
- if (getLangOpts().OpenCLCPlusPlus) {
- // OpenCL: Implicitly defaulted special member are of the generic address
- // space.
- EPI.TypeQuals.addAddressSpace(LangAS::opencl_generic);
+ LangAS AS = getDefaultCXXMethodAddrSpace();
+ if (AS != LangAS::Default) {
+ EPI.TypeQuals.addAddressSpace(AS);
}
auto QT = Context.getFunctionType(ResultTy, Args, EPI);
@@ -11384,7 +12722,8 @@ Sema::findInheritingConstructor(SourceLocation Loc,
BaseCtor->getExplicitSpecifier(), /*isInline=*/true,
/*isImplicitlyDeclared=*/true,
Constexpr ? BaseCtor->getConstexprKind() : CSK_unspecified,
- InheritedConstructor(Shadow, BaseCtor));
+ InheritedConstructor(Shadow, BaseCtor),
+ BaseCtor->getTrailingRequiresClause());
if (Shadow->isInvalidDecl())
DerivedCtor->setInvalidDecl();
@@ -11635,7 +12974,7 @@ void Sema::ActOnFinishCXXMemberDecls() {
}
}
-void Sema::ActOnFinishCXXNonNestedClass(Decl *D) {
+void Sema::ActOnFinishCXXNonNestedClass() {
referenceDLLExportedClassMethods();
if (!DelayedDllExportMemberFunctions.empty()) {
@@ -11676,8 +13015,7 @@ void Sema::AdjustDestructorExceptionSpec(CXXDestructorDecl *Destructor) {
// A declaration of a destructor that does not have an exception-
// specification is implicitly considered to have the same exception-
// specification as an implicit declaration.
- const FunctionProtoType *DtorType = Destructor->getType()->
- getAs<FunctionProtoType>();
+ const auto *DtorType = Destructor->getType()->castAs<FunctionProtoType>();
if (DtorType->hasExceptionSpec())
return;
@@ -12135,8 +13473,9 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
return nullptr;
QualType ArgType = Context.getTypeDeclType(ClassDecl);
- if (Context.getLangOpts().OpenCLCPlusPlus)
- ArgType = Context.getAddrSpaceQualType(ArgType, LangAS::opencl_generic);
+ LangAS AS = getDefaultCXXMethodAddrSpace();
+ if (AS != LangAS::Default)
+ ArgType = Context.getAddrSpaceQualType(ArgType, AS);
QualType RetType = Context.getLValueReferenceType(ArgType);
bool Const = ClassDecl->implicitCopyAssignmentHasConstParam();
if (Const)
@@ -12237,11 +13576,12 @@ static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp) {
assert(UserDeclaredOperation);
}
- if (UserDeclaredOperation) {
+ if (UserDeclaredOperation && UserDeclaredOperation->isUserProvided()) {
S.Diag(UserDeclaredOperation->getLocation(),
- diag::warn_deprecated_copy_operation)
- << RD << /*copy assignment*/!isa<CXXConstructorDecl>(CopyOp)
- << /*destructor*/isa<CXXDestructorDecl>(UserDeclaredOperation);
+ isa<CXXDestructorDecl>(UserDeclaredOperation)
+ ? diag::warn_deprecated_copy_dtor_operation
+ : diag::warn_deprecated_copy_operation)
+ << RD << /*copy assignment*/ !isa<CXXConstructorDecl>(CopyOp);
}
}
@@ -12460,8 +13800,9 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
// constructor rules.
QualType ArgType = Context.getTypeDeclType(ClassDecl);
- if (Context.getLangOpts().OpenCLCPlusPlus)
- ArgType = Context.getAddrSpaceQualType(ArgType, LangAS::opencl_generic);
+ LangAS AS = getDefaultCXXMethodAddrSpace();
+ if (AS != LangAS::Default)
+ ArgType = Context.getAddrSpaceQualType(ArgType, AS);
QualType RetType = Context.getLValueReferenceType(ArgType);
ArgType = Context.getRValueReferenceType(ArgType);
@@ -12654,8 +13995,8 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
// The parameter for the "other" object, which we are move from.
ParmVarDecl *Other = MoveAssignOperator->getParamDecl(0);
- QualType OtherRefType = Other->getType()->
- getAs<RValueReferenceType>()->getPointeeType();
+ QualType OtherRefType =
+ Other->getType()->castAs<RValueReferenceType>()->getPointeeType();
// Our location for everything implicitly-generated.
SourceLocation Loc = MoveAssignOperator->getEndLoc().isValid()
@@ -12838,8 +14179,9 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
if (Const)
ArgType = ArgType.withConst();
- if (Context.getLangOpts().OpenCLCPlusPlus)
- ArgType = Context.getAddrSpaceQualType(ArgType, LangAS::opencl_generic);
+ LangAS AS = getDefaultCXXMethodAddrSpace();
+ if (AS != LangAS::Default)
+ ArgType = Context.getAddrSpaceQualType(ArgType, AS);
ArgType = Context.getLValueReferenceType(ArgType);
@@ -12970,8 +14312,9 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
QualType ClassType = Context.getTypeDeclType(ClassDecl);
QualType ArgType = ClassType;
- if (Context.getLangOpts().OpenCLCPlusPlus)
- ArgType = Context.getAddrSpaceQualType(ClassType, LangAS::opencl_generic);
+ LangAS AS = getDefaultCXXMethodAddrSpace();
+ if (AS != LangAS::Default)
+ ArgType = Context.getAddrSpaceQualType(ClassType, AS);
ArgType = Context.getRValueReferenceType(ArgType);
bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl,
@@ -13447,9 +14790,7 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
unsigned NumArgs = ArgsPtr.size();
Expr **Args = ArgsPtr.data();
- const FunctionProtoType *Proto
- = Constructor->getType()->getAs<FunctionProtoType>();
- assert(Proto && "Constructor without a prototype?");
+ const auto *Proto = Constructor->getType()->castAs<FunctionProtoType>();
unsigned NumParams = Proto->getNumParams();
// If too few arguments are available, we'll fill in the rest with defaults.
@@ -13512,7 +14853,7 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl,
unsigned DependentParamTypeDiag,
unsigned InvalidParamTypeDiag) {
QualType ResultType =
- FnDecl->getType()->getAs<FunctionType>()->getReturnType();
+ FnDecl->getType()->castAs<FunctionType>()->getReturnType();
// Check that the result type is not dependent.
if (ResultType->isDependentType())
@@ -13741,7 +15082,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// Overloaded operators other than operator() cannot be variadic.
if (Op != OO_Call &&
- FnDecl->getType()->getAs<FunctionProtoType>()->isVariadic()) {
+ FnDecl->getType()->castAs<FunctionProtoType>()->isVariadic()) {
return Diag(FnDecl->getLocation(), diag::err_operator_overload_variadic)
<< FnDecl->getDeclName();
}
@@ -14010,10 +15351,6 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc,
Language = LinkageSpecDecl::lang_c;
else if (Lang == "C++")
Language = LinkageSpecDecl::lang_cxx;
- else if (Lang == "C++11")
- Language = LinkageSpecDecl::lang_cxx_11;
- else if (Lang == "C++14")
- Language = LinkageSpecDecl::lang_cxx_14;
else {
Diag(LangStr->getExprLoc(), diag::err_language_linkage_spec_unknown)
<< LangStr->getSourceRange();
@@ -14291,8 +15628,16 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
std::string InnerCondDescription;
std::tie(InnerCond, InnerCondDescription) =
findFailedBooleanCondition(Converted.get());
- if (InnerCond && !isa<CXXBoolLiteralExpr>(InnerCond)
- && !isa<IntegerLiteral>(InnerCond)) {
+ if (InnerCond && isa<ConceptSpecializationExpr>(InnerCond)) {
+ // Drill down into concept specialization expressions to see why they
+ // weren't satisfied.
+ Diag(StaticAssertLoc, diag::err_static_assert_failed)
+ << !AssertMessage << Msg.str() << AssertExpr->getSourceRange();
+ ConstraintSatisfaction Satisfaction;
+ if (!CheckConstraintSatisfaction(InnerCond, Satisfaction))
+ DiagnoseUnsatisfiedConstraint(Satisfaction);
+ } else if (InnerCond && !isa<CXXBoolLiteralExpr>(InnerCond)
+ && !isa<IntegerLiteral>(InnerCond)) {
Diag(StaticAssertLoc, diag::err_static_assert_requirement_failed)
<< InnerCondDescription << !AssertMessage
<< Msg.str() << InnerCond->getSourceRange();
@@ -14974,6 +16319,16 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
if (Fn->isDeleted())
return;
+ // C++11 [basic.start.main]p3:
+ // A program that defines main as deleted [...] is ill-formed.
+ if (Fn->isMain())
+ Diag(DelLoc, diag::err_deleted_main);
+
+ // C++11 [dcl.fct.def.delete]p4:
+ // A deleted function is implicitly inline.
+ Fn->setImplicitlyInline();
+ Fn->setDeletedAsWritten();
+
// See if we're deleting a function which is already known to override a
// non-deleted virtual function.
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn)) {
@@ -14990,67 +16345,93 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
// If this function was implicitly deleted because it was defaulted,
// explain why it was deleted.
if (IssuedDiagnostic && MD->isDefaulted())
- ShouldDeleteSpecialMember(MD, getSpecialMember(MD), nullptr,
- /*Diagnose*/true);
+ DiagnoseDeletedDefaultedFunction(MD);
}
-
- // C++11 [basic.start.main]p3:
- // A program that defines main as deleted [...] is ill-formed.
- if (Fn->isMain())
- Diag(DelLoc, diag::err_deleted_main);
-
- // C++11 [dcl.fct.def.delete]p4:
- // A deleted function is implicitly inline.
- Fn->setImplicitlyInline();
- Fn->setDeletedAsWritten();
}
void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
- CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(Dcl);
+ if (!Dcl || Dcl->isInvalidDecl())
+ return;
- if (MD) {
- if (MD->getParent()->isDependentType()) {
- MD->setDefaulted();
- MD->setExplicitlyDefaulted();
- return;
+ auto *FD = dyn_cast<FunctionDecl>(Dcl);
+ if (!FD) {
+ if (auto *FTD = dyn_cast<FunctionTemplateDecl>(Dcl)) {
+ if (getDefaultedFunctionKind(FTD->getTemplatedDecl()).isComparison()) {
+ Diag(DefaultLoc, diag::err_defaulted_comparison_template);
+ return;
+ }
}
- CXXSpecialMember Member = getSpecialMember(MD);
- if (Member == CXXInvalid) {
- if (!MD->isInvalidDecl())
- Diag(DefaultLoc, diag::err_default_special_members);
- return;
- }
+ Diag(DefaultLoc, diag::err_default_special_members)
+ << getLangOpts().CPlusPlus2a;
+ return;
+ }
+
+ // Reject if this can't possibly be a defaultable function.
+ DefaultedFunctionKind DefKind = getDefaultedFunctionKind(FD);
+ if (!DefKind &&
+ // A dependent function that doesn't locally look defaultable can
+ // still instantiate to a defaultable function if it's a constructor
+ // or assignment operator.
+ (!FD->isDependentContext() ||
+ (!isa<CXXConstructorDecl>(FD) &&
+ FD->getDeclName().getCXXOverloadedOperator() != OO_Equal))) {
+ Diag(DefaultLoc, diag::err_default_special_members)
+ << getLangOpts().CPlusPlus2a;
+ return;
+ }
+
+ if (DefKind.isComparison() &&
+ !isa<CXXRecordDecl>(FD->getLexicalDeclContext())) {
+ Diag(FD->getLocation(), diag::err_defaulted_comparison_out_of_class)
+ << (int)DefKind.asComparison();
+ return;
+ }
- MD->setDefaulted();
- MD->setExplicitlyDefaulted();
+ // Issue compatibility warning. We already warned if the operator is
+ // 'operator<=>' when parsing the '<=>' token.
+ if (DefKind.isComparison() &&
+ DefKind.asComparison() != DefaultedComparisonKind::ThreeWay) {
+ Diag(DefaultLoc, getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_defaulted_comparison
+ : diag::ext_defaulted_comparison);
+ }
- // Unset that we will have a body for this function. We might not,
- // if it turns out to be trivial, and we don't need this marking now
- // that we've marked it as defaulted.
- MD->setWillHaveBody(false);
+ FD->setDefaulted();
+ FD->setExplicitlyDefaulted();
- // If this definition appears within the record, do the checking when
- // the record is complete.
- const FunctionDecl *Primary = MD;
- if (const FunctionDecl *Pattern = MD->getTemplateInstantiationPattern())
- // Ask the template instantiation pattern that actually had the
- // '= default' on it.
- Primary = Pattern;
+ // Defer checking functions that are defaulted in a dependent context.
+ if (FD->isDependentContext())
+ return;
- // If the method was defaulted on its first declaration, we will have
- // already performed the checking in CheckCompletedCXXClass. Such a
- // declaration doesn't trigger an implicit definition.
- if (Primary->getCanonicalDecl()->isDefaulted())
- return;
+ // Unset that we will have a body for this function. We might not,
+ // if it turns out to be trivial, and we don't need this marking now
+ // that we've marked it as defaulted.
+ FD->setWillHaveBody(false);
- CheckExplicitlyDefaultedSpecialMember(MD);
+ // If this definition appears within the record, do the checking when
+ // the record is complete. This is always the case for a defaulted
+ // comparison.
+ if (DefKind.isComparison())
+ return;
+ auto *MD = cast<CXXMethodDecl>(FD);
- if (!MD->isInvalidDecl())
- DefineImplicitSpecialMember(*this, MD, DefaultLoc);
- } else {
- Diag(DefaultLoc, diag::err_default_special_members);
- }
+ const FunctionDecl *Primary = FD;
+ if (const FunctionDecl *Pattern = FD->getTemplateInstantiationPattern())
+ // Ask the template instantiation pattern that actually had the
+ // '= default' on it.
+ Primary = Pattern;
+
+ // If the method was defaulted on its first declaration, we will have
+ // already performed the checking in CheckCompletedCXXClass. Such a
+ // declaration doesn't trigger an implicit definition.
+ if (Primary->getCanonicalDecl()->isDefaulted())
+ return;
+
+ if (CheckExplicitlyDefaultedSpecialMember(MD, DefKind.asSpecialMember()))
+ MD->setInvalidDecl();
+ else
+ DefineImplicitSpecialMember(*this, MD, DefaultLoc);
}
static void SearchForReturnInStmt(Sema &Self, Stmt *S) {
@@ -15074,8 +16455,8 @@ void Sema::DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock) {
bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
- const auto *NewFT = New->getType()->getAs<FunctionProtoType>();
- const auto *OldFT = Old->getType()->getAs<FunctionProtoType>();
+ const auto *NewFT = New->getType()->castAs<FunctionProtoType>();
+ const auto *OldFT = Old->getType()->castAs<FunctionProtoType>();
if (OldFT->hasExtParameterInfos()) {
for (unsigned I = 0, E = OldFT->getNumParams(); I != E; ++I)
@@ -15122,8 +16503,8 @@ bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
- QualType NewTy = New->getType()->getAs<FunctionType>()->getReturnType();
- QualType OldTy = Old->getType()->getAs<FunctionType>()->getReturnType();
+ QualType NewTy = New->getType()->castAs<FunctionType>()->getReturnType();
+ QualType OldTy = Old->getType()->castAs<FunctionType>()->getReturnType();
if (Context.hasSameType(NewTy, OldTy) ||
NewTy->isDependentType() || OldTy->isDependentType())
@@ -15729,6 +17110,11 @@ bool Sema::checkThisInStaticMemberFunctionType(CXXMethodDecl *Method) {
if (checkThisInStaticMemberFunctionExceptionSpec(Method))
return true;
+ // Check the trailing requires clause
+ if (Expr *E = Method->getTrailingRequiresClause())
+ if (!Finder.TraverseStmt(E))
+ return true;
+
return checkThisInStaticMemberFunctionAttributes(Method);
}
diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp
index db594bbd21dd..5fdf6aeed5b4 100644
--- a/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/clang/lib/Sema/SemaDeclObjC.cpp
@@ -2828,6 +2828,9 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
"Expected to find the method through lookup as well");
// ImpMethodDecl may be null as in a @dynamic property.
if (ImpMethodDecl) {
+ // Skip property accessor function stubs.
+ if (ImpMethodDecl->isSynthesizedAccessorStub())
+ continue;
if (!WarnCategoryMethodImpl)
WarnConflictingTypedMethods(ImpMethodDecl, I,
isa<ObjCProtocolDecl>(CDecl));
@@ -2854,6 +2857,9 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
"Expected to find the method through lookup as well");
// ImpMethodDecl may be null as in a @dynamic property.
if (ImpMethodDecl) {
+ // Skip property accessor function stubs.
+ if (ImpMethodDecl->isSynthesizedAccessorStub())
+ continue;
if (!WarnCategoryMethodImpl)
WarnConflictingTypedMethods(ImpMethodDecl, I,
isa<ObjCProtocolDecl>(CDecl));
@@ -3233,6 +3239,9 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left,
if (left->isHidden() || right->isHidden())
return false;
+ if (left->isDirectMethod() != right->isDirectMethod())
+ return false;
+
if (getLangOpts().ObjCAutoRefCount &&
(left->hasAttr<NSReturnsRetainedAttr>()
!= right->hasAttr<NSReturnsRetainedAttr>() ||
@@ -3424,6 +3433,9 @@ static bool isAcceptableMethodMismatch(ObjCMethodDecl *chosen,
if (!chosen->isInstanceMethod())
return false;
+ if (chosen->isDirectMethod() != other->isDirectMethod())
+ return false;
+
Selector sel = chosen->getSelector();
if (!sel.isUnarySelector() || sel.getNameForSlot(0) != "length")
return false;
@@ -3903,6 +3915,25 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
|| isa<ObjCProtocolDecl>(ClassDecl);
bool checkIdenticalMethods = isa<ObjCImplementationDecl>(ClassDecl);
+ // Make synthesized accessor stub functions visible.
+ // ActOnPropertyImplDecl() creates them as not visible in case
+ // they are overridden by an explicit method that is encountered
+ // later.
+ if (auto *OID = dyn_cast<ObjCImplementationDecl>(CurContext)) {
+ for (auto PropImpl : OID->property_impls()) {
+ if (auto *Getter = PropImpl->getGetterMethodDecl())
+ if (Getter->isSynthesizedAccessorStub()) {
+ OID->makeDeclVisibleInContext(Getter);
+ OID->addDecl(Getter);
+ }
+ if (auto *Setter = PropImpl->getSetterMethodDecl())
+ if (Setter->isSynthesizedAccessorStub()) {
+ OID->makeDeclVisibleInContext(Setter);
+ OID->addDecl(Setter);
+ }
+ }
+ }
+
// FIXME: Remove these and use the ObjCContainerDecl/DeclContext.
llvm::DenseMap<Selector, const ObjCMethodDecl*> InsMap;
llvm::DenseMap<Selector, const ObjCMethodDecl*> ClsMap;
@@ -4001,8 +4032,8 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
continue;
for (const auto *Ext : IDecl->visible_extensions()) {
- if (ObjCMethodDecl *GetterMethod
- = Ext->getInstanceMethod(Property->getGetterName()))
+ if (ObjCMethodDecl *GetterMethod =
+ Ext->getInstanceMethod(Property->getGetterName()))
GetterMethod->setPropertyAccessor(true);
if (!Property->isReadOnly())
if (ObjCMethodDecl *SetterMethod
@@ -4314,6 +4345,18 @@ private:
};
} // end anonymous namespace
+void Sema::CheckObjCMethodDirectOverrides(ObjCMethodDecl *method,
+ ObjCMethodDecl *overridden) {
+ if (const auto *attr = overridden->getAttr<ObjCDirectAttr>()) {
+ Diag(method->getLocation(), diag::err_objc_override_direct_method);
+ Diag(attr->getLocation(), diag::note_previous_declaration);
+ } else if (const auto *attr = method->getAttr<ObjCDirectAttr>()) {
+ Diag(attr->getLocation(), diag::err_objc_direct_on_override)
+ << isa<ObjCProtocolDecl>(overridden->getDeclContext());
+ Diag(overridden->getLocation(), diag::note_previous_declaration);
+ }
+}
+
void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,
ObjCInterfaceDecl *CurrentClass,
ResultTypeCompatibilityKind RTC) {
@@ -4332,8 +4375,8 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,
if (isa<ObjCProtocolDecl>(overridden->getDeclContext()) ||
CurrentClass != overridden->getClassInterface() ||
overridden->isOverriding()) {
+ CheckObjCMethodDirectOverrides(ObjCMethod, overridden);
hasOverriddenMethodsInBaseOrProtocol = true;
-
} else if (isa<ObjCImplDecl>(ObjCMethod->getDeclContext())) {
// OverrideSearch will return as "overridden" the same method in the
// interface. For hasOverriddenMethodsInBaseOrProtocol, we need to
@@ -4357,6 +4400,7 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,
for (ObjCMethodDecl *SuperOverridden : overrides) {
if (isa<ObjCProtocolDecl>(SuperOverridden->getDeclContext()) ||
CurrentClass != SuperOverridden->getClassInterface()) {
+ CheckObjCMethodDirectOverrides(ObjCMethod, SuperOverridden);
hasOverriddenMethodsInBaseOrProtocol = true;
overridden->setOverriding(true);
break;
@@ -4551,6 +4595,7 @@ Decl *Sema::ActOnMethodDeclaration(
Diag(MethodLoc, diag::err_missing_method_context);
return nullptr;
}
+
Decl *ClassDecl = cast<ObjCContainerDecl>(CurContext);
QualType resultDeclType;
@@ -4574,7 +4619,7 @@ Decl *Sema::ActOnMethodDeclaration(
ObjCMethodDecl *ObjCMethod = ObjCMethodDecl::Create(
Context, MethodLoc, EndLoc, Sel, resultDeclType, ReturnTInfo, CurContext,
MethodType == tok::minus, isVariadic,
- /*isPropertyAccessor=*/false,
+ /*isPropertyAccessor=*/false, /*isSynthesizedAccessorStub=*/false,
/*isImplicitlyDeclared=*/false, /*isDefined=*/false,
MethodDeclKind == tok::objc_optional ? ObjCMethodDecl::Optional
: ObjCMethodDecl::Required,
@@ -4666,6 +4711,41 @@ Decl *Sema::ActOnMethodDeclaration(
ImpDecl->addClassMethod(ObjCMethod);
}
+ // If this method overrides a previous @synthesize declaration,
+ // register it with the property. Linear search through all
+ // properties here, because the autosynthesized stub hasn't been
+ // made visible yet, so it can be overriden by a later
+ // user-specified implementation.
+ for (ObjCPropertyImplDecl *PropertyImpl : ImpDecl->property_impls()) {
+ if (auto *Setter = PropertyImpl->getSetterMethodDecl())
+ if (Setter->getSelector() == Sel &&
+ Setter->isInstanceMethod() == ObjCMethod->isInstanceMethod()) {
+ assert(Setter->isSynthesizedAccessorStub() && "autosynth stub expected");
+ PropertyImpl->setSetterMethodDecl(ObjCMethod);
+ }
+ if (auto *Getter = PropertyImpl->getGetterMethodDecl())
+ if (Getter->getSelector() == Sel &&
+ Getter->isInstanceMethod() == ObjCMethod->isInstanceMethod()) {
+ assert(Getter->isSynthesizedAccessorStub() && "autosynth stub expected");
+ PropertyImpl->setGetterMethodDecl(ObjCMethod);
+ break;
+ }
+ }
+
+ // A method is either tagged direct explicitly, or inherits it from its
+ // canonical declaration.
+ //
+ // We have to do the merge upfront and not in mergeInterfaceMethodToImpl()
+ // because IDecl->lookupMethod() returns more possible matches than just
+ // the canonical declaration.
+ if (!ObjCMethod->isDirectMethod()) {
+ const ObjCMethodDecl *CanonicalMD = ObjCMethod->getCanonicalDecl();
+ if (const auto *attr = CanonicalMD->getAttr<ObjCDirectAttr>()) {
+ ObjCMethod->addAttr(
+ ObjCDirectAttr::CreateImplicit(Context, attr->getLocation()));
+ }
+ }
+
// Merge information from the @interface declaration into the
// @implementation.
if (ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface()) {
@@ -4673,12 +4753,64 @@ Decl *Sema::ActOnMethodDeclaration(
ObjCMethod->isInstanceMethod())) {
mergeInterfaceMethodToImpl(*this, ObjCMethod, IMD);
+ // The Idecl->lookupMethod() above will find declarations for ObjCMethod
+ // in one of these places:
+ //
+ // (1) the canonical declaration in an @interface container paired
+ // with the ImplDecl,
+ // (2) non canonical declarations in @interface not paired with the
+ // ImplDecl for the same Class,
+ // (3) any superclass container.
+ //
+ // Direct methods only allow for canonical declarations in the matching
+ // container (case 1).
+ //
+ // Direct methods overriding a superclass declaration (case 3) is
+ // handled during overrides checks in CheckObjCMethodOverrides().
+ //
+ // We deal with same-class container mismatches (Case 2) here.
+ if (IDecl == IMD->getClassInterface()) {
+ auto diagContainerMismatch = [&] {
+ int decl = 0, impl = 0;
+
+ if (auto *Cat = dyn_cast<ObjCCategoryDecl>(IMD->getDeclContext()))
+ decl = Cat->IsClassExtension() ? 1 : 2;
+
+ if (isa<ObjCCategoryImplDecl>(ImpDecl))
+ impl = 1 + (decl != 0);
+
+ Diag(ObjCMethod->getLocation(),
+ diag::err_objc_direct_impl_decl_mismatch)
+ << decl << impl;
+ Diag(IMD->getLocation(), diag::note_previous_declaration);
+ };
+
+ if (const auto *attr = ObjCMethod->getAttr<ObjCDirectAttr>()) {
+ if (ObjCMethod->getCanonicalDecl() != IMD) {
+ diagContainerMismatch();
+ } else if (!IMD->isDirectMethod()) {
+ Diag(attr->getLocation(), diag::err_objc_direct_missing_on_decl);
+ Diag(IMD->getLocation(), diag::note_previous_declaration);
+ }
+ } else if (const auto *attr = IMD->getAttr<ObjCDirectAttr>()) {
+ if (ObjCMethod->getCanonicalDecl() != IMD) {
+ diagContainerMismatch();
+ } else {
+ ObjCMethod->addAttr(
+ ObjCDirectAttr::CreateImplicit(Context, attr->getLocation()));
+ }
+ }
+ }
+
// Warn about defining -dealloc in a category.
if (isa<ObjCCategoryImplDecl>(ImpDecl) && IMD->isOverriding() &&
ObjCMethod->getSelector().getMethodFamily() == OMF_dealloc) {
Diag(ObjCMethod->getLocation(), diag::warn_dealloc_in_category)
<< ObjCMethod->getDeclName();
}
+ } else if (ImpDecl->hasAttr<ObjCDirectMembersAttr>()) {
+ ObjCMethod->addAttr(
+ ObjCDirectAttr::CreateImplicit(Context, ObjCMethod->getLocation()));
}
// Warn if a method declared in a protocol to which a category or
@@ -4698,6 +4830,42 @@ Decl *Sema::ActOnMethodDeclaration(
}
}
} else {
+ if (!isa<ObjCProtocolDecl>(ClassDecl)) {
+ if (!ObjCMethod->isDirectMethod() &&
+ ClassDecl->hasAttr<ObjCDirectMembersAttr>()) {
+ ObjCMethod->addAttr(
+ ObjCDirectAttr::CreateImplicit(Context, ObjCMethod->getLocation()));
+ }
+
+ // There can be a single declaration in any @interface container
+ // for a given direct method, look for clashes as we add them.
+ //
+ // For valid code, we should always know the primary interface
+ // declaration by now, however for invalid code we'll keep parsing
+ // but we won't find the primary interface and IDecl will be nil.
+ ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl);
+ if (!IDecl)
+ IDecl = cast<ObjCCategoryDecl>(ClassDecl)->getClassInterface();
+
+ if (IDecl)
+ if (auto *IMD = IDecl->lookupMethod(ObjCMethod->getSelector(),
+ ObjCMethod->isInstanceMethod(),
+ /*shallowCategoryLookup=*/false,
+ /*followSuper=*/false)) {
+ if (isa<ObjCProtocolDecl>(IMD->getDeclContext())) {
+ // Do not emit a diagnostic for the Protocol case:
+ // diag::err_objc_direct_on_protocol has already been emitted
+ // during parsing for these with a nicer diagnostic.
+ } else if (ObjCMethod->isDirectMethod() || IMD->isDirectMethod()) {
+ Diag(ObjCMethod->getLocation(),
+ diag::err_objc_direct_duplicate_decl)
+ << ObjCMethod->isDirectMethod() << IMD->isDirectMethod()
+ << ObjCMethod->getDeclName();
+ Diag(IMD->getLocation(), diag::note_previous_declaration);
+ }
+ }
+ }
+
cast<DeclContext>(ClassDecl)->addDecl(ObjCMethod);
}
@@ -4783,6 +4951,9 @@ Decl *Sema::ActOnMethodDeclaration(
}
}
+ // Insert the invisible arguments, self and _cmd!
+ ObjCMethod->createImplicitParams(Context, ObjCMethod->getClassInterface());
+
ActOnDocumentableDecl(ObjCMethod);
return ObjCMethod;
@@ -5063,6 +5234,9 @@ void Sema::DiagnoseUnusedBackingIvarInAccessor(Scope *S,
if (!IV)
continue;
+ if (CurMethod->isSynthesizedAccessorStub())
+ continue;
+
UnusedBackingIvarChecker Checker(*this, CurMethod, IV);
Checker.TraverseStmt(CurMethod->getBody());
if (Checker.AccessedIvar)
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index c1abf099e9f2..5aedbe7644e4 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/StmtObjC.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
@@ -80,8 +81,16 @@ ExprResult Sema::ActOnNoexceptSpec(SourceLocation NoexceptLoc,
ExceptionSpecificationType &EST) {
// FIXME: This is bogus, a noexcept expression is not a condition.
ExprResult Converted = CheckBooleanCondition(NoexceptLoc, NoexceptExpr);
- if (Converted.isInvalid())
- return Converted;
+ if (Converted.isInvalid()) {
+ EST = EST_NoexceptFalse;
+
+ // Fill in an expression of 'false' as a fixup.
+ auto *BoolExpr = new (Context)
+ CXXBoolLiteralExpr(false, Context.BoolTy, NoexceptExpr->getBeginLoc());
+ llvm::APSInt Value{1};
+ Value = 0;
+ return ConstantExpr::Create(Context, BoolExpr, APValue{Value});
+ }
if (Converted.get()->isValueDependent()) {
EST = EST_DependentNoexcept;
@@ -204,7 +213,7 @@ Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
// Compute or instantiate the exception specification now.
if (SourceFPT->getExceptionSpecType() == EST_Unevaluated)
- EvaluateImplicitExceptionSpec(Loc, cast<CXXMethodDecl>(SourceDecl));
+ EvaluateImplicitExceptionSpec(Loc, SourceDecl);
else
InstantiateExceptionSpec(Loc, SourceDecl);
@@ -970,17 +979,22 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
New->getLocation());
}
-static CanThrowResult canSubExprsThrow(Sema &S, const Expr *E) {
+static CanThrowResult canSubStmtsThrow(Sema &Self, const Stmt *S) {
CanThrowResult R = CT_Cannot;
- for (const Stmt *SubStmt : E->children()) {
- R = mergeCanThrow(R, S.canThrow(cast<Expr>(SubStmt)));
+ for (const Stmt *SubStmt : S->children()) {
+ if (!SubStmt)
+ continue;
+ R = mergeCanThrow(R, Self.canThrow(SubStmt));
if (R == CT_Can)
break;
}
return R;
}
-static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D) {
+/// Determine whether the callee of a particular function call can throw.
+/// E and D are both optional, but at least one of E and Loc must be specified.
+static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D,
+ SourceLocation Loc = SourceLocation()) {
// As an extension, we assume that __attribute__((nothrow)) functions don't
// throw.
if (D && isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())
@@ -989,7 +1003,7 @@ static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D) {
QualType T;
// In C++1z, just look at the function type of the callee.
- if (S.getLangOpts().CPlusPlus17 && isa<CallExpr>(E)) {
+ if (S.getLangOpts().CPlusPlus17 && E && isa<CallExpr>(E)) {
E = cast<CallExpr>(E)->getCallee();
T = E->getType();
if (T->isSpecificPlaceholderType(BuiltinType::BoundMember)) {
@@ -1026,13 +1040,41 @@ static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D) {
if (!FT)
return CT_Can;
- FT = S.ResolveExceptionSpec(E->getBeginLoc(), FT);
+ FT = S.ResolveExceptionSpec(Loc.isInvalid() ? E->getBeginLoc() : Loc, FT);
if (!FT)
return CT_Can;
return FT->canThrow();
}
+static CanThrowResult canVarDeclThrow(Sema &Self, const VarDecl *VD) {
+ CanThrowResult CT = CT_Cannot;
+
+ // Initialization might throw.
+ if (!VD->isUsableInConstantExpressions(Self.Context))
+ if (const Expr *Init = VD->getInit())
+ CT = mergeCanThrow(CT, Self.canThrow(Init));
+
+ // Destructor might throw.
+ if (VD->needsDestruction(Self.Context) == QualType::DK_cxx_destructor) {
+ if (auto *RD =
+ VD->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) {
+ if (auto *Dtor = RD->getDestructor()) {
+ CT = mergeCanThrow(
+ CT, canCalleeThrow(Self, nullptr, Dtor, VD->getLocation()));
+ }
+ }
+ }
+
+ // If this is a decomposition declaration, bindings might throw.
+ if (auto *DD = dyn_cast<DecompositionDecl>(VD))
+ for (auto *B : DD->bindings())
+ if (auto *HD = B->getHoldingVar())
+ CT = mergeCanThrow(CT, canVarDeclThrow(Self, HD));
+
+ return CT;
+}
+
static CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) {
if (DC->isTypeDependent())
return CT_Dependent;
@@ -1067,13 +1109,13 @@ static CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) {
return CT_Can;
}
-CanThrowResult Sema::canThrow(const Expr *E) {
+CanThrowResult Sema::canThrow(const Stmt *S) {
// C++ [expr.unary.noexcept]p3:
// [Can throw] if in a potentially-evaluated context the expression would
// contain:
- switch (E->getStmtClass()) {
+ switch (S->getStmtClass()) {
case Expr::ConstantExprClass:
- return canThrow(cast<ConstantExpr>(E)->getSubExpr());
+ return canThrow(cast<ConstantExpr>(S)->getSubExpr());
case Expr::CXXThrowExprClass:
// - a potentially evaluated throw-expression
@@ -1082,16 +1124,20 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::CXXDynamicCastExprClass: {
// - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v),
// where T is a reference type, that requires a run-time check
- CanThrowResult CT = canDynamicCastThrow(cast<CXXDynamicCastExpr>(E));
+ auto *CE = cast<CXXDynamicCastExpr>(S);
+ // FIXME: Properly determine whether a variably-modified type can throw.
+ if (CE->getType()->isVariablyModifiedType())
+ return CT_Can;
+ CanThrowResult CT = canDynamicCastThrow(CE);
if (CT == CT_Can)
return CT;
- return mergeCanThrow(CT, canSubExprsThrow(*this, E));
+ return mergeCanThrow(CT, canSubStmtsThrow(*this, CE));
}
case Expr::CXXTypeidExprClass:
// - a potentially evaluated typeid expression applied to a glvalue
// expression whose type is a polymorphic class type
- return canTypeidThrow(*this, cast<CXXTypeidExpr>(E));
+ return canTypeidThrow(*this, cast<CXXTypeidExpr>(S));
// - a potentially evaluated call to a function, member function, function
// pointer, or member function pointer that does not have a non-throwing
@@ -1100,34 +1146,38 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::CXXMemberCallExprClass:
case Expr::CXXOperatorCallExprClass:
case Expr::UserDefinedLiteralClass: {
- const CallExpr *CE = cast<CallExpr>(E);
+ const CallExpr *CE = cast<CallExpr>(S);
CanThrowResult CT;
- if (E->isTypeDependent())
+ if (CE->isTypeDependent())
CT = CT_Dependent;
else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))
CT = CT_Cannot;
else
- CT = canCalleeThrow(*this, E, CE->getCalleeDecl());
+ CT = canCalleeThrow(*this, CE, CE->getCalleeDecl());
if (CT == CT_Can)
return CT;
- return mergeCanThrow(CT, canSubExprsThrow(*this, E));
+ return mergeCanThrow(CT, canSubStmtsThrow(*this, CE));
}
case Expr::CXXConstructExprClass:
case Expr::CXXTemporaryObjectExprClass: {
- CanThrowResult CT = canCalleeThrow(*this, E,
- cast<CXXConstructExpr>(E)->getConstructor());
+ auto *CE = cast<CXXConstructExpr>(S);
+ // FIXME: Properly determine whether a variably-modified type can throw.
+ if (CE->getType()->isVariablyModifiedType())
+ return CT_Can;
+ CanThrowResult CT = canCalleeThrow(*this, CE, CE->getConstructor());
if (CT == CT_Can)
return CT;
- return mergeCanThrow(CT, canSubExprsThrow(*this, E));
+ return mergeCanThrow(CT, canSubStmtsThrow(*this, CE));
}
- case Expr::CXXInheritedCtorInitExprClass:
- return canCalleeThrow(*this, E,
- cast<CXXInheritedCtorInitExpr>(E)->getConstructor());
+ case Expr::CXXInheritedCtorInitExprClass: {
+ auto *ICIE = cast<CXXInheritedCtorInitExpr>(S);
+ return canCalleeThrow(*this, ICIE, ICIE->getConstructor());
+ }
case Expr::LambdaExprClass: {
- const LambdaExpr *Lambda = cast<LambdaExpr>(E);
+ const LambdaExpr *Lambda = cast<LambdaExpr>(S);
CanThrowResult CT = CT_Cannot;
for (LambdaExpr::const_capture_init_iterator
Cap = Lambda->capture_init_begin(),
@@ -1138,43 +1188,56 @@ CanThrowResult Sema::canThrow(const Expr *E) {
}
case Expr::CXXNewExprClass: {
+ auto *NE = cast<CXXNewExpr>(S);
CanThrowResult CT;
- if (E->isTypeDependent())
+ if (NE->isTypeDependent())
CT = CT_Dependent;
else
- CT = canCalleeThrow(*this, E, cast<CXXNewExpr>(E)->getOperatorNew());
+ CT = canCalleeThrow(*this, NE, NE->getOperatorNew());
if (CT == CT_Can)
return CT;
- return mergeCanThrow(CT, canSubExprsThrow(*this, E));
+ return mergeCanThrow(CT, canSubStmtsThrow(*this, NE));
}
case Expr::CXXDeleteExprClass: {
+ auto *DE = cast<CXXDeleteExpr>(S);
CanThrowResult CT;
- QualType DTy = cast<CXXDeleteExpr>(E)->getDestroyedType();
+ QualType DTy = DE->getDestroyedType();
if (DTy.isNull() || DTy->isDependentType()) {
CT = CT_Dependent;
} else {
- CT = canCalleeThrow(*this, E,
- cast<CXXDeleteExpr>(E)->getOperatorDelete());
+ CT = canCalleeThrow(*this, DE, DE->getOperatorDelete());
if (const RecordType *RT = DTy->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
const CXXDestructorDecl *DD = RD->getDestructor();
if (DD)
- CT = mergeCanThrow(CT, canCalleeThrow(*this, E, DD));
+ CT = mergeCanThrow(CT, canCalleeThrow(*this, DE, DD));
}
if (CT == CT_Can)
return CT;
}
- return mergeCanThrow(CT, canSubExprsThrow(*this, E));
+ return mergeCanThrow(CT, canSubStmtsThrow(*this, DE));
}
case Expr::CXXBindTemporaryExprClass: {
+ auto *BTE = cast<CXXBindTemporaryExpr>(S);
// The bound temporary has to be destroyed again, which might throw.
- CanThrowResult CT = canCalleeThrow(*this, E,
- cast<CXXBindTemporaryExpr>(E)->getTemporary()->getDestructor());
+ CanThrowResult CT =
+ canCalleeThrow(*this, BTE, BTE->getTemporary()->getDestructor());
if (CT == CT_Can)
return CT;
- return mergeCanThrow(CT, canSubExprsThrow(*this, E));
+ return mergeCanThrow(CT, canSubStmtsThrow(*this, BTE));
+ }
+
+ case Expr::PseudoObjectExprClass: {
+ auto *POE = cast<PseudoObjectExpr>(S);
+ CanThrowResult CT = CT_Cannot;
+ for (const Expr *E : POE->semantics()) {
+ CT = mergeCanThrow(CT, canThrow(E));
+ if (CT == CT_Can)
+ break;
+ }
+ return CT;
}
// ObjC message sends are like function calls, but never have exception
@@ -1196,12 +1259,8 @@ CanThrowResult Sema::canThrow(const Expr *E) {
// Some are simple:
case Expr::CoawaitExprClass:
case Expr::ConditionalOperatorClass:
- case Expr::CompoundLiteralExprClass:
case Expr::CoyieldExprClass:
- case Expr::CXXConstCastExprClass:
- case Expr::CXXReinterpretCastExprClass:
case Expr::CXXRewrittenBinaryOperatorClass:
- case Expr::BuiltinBitCastExprClass:
case Expr::CXXStdInitializerListExprClass:
case Expr::DesignatedInitExprClass:
case Expr::DesignatedInitUpdateExprClass:
@@ -1215,9 +1274,19 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::ParenExprClass:
case Expr::ParenListExprClass:
case Expr::ShuffleVectorExprClass:
+ case Expr::StmtExprClass:
case Expr::ConvertVectorExprClass:
case Expr::VAArgExprClass:
- return canSubExprsThrow(*this, E);
+ return canSubStmtsThrow(*this, S);
+
+ case Expr::CompoundLiteralExprClass:
+ case Expr::CXXConstCastExprClass:
+ case Expr::CXXReinterpretCastExprClass:
+ case Expr::BuiltinBitCastExprClass:
+ // FIXME: Properly determine whether a variably-modified type can throw.
+ if (cast<Expr>(S)->getType()->isVariablyModifiedType())
+ return CT_Can;
+ return canSubStmtsThrow(*this, S);
// Some might be dependent for other reasons.
case Expr::ArraySubscriptExprClass:
@@ -1231,29 +1300,32 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::ImplicitCastExprClass:
case Expr::MaterializeTemporaryExprClass:
case Expr::UnaryOperatorClass: {
- CanThrowResult CT = E->isTypeDependent() ? CT_Dependent : CT_Cannot;
- return mergeCanThrow(CT, canSubExprsThrow(*this, E));
+ // FIXME: Properly determine whether a variably-modified type can throw.
+ if (auto *CE = dyn_cast<CastExpr>(S))
+ if (CE->getType()->isVariablyModifiedType())
+ return CT_Can;
+ CanThrowResult CT =
+ cast<Expr>(S)->isTypeDependent() ? CT_Dependent : CT_Cannot;
+ return mergeCanThrow(CT, canSubStmtsThrow(*this, S));
}
- // FIXME: We should handle StmtExpr, but that opens a MASSIVE can of worms.
- case Expr::StmtExprClass:
- return CT_Can;
-
case Expr::CXXDefaultArgExprClass:
- return canThrow(cast<CXXDefaultArgExpr>(E)->getExpr());
+ return canThrow(cast<CXXDefaultArgExpr>(S)->getExpr());
case Expr::CXXDefaultInitExprClass:
- return canThrow(cast<CXXDefaultInitExpr>(E)->getExpr());
+ return canThrow(cast<CXXDefaultInitExpr>(S)->getExpr());
- case Expr::ChooseExprClass:
- if (E->isTypeDependent() || E->isValueDependent())
+ case Expr::ChooseExprClass: {
+ auto *CE = cast<ChooseExpr>(S);
+ if (CE->isTypeDependent() || CE->isValueDependent())
return CT_Dependent;
- return canThrow(cast<ChooseExpr>(E)->getChosenSubExpr());
+ return canThrow(CE->getChosenSubExpr());
+ }
case Expr::GenericSelectionExprClass:
- if (cast<GenericSelectionExpr>(E)->isResultDependent())
+ if (cast<GenericSelectionExpr>(S)->isResultDependent())
return CT_Dependent;
- return canThrow(cast<GenericSelectionExpr>(E)->getResultExpr());
+ return canThrow(cast<GenericSelectionExpr>(S)->getResultExpr());
// Some expressions are always dependent.
case Expr::CXXDependentScopeMemberExprClass:
@@ -1274,7 +1346,6 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::ObjCAvailabilityCheckExprClass:
case Expr::OffsetOfExprClass:
case Expr::PackExpansionExprClass:
- case Expr::PseudoObjectExprClass:
case Expr::SubstNonTypeTemplateParmExprClass:
case Expr::SubstNonTypeTemplateParmPackExprClass:
case Expr::FunctionParmPackExprClass:
@@ -1282,7 +1353,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::UnresolvedLookupExprClass:
case Expr::UnresolvedMemberExprClass:
case Expr::TypoExprClass:
- // FIXME: Can any of the above throw? If so, when?
+ // FIXME: Many of the above can throw.
return CT_Cannot;
case Expr::AddrLabelExprClass:
@@ -1322,14 +1393,170 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::MSPropertySubscriptExprClass:
llvm_unreachable("Invalid class for expression");
-#define STMT(CLASS, PARENT) case Expr::CLASS##Class:
-#define STMT_RANGE(Base, First, Last)
-#define LAST_STMT_RANGE(BASE, FIRST, LAST)
-#define EXPR(CLASS, PARENT)
-#define ABSTRACT_STMT(STMT)
-#include "clang/AST/StmtNodes.inc"
- case Expr::NoStmtClass:
- llvm_unreachable("Invalid class for expression");
+ // Most statements can throw if any substatement can throw.
+ case Stmt::AttributedStmtClass:
+ case Stmt::BreakStmtClass:
+ case Stmt::CapturedStmtClass:
+ case Stmt::CaseStmtClass:
+ case Stmt::CompoundStmtClass:
+ case Stmt::ContinueStmtClass:
+ case Stmt::CoreturnStmtClass:
+ case Stmt::CoroutineBodyStmtClass:
+ case Stmt::CXXCatchStmtClass:
+ case Stmt::CXXForRangeStmtClass:
+ case Stmt::DefaultStmtClass:
+ case Stmt::DoStmtClass:
+ case Stmt::ForStmtClass:
+ case Stmt::GCCAsmStmtClass:
+ case Stmt::GotoStmtClass:
+ case Stmt::IndirectGotoStmtClass:
+ case Stmt::LabelStmtClass:
+ case Stmt::MSAsmStmtClass:
+ case Stmt::MSDependentExistsStmtClass:
+ case Stmt::NullStmtClass:
+ case Stmt::ObjCAtCatchStmtClass:
+ case Stmt::ObjCAtFinallyStmtClass:
+ case Stmt::ObjCAtSynchronizedStmtClass:
+ case Stmt::ObjCAutoreleasePoolStmtClass:
+ case Stmt::ObjCForCollectionStmtClass:
+ case Stmt::OMPAtomicDirectiveClass:
+ case Stmt::OMPBarrierDirectiveClass:
+ case Stmt::OMPCancelDirectiveClass:
+ case Stmt::OMPCancellationPointDirectiveClass:
+ case Stmt::OMPCriticalDirectiveClass:
+ case Stmt::OMPDistributeDirectiveClass:
+ case Stmt::OMPDistributeParallelForDirectiveClass:
+ case Stmt::OMPDistributeParallelForSimdDirectiveClass:
+ case Stmt::OMPDistributeSimdDirectiveClass:
+ case Stmt::OMPFlushDirectiveClass:
+ case Stmt::OMPForDirectiveClass:
+ case Stmt::OMPForSimdDirectiveClass:
+ case Stmt::OMPMasterDirectiveClass:
+ case Stmt::OMPMasterTaskLoopDirectiveClass:
+ case Stmt::OMPMasterTaskLoopSimdDirectiveClass:
+ case Stmt::OMPOrderedDirectiveClass:
+ case Stmt::OMPParallelDirectiveClass:
+ case Stmt::OMPParallelForDirectiveClass:
+ case Stmt::OMPParallelForSimdDirectiveClass:
+ case Stmt::OMPParallelMasterDirectiveClass:
+ case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
+ case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:
+ case Stmt::OMPParallelSectionsDirectiveClass:
+ case Stmt::OMPSectionDirectiveClass:
+ case Stmt::OMPSectionsDirectiveClass:
+ case Stmt::OMPSimdDirectiveClass:
+ case Stmt::OMPSingleDirectiveClass:
+ case Stmt::OMPTargetDataDirectiveClass:
+ case Stmt::OMPTargetDirectiveClass:
+ case Stmt::OMPTargetEnterDataDirectiveClass:
+ case Stmt::OMPTargetExitDataDirectiveClass:
+ case Stmt::OMPTargetParallelDirectiveClass:
+ case Stmt::OMPTargetParallelForDirectiveClass:
+ case Stmt::OMPTargetParallelForSimdDirectiveClass:
+ case Stmt::OMPTargetSimdDirectiveClass:
+ case Stmt::OMPTargetTeamsDirectiveClass:
+ case Stmt::OMPTargetTeamsDistributeDirectiveClass:
+ case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
+ case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
+ case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
+ case Stmt::OMPTargetUpdateDirectiveClass:
+ case Stmt::OMPTaskDirectiveClass:
+ case Stmt::OMPTaskgroupDirectiveClass:
+ case Stmt::OMPTaskLoopDirectiveClass:
+ case Stmt::OMPTaskLoopSimdDirectiveClass:
+ case Stmt::OMPTaskwaitDirectiveClass:
+ case Stmt::OMPTaskyieldDirectiveClass:
+ case Stmt::OMPTeamsDirectiveClass:
+ case Stmt::OMPTeamsDistributeDirectiveClass:
+ case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
+ case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
+ case Stmt::OMPTeamsDistributeSimdDirectiveClass:
+ case Stmt::ReturnStmtClass:
+ case Stmt::SEHExceptStmtClass:
+ case Stmt::SEHFinallyStmtClass:
+ case Stmt::SEHLeaveStmtClass:
+ case Stmt::SEHTryStmtClass:
+ case Stmt::SwitchStmtClass:
+ case Stmt::WhileStmtClass:
+ return canSubStmtsThrow(*this, S);
+
+ case Stmt::DeclStmtClass: {
+ CanThrowResult CT = CT_Cannot;
+ for (const Decl *D : cast<DeclStmt>(S)->decls()) {
+ if (auto *VD = dyn_cast<VarDecl>(D))
+ CT = mergeCanThrow(CT, canVarDeclThrow(*this, VD));
+
+ // FIXME: Properly determine whether a variably-modified type can throw.
+ if (auto *TND = dyn_cast<TypedefNameDecl>(D))
+ if (TND->getUnderlyingType()->isVariablyModifiedType())
+ return CT_Can;
+ if (auto *VD = dyn_cast<ValueDecl>(D))
+ if (VD->getType()->isVariablyModifiedType())
+ return CT_Can;
+ }
+ return CT;
+ }
+
+ case Stmt::IfStmtClass: {
+ auto *IS = cast<IfStmt>(S);
+ CanThrowResult CT = CT_Cannot;
+ if (const Stmt *Init = IS->getInit())
+ CT = mergeCanThrow(CT, canThrow(Init));
+ if (const Stmt *CondDS = IS->getConditionVariableDeclStmt())
+ CT = mergeCanThrow(CT, canThrow(CondDS));
+ CT = mergeCanThrow(CT, canThrow(IS->getCond()));
+
+ // 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))
+ return *Case ? mergeCanThrow(CT, canThrow(*Case)) : CT;
+
+ CanThrowResult Then = canThrow(IS->getThen());
+ CanThrowResult Else = IS->getElse() ? canThrow(IS->getElse()) : CT_Cannot;
+ if (Then == Else)
+ return mergeCanThrow(CT, Then);
+
+ // For a dependent 'if constexpr', the result is dependent if it depends on
+ // the value of the condition.
+ return mergeCanThrow(CT, IS->isConstexpr() ? CT_Dependent
+ : mergeCanThrow(Then, Else));
+ }
+
+ case Stmt::CXXTryStmtClass: {
+ auto *TS = cast<CXXTryStmt>(S);
+ // try /*...*/ catch (...) { H } can throw only if H can throw.
+ // Any other try-catch can throw if any substatement can throw.
+ const CXXCatchStmt *FinalHandler = TS->getHandler(TS->getNumHandlers() - 1);
+ if (!FinalHandler->getExceptionDecl())
+ return canThrow(FinalHandler->getHandlerBlock());
+ return canSubStmtsThrow(*this, S);
+ }
+
+ case Stmt::ObjCAtThrowStmtClass:
+ return CT_Can;
+
+ case Stmt::ObjCAtTryStmtClass: {
+ auto *TS = cast<ObjCAtTryStmt>(S);
+
+ // @catch(...) need not be last in Objective-C. Walk backwards until we
+ // see one or hit the @try.
+ CanThrowResult CT = CT_Cannot;
+ if (const Stmt *Finally = TS->getFinallyStmt())
+ CT = mergeCanThrow(CT, canThrow(Finally));
+ for (unsigned I = TS->getNumCatchStmts(); I != 0; --I) {
+ const ObjCAtCatchStmt *Catch = TS->getCatchStmt(I - 1);
+ CT = mergeCanThrow(CT, canThrow(Catch));
+ // If we reach a @catch(...), no earlier exceptions can escape.
+ if (Catch->hasEllipsis())
+ return CT;
+ }
+
+ // Didn't find an @catch(...). Exceptions from the @try body can escape.
+ return mergeCanThrow(CT, canThrow(TS->getTryBody()));
+ }
+
+ case Stmt::NoStmtClass:
+ llvm_unreachable("Invalid class for statement");
}
llvm_unreachable("Bogus StmtClass");
}
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index e41cd5b6653a..5f4071924d3f 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -25,6 +25,7 @@
#include "clang/AST/ExprOpenMP.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TypeLoc.h"
+#include "clang/Basic/Builtins.h"
#include "clang/Basic/FixedPoint.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceManager.h"
@@ -97,21 +98,16 @@ static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) {
/// Emit a note explaining that this function is deleted.
void Sema::NoteDeletedFunction(FunctionDecl *Decl) {
- assert(Decl->isDeleted());
+ assert(Decl && Decl->isDeleted());
- CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Decl);
-
- if (Method && Method->isDeleted() && Method->isDefaulted()) {
+ if (Decl->isDefaulted()) {
// If the method was explicitly defaulted, point at that declaration.
- if (!Method->isImplicit())
+ if (!Decl->isImplicit())
Diag(Decl->getLocation(), diag::note_implicitly_deleted);
// Try to diagnose why this special member function was implicitly
// deleted. This might fail, if that reason no longer applies.
- CXXSpecialMember CSM = getSpecialMember(Method);
- if (CSM != CXXInvalid)
- ShouldDeleteSpecialMember(Method, CSM, nullptr, /*Diagnose=*/true);
-
+ DiagnoseDeletedDefaultedFunction(Decl);
return;
}
@@ -330,6 +326,30 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
diagnoseUseOfInternalDeclInInlineFunction(*this, D, Loc);
+ // [expr.prim.id]p4
+ // A program that refers explicitly or implicitly to a function with a
+ // trailing requires-clause whose constraint-expression is not satisfied,
+ // other than to declare it, is ill-formed. [...]
+ //
+ // See if this is a function with constraints that need to be satisfied.
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (Expr *RC = FD->getTrailingRequiresClause()) {
+ ConstraintSatisfaction Satisfaction;
+ bool Failed = CheckConstraintSatisfaction(RC, Satisfaction);
+ if (Failed)
+ // A diagnostic will have already been generated (non-constant
+ // constraint expression, for example)
+ return true;
+ if (!Satisfaction.IsSatisfied) {
+ Diag(Loc,
+ diag::err_reference_to_function_with_unsatisfied_constraints)
+ << D;
+ DiagnoseUnsatisfiedConstraint(Satisfaction);
+ return true;
+ }
+ }
+ }
+
return false;
}
@@ -481,16 +501,22 @@ static void CheckForNullPointerDereference(Sema &S, Expr *E) {
// optimizer will delete, so warn about it. People sometimes try to use this
// to get a deterministic trap and are surprised by clang's behavior. This
// only handles the pattern "*null", which is a very syntactic check.
- if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParenCasts()))
- if (UO->getOpcode() == UO_Deref &&
- UO->getSubExpr()->IgnoreParenCasts()->
- isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull) &&
+ const auto *UO = dyn_cast<UnaryOperator>(E->IgnoreParenCasts());
+ if (UO && UO->getOpcode() == UO_Deref &&
+ UO->getSubExpr()->getType()->isPointerType()) {
+ const LangAS AS =
+ UO->getSubExpr()->getType()->getPointeeType().getAddressSpace();
+ if ((!isTargetAddressSpace(AS) ||
+ (isTargetAddressSpace(AS) && toTargetAddressSpace(AS) == 0)) &&
+ UO->getSubExpr()->IgnoreParenCasts()->isNullPointerConstant(
+ S.Context, Expr::NPC_ValueDependentIsNotNull) &&
!UO->getType().isVolatileQualified()) {
- S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO,
- S.PDiag(diag::warn_indirection_through_null)
- << UO->getSubExpr()->getSourceRange());
- S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO,
- S.PDiag(diag::note_indirection_through_null));
+ S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO,
+ S.PDiag(diag::warn_indirection_through_null)
+ << UO->getSubExpr()->getSourceRange());
+ S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO,
+ S.PDiag(diag::note_indirection_through_null));
+ }
}
}
@@ -1331,13 +1357,72 @@ static QualType handleFixedPointConversion(Sema &S, QualType LHSTy,
return ResultTy;
}
+/// Check that the usual arithmetic conversions can be performed on this pair of
+/// expressions that might be of enumeration type.
+static void checkEnumArithmeticConversions(Sema &S, Expr *LHS, Expr *RHS,
+ SourceLocation Loc,
+ Sema::ArithConvKind ACK) {
+ // C++2a [expr.arith.conv]p1:
+ // If one operand is of enumeration type and the other operand is of a
+ // different enumeration type or a floating-point type, this behavior is
+ // deprecated ([depr.arith.conv.enum]).
+ //
+ // Warn on this in all language modes. Produce a deprecation warning in C++20.
+ // Eventually we will presumably reject these cases (in C++23 onwards?).
+ QualType L = LHS->getType(), R = RHS->getType();
+ bool LEnum = L->isUnscopedEnumerationType(),
+ REnum = R->isUnscopedEnumerationType();
+ bool IsCompAssign = ACK == Sema::ACK_CompAssign;
+ if ((!IsCompAssign && LEnum && R->isFloatingType()) ||
+ (REnum && L->isFloatingType())) {
+ S.Diag(Loc, S.getLangOpts().CPlusPlus2a
+ ? diag::warn_arith_conv_enum_float_cxx2a
+ : diag::warn_arith_conv_enum_float)
+ << LHS->getSourceRange() << RHS->getSourceRange()
+ << (int)ACK << LEnum << L << R;
+ } else if (!IsCompAssign && LEnum && REnum &&
+ !S.Context.hasSameUnqualifiedType(L, R)) {
+ unsigned DiagID;
+ if (!L->castAs<EnumType>()->getDecl()->hasNameForLinkage() ||
+ !R->castAs<EnumType>()->getDecl()->hasNameForLinkage()) {
+ // If either enumeration type is unnamed, it's less likely that the
+ // user cares about this, but this situation is still deprecated in
+ // C++2a. Use a different warning group.
+ DiagID = S.getLangOpts().CPlusPlus2a
+ ? diag::warn_arith_conv_mixed_anon_enum_types_cxx2a
+ : diag::warn_arith_conv_mixed_anon_enum_types;
+ } else if (ACK == Sema::ACK_Conditional) {
+ // Conditional expressions are separated out because they have
+ // historically had a different warning flag.
+ DiagID = S.getLangOpts().CPlusPlus2a
+ ? diag::warn_conditional_mixed_enum_types_cxx2a
+ : diag::warn_conditional_mixed_enum_types;
+ } else if (ACK == Sema::ACK_Comparison) {
+ // Comparison expressions are separated out because they have
+ // historically had a different warning flag.
+ DiagID = S.getLangOpts().CPlusPlus2a
+ ? diag::warn_comparison_mixed_enum_types_cxx2a
+ : diag::warn_comparison_mixed_enum_types;
+ } else {
+ DiagID = S.getLangOpts().CPlusPlus2a
+ ? diag::warn_arith_conv_mixed_enum_types_cxx2a
+ : diag::warn_arith_conv_mixed_enum_types;
+ }
+ S.Diag(Loc, DiagID) << LHS->getSourceRange() << RHS->getSourceRange()
+ << (int)ACK << L << R;
+ }
+}
+
/// UsualArithmeticConversions - Performs various conversions that are common to
/// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this
/// routine returns the first non-arithmetic type found. The client is
/// responsible for emitting appropriate error diagnostics.
QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
- bool IsCompAssign) {
- if (!IsCompAssign) {
+ SourceLocation Loc,
+ ArithConvKind ACK) {
+ checkEnumArithmeticConversions(*this, LHS.get(), RHS.get(), Loc, ACK);
+
+ if (ACK != ACK_CompAssign) {
LHS = UsualUnaryConversions(LHS.get());
if (LHS.isInvalid())
return QualType();
@@ -1374,7 +1459,7 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(LHS.get());
if (!LHSBitfieldPromoteTy.isNull())
LHSType = LHSBitfieldPromoteTy;
- if (LHSType != LHSUnpromotedType && !IsCompAssign)
+ if (LHSType != LHSUnpromotedType && ACK != ACK_CompAssign)
LHS = ImpCastExprToType(LHS.get(), LHSType, CK_IntegralCast);
// If both types are identical, no conversion is needed.
@@ -1391,24 +1476,24 @@ 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,
- IsCompAssign);
+ ACK == ACK_CompAssign);
// Now handle "real" floating types (i.e. float, double, long double).
if (LHSType->isRealFloatingType() || RHSType->isRealFloatingType())
return handleFloatConversion(*this, LHS, RHS, LHSType, RHSType,
- IsCompAssign);
+ ACK == ACK_CompAssign);
// Handle GCC complex int extension.
if (LHSType->isComplexIntegerType() || RHSType->isComplexIntegerType())
return handleComplexIntConversion(*this, LHS, RHS, LHSType, RHSType,
- IsCompAssign);
+ ACK == ACK_CompAssign);
if (LHSType->isFixedPointType() || RHSType->isFixedPointType())
return handleFixedPointConversion(*this, LHSType, RHSType);
// Finally, we have two differing integer types.
return handleIntegerConversion<doIntegralCast, doIntegralCast>
- (*this, LHS, RHS, LHSType, RHSType, IsCompAssign);
+ (*this, LHS, RHS, LHSType, RHSType, ACK == ACK_CompAssign);
}
//===----------------------------------------------------------------------===//
@@ -1825,6 +1910,25 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
VK, FoundD, TemplateArgs, getNonOdrUseReasonInCurrentContext(D));
MarkDeclRefReferenced(E);
+ // C++ [except.spec]p17:
+ // An exception-specification is considered to be needed when:
+ // - in an expression, the function is the unique lookup result or
+ // the selected member of a set of overloaded functions.
+ //
+ // We delay doing this until after we've built the function reference and
+ // marked it as used so that:
+ // a) if the function is defaulted, we get errors from defining it before /
+ // instead of errors from computing its exception specification, and
+ // b) if the function is a defaulted comparison, we can use the body we
+ // build when defining it as input to the exception specification
+ // computation rather than computing a new body.
+ if (auto *FPT = Ty->getAs<FunctionProtoType>()) {
+ if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
+ if (auto *NewFPT = ResolveExceptionSpec(NameInfo.getLoc(), FPT))
+ E->setType(Context.getQualifiedType(NewFPT, Ty.getQualifiers()));
+ }
+ }
+
if (getLangOpts().ObjCWeak && isa<VarDecl>(D) &&
Ty.getObjCLifetime() == Qualifiers::OCL_Weak && !isUnevaluatedContext() &&
!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, E->getBeginLoc()))
@@ -2704,6 +2808,20 @@ Sema::PerformObjectMemberConversion(Expr *From,
FromRecordType = FromType;
DestType = DestRecordType;
}
+
+ LangAS FromAS = FromRecordType.getAddressSpace();
+ LangAS DestAS = DestRecordType.getAddressSpace();
+ if (FromAS != DestAS) {
+ QualType FromRecordTypeWithoutAS =
+ Context.removeAddrSpaceQualType(FromRecordType);
+ QualType FromTypeWithDestAS =
+ Context.getAddrSpaceQualType(FromRecordTypeWithoutAS, DestAS);
+ if (PointerConversions)
+ FromTypeWithDestAS = Context.getPointerType(FromTypeWithDestAS);
+ From = ImpCastExprToType(From, FromTypeWithDestAS,
+ CK_AddressSpaceConversion, From->getValueKind())
+ .get();
+ }
} else {
// No conversion necessary.
return From;
@@ -2993,14 +3111,6 @@ ExprResult Sema::BuildDeclarationNameExpr(
QualType type = VD->getType();
if (type.isNull())
return ExprError();
- if (auto *FPT = type->getAs<FunctionProtoType>()) {
- // C++ [except.spec]p17:
- // An exception-specification is considered to be needed when:
- // - in an expression, the function is the unique lookup result or
- // the selected member of a set of overloaded functions.
- ResolveExceptionSpec(Loc, FPT);
- type = VD->getType();
- }
ExprValueKind valueKind = VK_RValue;
switch (D->getKind()) {
@@ -5231,6 +5341,9 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl,
for (Expr *A : Args.slice(ArgIx)) {
ExprResult Arg = DefaultVariadicArgumentPromotion(A, CallType, FDecl);
Invalid |= Arg.isInvalid();
+ // Copy blocks to the heap.
+ if (A->getType()->isBlockPointerType())
+ maybeExtendBlockObject(Arg);
AllArgs.push_back(Arg.get());
}
}
@@ -5424,15 +5537,15 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context,
Expr *Arg = ArgRes.get();
QualType ArgType = Arg->getType();
if (!ParamType->isPointerType() ||
- ParamType.getQualifiers().hasAddressSpace() ||
+ ParamType.hasAddressSpace() ||
!ArgType->isPointerType() ||
- !ArgType->getPointeeType().getQualifiers().hasAddressSpace()) {
+ !ArgType->getPointeeType().hasAddressSpace()) {
OverloadParams.push_back(ParamType);
continue;
}
QualType PointeeType = ParamType->getPointeeType();
- if (PointeeType.getQualifiers().hasAddressSpace())
+ if (PointeeType.hasAddressSpace())
continue;
NeedsNewDecl = true;
@@ -7363,7 +7476,8 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
/*AllowBothBool*/true,
/*AllowBoolConversions*/false);
- QualType ResTy = UsualArithmeticConversions(LHS, RHS);
+ QualType ResTy =
+ UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
@@ -7639,7 +7753,7 @@ static bool IsArithmeticBinaryExpr(Expr *E, BinaryOperatorKind *Opcode,
E = E->IgnoreConversionOperator();
E = E->IgnoreImpCasts();
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) {
- E = MTE->GetTemporaryExpr();
+ E = MTE->getSubExpr();
E = E->IgnoreImpCasts();
}
@@ -8695,7 +8809,7 @@ namespace {
struct OriginalOperand {
explicit OriginalOperand(Expr *Op) : Orig(Op), Conversion(nullptr) {
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Op))
- Op = MTE->GetTemporaryExpr();
+ Op = MTE->getSubExpr();
if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Op))
Op = BTE->getSubExpr();
if (auto *ICE = dyn_cast<ImplicitCastExpr>(Op)) {
@@ -8957,6 +9071,12 @@ static bool tryGCCVectorConvertAndSplat(Sema &S, ExprResult *Scalar,
return true;
ScalarCast = CK_IntegralCast;
+ } else if (VectorEltTy->isIntegralType(S.Context) &&
+ ScalarTy->isRealFloatingType()) {
+ if (S.Context.getTypeSize(VectorEltTy) == S.Context.getTypeSize(ScalarTy))
+ ScalarCast = CK_FloatingToIntegral;
+ else
+ return true;
} else if (VectorEltTy->isRealFloatingType()) {
if (ScalarTy->isRealFloatingType()) {
@@ -9276,7 +9396,8 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS,
/*AllowBothBool*/getLangOpts().AltiVec,
/*AllowBoolConversions*/false);
- QualType compType = UsualArithmeticConversions(LHS, RHS, IsCompAssign);
+ QualType compType = UsualArithmeticConversions(
+ LHS, RHS, Loc, IsCompAssign ? ACK_CompAssign : ACK_Arithmetic);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
@@ -9304,7 +9425,8 @@ QualType Sema::CheckRemainderOperands(
return InvalidOperands(Loc, LHS, RHS);
}
- QualType compType = UsualArithmeticConversions(LHS, RHS, IsCompAssign);
+ QualType compType = UsualArithmeticConversions(
+ LHS, RHS, Loc, IsCompAssign ? ACK_CompAssign : ACK_Arithmetic);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
@@ -9593,7 +9715,8 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS,
return compType;
}
- QualType compType = UsualArithmeticConversions(LHS, RHS, CompLHSTy);
+ QualType compType = UsualArithmeticConversions(
+ LHS, RHS, Loc, CompLHSTy ? ACK_CompAssign : ACK_Arithmetic);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
@@ -9687,7 +9810,8 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
return compType;
}
- QualType compType = UsualArithmeticConversions(LHS, RHS, CompLHSTy);
+ QualType compType = UsualArithmeticConversions(
+ LHS, RHS, Loc, CompLHSTy ? ACK_CompAssign : ACK_Arithmetic);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
@@ -10018,35 +10142,6 @@ QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS,
return LHSType;
}
-/// If two different enums are compared, raise a warning.
-static void checkEnumComparison(Sema &S, SourceLocation Loc, Expr *LHS,
- Expr *RHS) {
- QualType LHSStrippedType = LHS->IgnoreParenImpCasts()->getType();
- QualType RHSStrippedType = RHS->IgnoreParenImpCasts()->getType();
-
- const EnumType *LHSEnumType = LHSStrippedType->getAs<EnumType>();
- if (!LHSEnumType)
- return;
- const EnumType *RHSEnumType = RHSStrippedType->getAs<EnumType>();
- if (!RHSEnumType)
- return;
-
- // Ignore anonymous enums.
- if (!LHSEnumType->getDecl()->getIdentifier() &&
- !LHSEnumType->getDecl()->getTypedefNameForAnonDecl())
- return;
- if (!RHSEnumType->getDecl()->getIdentifier() &&
- !RHSEnumType->getDecl()->getTypedefNameForAnonDecl())
- return;
-
- if (S.Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType))
- return;
-
- S.Diag(Loc, diag::warn_comparison_of_mixed_enum_types)
- << LHSStrippedType << RHSStrippedType
- << LHS->getSourceRange() << RHS->getSourceRange();
-}
-
/// Diagnose bad pointer comparisons.
static void diagnoseDistinctPointerComparison(Sema &S, SourceLocation Loc,
ExprResult &LHS, ExprResult &RHS,
@@ -10085,8 +10180,6 @@ static bool convertPointersToCompositeType(Sema &S, SourceLocation Loc,
return true;
}
- LHS = S.ImpCastExprToType(LHS.get(), T, CK_BitCast);
- RHS = S.ImpCastExprToType(RHS.get(), T, CK_BitCast);
return false;
}
@@ -10317,7 +10410,6 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
QualType RHSType = RHS->getType();
if (LHSType->hasFloatingRepresentation() ||
(LHSType->isBlockPointerType() && !BinaryOperator::isEqualityOp(Opc)) ||
- LHS->getBeginLoc().isMacroID() || RHS->getBeginLoc().isMacroID() ||
S.inTemplateInstantiation())
return;
@@ -10345,45 +10437,64 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
AlwaysEqual, // std::strong_ordering::equal from operator<=>
};
- if (Expr::isSameComparisonOperand(LHS, RHS)) {
- unsigned Result;
- switch (Opc) {
- case BO_EQ: case BO_LE: case BO_GE:
- Result = AlwaysTrue;
- break;
- case BO_NE: case BO_LT: case BO_GT:
- Result = AlwaysFalse;
- break;
- case BO_Cmp:
- Result = AlwaysEqual;
- break;
- default:
- Result = AlwaysConstant;
- break;
- }
- S.DiagRuntimeBehavior(Loc, nullptr,
- S.PDiag(diag::warn_comparison_always)
- << 0 /*self-comparison*/
- << Result);
- } else if (checkForArray(LHSStripped) && checkForArray(RHSStripped)) {
- // What is it always going to evaluate to?
- unsigned Result;
- switch(Opc) {
- case BO_EQ: // e.g. array1 == array2
- Result = AlwaysFalse;
- break;
- case BO_NE: // e.g. array1 != array2
- Result = AlwaysTrue;
- break;
- default: // e.g. array1 <= array2
- // The best we can say is 'a constant'
- Result = AlwaysConstant;
- break;
+ // C++2a [depr.array.comp]:
+ // Equality and relational comparisons ([expr.eq], [expr.rel]) between two
+ // operands of array type are deprecated.
+ if (S.getLangOpts().CPlusPlus2a && LHSStripped->getType()->isArrayType() &&
+ RHSStripped->getType()->isArrayType()) {
+ S.Diag(Loc, diag::warn_depr_array_comparison)
+ << LHS->getSourceRange() << RHS->getSourceRange()
+ << LHSStripped->getType() << RHSStripped->getType();
+ // Carry on to produce the tautological comparison warning, if this
+ // expression is potentially-evaluated, we can resolve the array to a
+ // non-weak declaration, and so on.
+ }
+
+ if (!LHS->getBeginLoc().isMacroID() && !RHS->getBeginLoc().isMacroID()) {
+ if (Expr::isSameComparisonOperand(LHS, RHS)) {
+ unsigned Result;
+ switch (Opc) {
+ case BO_EQ:
+ case BO_LE:
+ case BO_GE:
+ Result = AlwaysTrue;
+ break;
+ case BO_NE:
+ case BO_LT:
+ case BO_GT:
+ Result = AlwaysFalse;
+ break;
+ case BO_Cmp:
+ Result = AlwaysEqual;
+ break;
+ default:
+ Result = AlwaysConstant;
+ break;
+ }
+ S.DiagRuntimeBehavior(Loc, nullptr,
+ S.PDiag(diag::warn_comparison_always)
+ << 0 /*self-comparison*/
+ << Result);
+ } else if (checkForArray(LHSStripped) && checkForArray(RHSStripped)) {
+ // What is it always going to evaluate to?
+ unsigned Result;
+ switch (Opc) {
+ case BO_EQ: // e.g. array1 == array2
+ Result = AlwaysFalse;
+ break;
+ case BO_NE: // e.g. array1 != array2
+ Result = AlwaysTrue;
+ break;
+ default: // e.g. array1 <= array2
+ // The best we can say is 'a constant'
+ Result = AlwaysConstant;
+ break;
+ }
+ S.DiagRuntimeBehavior(Loc, nullptr,
+ S.PDiag(diag::warn_comparison_always)
+ << 1 /*array comparison*/
+ << Result);
}
- S.DiagRuntimeBehavior(Loc, nullptr,
- S.PDiag(diag::warn_comparison_always)
- << 1 /*array comparison*/
- << Result);
}
if (isa<CastExpr>(LHSStripped))
@@ -10392,7 +10503,7 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
RHSStripped = RHSStripped->IgnoreParenCasts();
// Warn about comparisons against a string constant (unless the other
- // operand is null); the user probably wants strcmp.
+ // operand is null); the user probably wants string comparison function.
Expr *LiteralString = nullptr;
Expr *LiteralStringStripped = nullptr;
if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) &&
@@ -10500,8 +10611,6 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S,
ExprResult &LHS,
ExprResult &RHS,
SourceLocation Loc) {
- using CCT = ComparisonCategoryType;
-
QualType LHSType = LHS.get()->getType();
QualType RHSType = RHS.get()->getType();
// Dig out the original argument type and expression before implicit casts
@@ -10519,6 +10628,7 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S,
return QualType();
}
+ // FIXME: Consider combining this with checkEnumArithmeticConversions.
int NumEnumArgs = (int)LHSStrippedType->isEnumeralType() +
RHSStrippedType->isEnumeralType();
if (NumEnumArgs == 1) {
@@ -10554,12 +10664,17 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S,
// C++2a [expr.spaceship]p4: If both operands have arithmetic types, the
// usual arithmetic conversions are applied to the operands.
- QualType Type = S.UsualArithmeticConversions(LHS, RHS);
+ QualType Type =
+ S.UsualArithmeticConversions(LHS, RHS, Loc, Sema::ACK_Comparison);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
if (Type.isNull())
return S.InvalidOperands(Loc, LHS, RHS);
- assert(Type->isArithmeticType() || Type->isEnumeralType());
+
+ Optional<ComparisonCategoryType> CCT =
+ getComparisonCategoryForBuiltinCmp(Type);
+ if (!CCT)
+ return S.InvalidOperands(Loc, LHS, RHS);
bool HasNarrowing = checkThreeWayNarrowingConversion(
S, Type, LHS.get(), LHSType, LHS.get()->getBeginLoc());
@@ -10570,20 +10685,8 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S,
assert(!Type.isNull() && "composite type for <=> has not been set");
- auto TypeKind = [&]() {
- if (const ComplexType *CT = Type->getAs<ComplexType>()) {
- if (CT->getElementType()->hasFloatingRepresentation())
- return CCT::WeakEquality;
- return CCT::StrongEquality;
- }
- if (Type->isIntegralOrEnumerationType())
- return CCT::StrongOrdering;
- if (Type->hasFloatingRepresentation())
- return CCT::PartialOrdering;
- llvm_unreachable("other types are unimplemented");
- }();
-
- return S.CheckComparisonCategoryType(TypeKind, Loc);
+ return S.CheckComparisonCategoryType(
+ *CCT, Loc, Sema::ComparisonCategoryUsage::OperatorInExpression);
}
static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS,
@@ -10594,15 +10697,14 @@ static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS,
return checkArithmeticOrEnumeralThreeWayCompare(S, LHS, RHS, Loc);
// C99 6.5.8p3 / C99 6.5.9p4
- QualType Type = S.UsualArithmeticConversions(LHS, RHS);
+ QualType Type =
+ S.UsualArithmeticConversions(LHS, RHS, Loc, Sema::ACK_Comparison);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
if (Type.isNull())
return S.InvalidOperands(Loc, LHS, RHS);
assert(Type->isArithmeticType() || Type->isEnumeralType());
- checkEnumComparison(S, Loc, LHS.get(), RHS.get());
-
if (Type->isAnyComplexType() && BinaryOperator::isRelationalOp(Opc))
return S.InvalidOperands(Loc, LHS, RHS);
@@ -10646,6 +10748,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
BinaryOperatorKind Opc) {
bool IsRelational = BinaryOperator::isRelationalOp(Opc);
bool IsThreeWay = Opc == BO_Cmp;
+ bool IsOrdered = IsRelational || IsThreeWay;
auto IsAnyPointerType = [](ExprResult E) {
QualType Ty = E.get()->getType();
return Ty->isPointerType() || Ty->isMemberPointerType();
@@ -10708,36 +10811,26 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
QualType CompositeTy = LHS.get()->getType();
assert(!CompositeTy->isReferenceType());
- auto buildResultTy = [&](ComparisonCategoryType Kind) {
- return CheckComparisonCategoryType(Kind, Loc);
- };
-
- // C++2a [expr.spaceship]p7: If the composite pointer type is a function
- // pointer type, a pointer-to-member type, or std::nullptr_t, the
- // result is of type std::strong_equality
- if (CompositeTy->isFunctionPointerType() ||
- CompositeTy->isMemberPointerType() || CompositeTy->isNullPtrType())
- // FIXME: consider making the function pointer case produce
- // strong_ordering not strong_equality, per P0946R0-Jax18 discussion
- // and direction polls
- return buildResultTy(ComparisonCategoryType::StrongEquality);
+ Optional<ComparisonCategoryType> CCT =
+ getComparisonCategoryForBuiltinCmp(CompositeTy);
+ if (!CCT)
+ return InvalidOperands(Loc, LHS, RHS);
- // C++2a [expr.spaceship]p8: If the composite pointer type is an object
- // pointer type, p <=> q is of type std::strong_ordering.
- if (CompositeTy->isPointerType()) {
+ if (CompositeTy->isPointerType() && LHSIsNull != RHSIsNull) {
// P0946R0: Comparisons between a null pointer constant and an object
- // pointer result in std::strong_equality
- if (LHSIsNull != RHSIsNull)
- return buildResultTy(ComparisonCategoryType::StrongEquality);
- return buildResultTy(ComparisonCategoryType::StrongOrdering);
+ // pointer result in std::strong_equality, which is ill-formed under
+ // P1959R0.
+ Diag(Loc, diag::err_typecheck_three_way_comparison_of_pointer_and_zero)
+ << (LHSIsNull ? LHS.get()->getSourceRange()
+ : RHS.get()->getSourceRange());
+ return QualType();
}
- // C++2a [expr.spaceship]p9: Otherwise, the program is ill-formed.
- // TODO: Extend support for operator<=> to ObjC types.
- return InvalidOperands(Loc, LHS, RHS);
- };
+ return CheckComparisonCategoryType(
+ *CCT, Loc, ComparisonCategoryUsage::OperatorInExpression);
+ };
- if (!IsRelational && LHSIsNull != RHSIsNull) {
+ if (!IsOrdered && LHSIsNull != RHSIsNull) {
bool IsEquality = Opc == BO_EQ;
if (RHSIsNull)
DiagnoseAlwaysNonNullPointer(LHS.get(), RHSNullKind, IsEquality,
@@ -10756,7 +10849,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
// but we allow it as an extension.
// FIXME: If we really want to allow this, should it be part of composite
// pointer type computation so it works in conditionals too?
- if (!IsRelational &&
+ if (!IsOrdered &&
((LHSType->isFunctionPointerType() && RHSType->isVoidPointerType()) ||
(RHSType->isFunctionPointerType() && LHSType->isVoidPointerType()))) {
// This is a gcc extension compatibility comparison.
@@ -10781,8 +10874,11 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
// C++ [expr.rel]p2:
// If both operands are pointers, [...] bring them to their composite
// pointer type.
+ // For <=>, the only valid non-pointer types are arrays and functions, and
+ // we already decayed those, so this is really the same as the relational
+ // comparison rule.
if ((int)LHSType->isPointerType() + (int)RHSType->isPointerType() >=
- (IsRelational ? 2 : 1) &&
+ (IsOrdered ? 2 : 1) &&
(!LangOpts.ObjCAutoRefCount || !(LHSType->isObjCObjectPointerType() ||
RHSType->isObjCObjectPointerType()))) {
if (convertPointersToCompositeType(*this, Loc, LHS, RHS))
@@ -10845,7 +10941,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
// 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 (!IsRelational && LHSIsNull && RHSIsNull) {
+ if (!IsOrdered && LHSIsNull && RHSIsNull) {
if (LHSType->isNullPtrType()) {
RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
return computeResultTy();
@@ -10858,12 +10954,12 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
// Comparison of Objective-C pointers and block pointers against nullptr_t.
// These aren't covered by the composite pointer type rules.
- if (!IsRelational && RHSType->isNullPtrType() &&
+ if (!IsOrdered && RHSType->isNullPtrType() &&
(LHSType->isObjCObjectPointerType() || LHSType->isBlockPointerType())) {
RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
return computeResultTy();
}
- if (!IsRelational && LHSType->isNullPtrType() &&
+ if (!IsOrdered && LHSType->isNullPtrType() &&
(RHSType->isObjCObjectPointerType() || RHSType->isBlockPointerType())) {
LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer);
return computeResultTy();
@@ -10897,7 +10993,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
// C++ [expr.eq]p2:
// If at least one operand is a pointer to member, [...] bring them to
// their composite pointer type.
- if (!IsRelational &&
+ if (!IsOrdered &&
(LHSType->isMemberPointerType() || RHSType->isMemberPointerType())) {
if (convertPointersToCompositeType(*this, Loc, LHS, RHS))
return QualType();
@@ -10907,7 +11003,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
}
// Handle block pointer types.
- if (!IsRelational && LHSType->isBlockPointerType() &&
+ if (!IsOrdered && LHSType->isBlockPointerType() &&
RHSType->isBlockPointerType()) {
QualType lpointee = LHSType->castAs<BlockPointerType>()->getPointeeType();
QualType rpointee = RHSType->castAs<BlockPointerType>()->getPointeeType();
@@ -10923,7 +11019,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
}
// Allow block pointers to be compared with null pointer constants.
- if (!IsRelational
+ if (!IsOrdered
&& ((LHSType->isBlockPointerType() && RHSType->isPointerType())
|| (LHSType->isPointerType() && RHSType->isBlockPointerType()))) {
if (!LHSIsNull && !RHSIsNull) {
@@ -10959,6 +11055,9 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS,
/*isError*/false);
}
+ // FIXME: If LPtrToVoid, we should presumably convert the LHS rather than
+ // the RHS, but we have test coverage for this behavior.
+ // FIXME: Consider using convertPointersToCompositeType in C++.
if (LHSIsNull && !RHSIsNull) {
Expr *E = LHS.get();
if (getLangOpts().ObjCAutoRefCount)
@@ -10993,12 +11092,12 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
return computeResultTy();
}
- if (!IsRelational && LHSType->isBlockPointerType() &&
+ if (!IsOrdered && LHSType->isBlockPointerType() &&
RHSType->isBlockCompatibleObjCPointerType(Context)) {
LHS = ImpCastExprToType(LHS.get(), RHSType,
CK_BlockPointerToObjCPointerCast);
return computeResultTy();
- } else if (!IsRelational &&
+ } else if (!IsOrdered &&
LHSType->isBlockCompatibleObjCPointerType(Context) &&
RHSType->isBlockPointerType()) {
RHS = ImpCastExprToType(RHS.get(), LHSType,
@@ -11015,7 +11114,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
// since users tend to want to compare addresses.
} else if ((LHSIsNull && LHSType->isIntegerType()) ||
(RHSIsNull && RHSType->isIntegerType())) {
- if (IsRelational) {
+ if (IsOrdered) {
isError = getLangOpts().CPlusPlus;
DiagID =
isError ? diag::err_typecheck_ordered_comparison_of_pointer_and_zero
@@ -11024,7 +11123,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
} else if (getLangOpts().CPlusPlus) {
DiagID = diag::err_typecheck_comparison_of_pointer_integer;
isError = true;
- } else if (IsRelational)
+ } else if (IsOrdered)
DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_integer;
else
DiagID = diag::ext_typecheck_comparison_of_pointer_integer;
@@ -11047,12 +11146,12 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
}
// Handle block pointers.
- if (!IsRelational && RHSIsNull
+ if (!IsOrdered && RHSIsNull
&& LHSType->isBlockPointerType() && RHSType->isIntegerType()) {
RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
return computeResultTy();
}
- if (!IsRelational && LHSIsNull
+ if (!IsOrdered && LHSIsNull
&& LHSType->isIntegerType() && RHSType->isBlockPointerType()) {
LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer);
return computeResultTy();
@@ -11129,6 +11228,11 @@ QualType Sema::GetSignedVectorType(QualType V) {
QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc,
BinaryOperatorKind Opc) {
+ if (Opc == BO_Cmp) {
+ Diag(Loc, diag::err_three_way_vector_comparison);
+ return QualType();
+ }
+
// Check to make sure we're operating on vectors of the same type and width,
// Allowing one side to be a scalar of element type.
QualType vType = CheckVectorOperands(LHS, RHS, Loc, /*isCompAssign*/false,
@@ -11318,9 +11422,13 @@ inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS,
if (Opc == BO_And)
diagnoseLogicalNotOnLHSofCheck(*this, LHS, RHS, Loc, Opc);
+ if (LHS.get()->getType()->hasFloatingRepresentation() ||
+ RHS.get()->getType()->hasFloatingRepresentation())
+ return InvalidOperands(Loc, LHS, RHS);
+
ExprResult LHSResult = LHS, RHSResult = RHS;
- QualType compType = UsualArithmeticConversions(LHSResult, RHSResult,
- IsCompAssign);
+ QualType compType = UsualArithmeticConversions(
+ LHSResult, RHSResult, Loc, IsCompAssign ? ACK_CompAssign : ACK_BitwiseOp);
if (LHSResult.isInvalid() || RHSResult.isInvalid())
return QualType();
LHS = LHSResult.get();
@@ -13011,6 +13119,14 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
if (ResultTy.isNull() || LHS.isInvalid() || RHS.isInvalid())
return ExprError();
+ if (ResultTy->isRealFloatingType() &&
+ (getLangOpts().getFPRoundingMode() != LangOptions::FPR_ToNearest ||
+ getLangOpts().getFPExceptionMode() != LangOptions::FPE_Ignore))
+ // Mark the current function as usng floating point constrained intrinsics
+ if (FunctionDecl *F = dyn_cast<FunctionDecl>(CurContext)) {
+ F->setUsesFPIntrin(true);
+ }
+
// Some of the binary operations require promoting operands of half vector to
// float vectors and truncating the result back to half vector. For now, we do
// this only when HalfArgsAndReturn is set (that is, when the target is arm or
@@ -15268,8 +15384,7 @@ static bool funcHasParameterSizeMangling(Sema &S, FunctionDecl *FD) {
// These manglings don't do anything on non-Windows or non-x86 platforms, so
// we don't need parameter type sizes.
const llvm::Triple &TT = S.Context.getTargetInfo().getTriple();
- if (!TT.isOSWindows() || (TT.getArch() != llvm::Triple::x86 &&
- TT.getArch() != llvm::Triple::x86_64))
+ if (!TT.isOSWindows() || !TT.isX86())
return false;
// If this is C++ and this isn't an extern "C" function, parameters do not
@@ -15385,9 +15500,8 @@ static OdrUseContext isOdrUseContext(Sema &SemaRef) {
}
static bool isImplicitlyDefinableConstexprFunction(FunctionDecl *Func) {
- CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Func);
return Func->isConstexpr() &&
- (Func->isImplicitlyInstantiable() || (MD && !MD->isUserProvided()));
+ (Func->isImplicitlyInstantiable() || !Func->isUserProvided());
}
/// Mark a function referenced, and check whether it is odr-used
@@ -15467,19 +15581,6 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
Func->getMemberSpecializationInfo()))
checkSpecializationVisibility(Loc, Func);
- // 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,
- // would be odr-used if the expression were potentially-evaluated;
- //
- // Note, we do this even if MightBeOdrUse is false. That indicates that the
- // function is a pure virtual function we're calling, and in that case the
- // function was selected by overload resolution and we need to resolve its
- // exception specification for a different reason.
- const FunctionProtoType *FPT = Func->getType()->getAs<FunctionProtoType>();
- if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
- ResolveExceptionSpec(Loc, FPT);
-
if (getLangOpts().CUDA)
CheckCUDACall(Loc, Func);
@@ -15535,6 +15636,12 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
MarkVTableUsed(Loc, MethodDecl->getParent());
}
+ if (Func->isDefaulted() && !Func->isDeleted()) {
+ DefaultedComparisonKind DCK = getDefaultedComparisonKind(Func);
+ if (DCK != DefaultedComparisonKind::None)
+ DefineDefaultedComparison(Loc, Func, DCK);
+ }
+
// Implicit instantiation of function templates and member functions of
// class templates.
if (Func->isImplicitlyInstantiable()) {
@@ -15582,6 +15689,19 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
});
}
+ // 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,
+ // would be odr-used if the expression were potentially-evaluated;
+ //
+ // Note, we do this even if MightBeOdrUse is false. That indicates that the
+ // function is a pure virtual function we're calling, and in that case the
+ // function was selected by overload resolution and we need to resolve its
+ // exception specification for a different reason.
+ const FunctionProtoType *FPT = Func->getType()->getAs<FunctionProtoType>();
+ if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
+ ResolveExceptionSpec(Loc, FPT);
+
// If this is the first "real" use, act on that.
if (OdrUse == OdrUseContext::Used && !Func->isUsed(/*CheckUsedAttr=*/false)) {
// Keep track of used but undefined functions.
@@ -17880,7 +18000,7 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
// No guarantees that ResolveAndFixSingleFunctionTemplateSpecialization
// leaves Result unchanged on failure.
Result = E;
- if (resolveAndFixAddressOfOnlyViableOverloadCandidate(Result))
+ if (resolveAndFixAddressOfSingleOverloadCandidate(Result))
return Result;
// If that failed, try to recover with a call.
@@ -18017,3 +18137,8 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr(
return new (Context)
ObjCAvailabilityCheckExpr(Version, AtLoc, RParen, Context.BoolTy);
}
+
+bool Sema::IsDependentFunctionNameExpr(Expr *E) {
+ assert(E->isTypeDependent());
+ return isa<UnresolvedLookupExpr>(E);
+}
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 9aae9289b514..a73e6906fceb 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -921,7 +921,7 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc,
// cannot be a simple walk of the class's decls. Instead, we must perform
// lookup and overload resolution.
CXXConstructorDecl *CD = LookupCopyingConstructor(Subobject, 0);
- if (!CD)
+ if (!CD || CD->isDeleted())
continue;
// Mark the constructor referenced as it is used by this throw expression.
@@ -2323,7 +2323,7 @@ static bool resolveAllocationOverload(
PartialDiagnosticAt(R.getNameLoc(),
S.PDiag(diag::err_ovl_ambiguous_call)
<< R.getLookupName() << Range),
- S, OCD_ViableCandidates, Args);
+ S, OCD_AmbiguousCandidates, Args);
}
return true;
@@ -3513,7 +3513,7 @@ static bool resolveBuiltinNewDeleteOverload(Sema &S, CallExpr *TheCall,
PartialDiagnosticAt(R.getNameLoc(),
S.PDiag(diag::err_ovl_ambiguous_call)
<< R.getLookupName() << Range),
- S, OCD_ViableCandidates, Args);
+ S, OCD_AmbiguousCandidates, Args);
return true;
case OR_Deleted: {
@@ -4095,9 +4095,26 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
<< From->getSourceRange();
}
+ // Defer address space conversion to the third conversion.
+ QualType FromPteeType = From->getType()->getPointeeType();
+ QualType ToPteeType = ToType->getPointeeType();
+ QualType NewToType = ToType;
+ if (!FromPteeType.isNull() && !ToPteeType.isNull() &&
+ FromPteeType.getAddressSpace() != ToPteeType.getAddressSpace()) {
+ NewToType = Context.removeAddrSpaceQualType(ToPteeType);
+ NewToType = Context.getAddrSpaceQualType(NewToType,
+ FromPteeType.getAddressSpace());
+ if (ToType->isObjCObjectPointerType())
+ NewToType = Context.getObjCObjectPointerType(NewToType);
+ else if (ToType->isBlockPointerType())
+ NewToType = Context.getBlockPointerType(NewToType);
+ else
+ NewToType = Context.getPointerType(NewToType);
+ }
+
CastKind Kind;
CXXCastPath BasePath;
- if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle))
+ if (CheckPointerConversion(From, NewToType, Kind, BasePath, CStyle))
return ExprError();
// Make sure we extend blocks if necessary.
@@ -4108,8 +4125,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
From = E.get();
}
if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers())
- CheckObjCConversion(SourceRange(), ToType, From, CCK);
- From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK)
+ CheckObjCConversion(SourceRange(), NewToType, From, CCK);
+ From = ImpCastExprToType(From, NewToType, Kind, VK_RValue, &BasePath, CCK)
.get();
break;
}
@@ -5730,38 +5747,157 @@ static bool ConvertForConditional(Sema &Self, ExprResult &E, QualType T) {
return false;
}
+// Check the condition operand of ?: to see if it is valid for the GCC
+// extension.
+static bool isValidVectorForConditionalCondition(ASTContext &Ctx,
+ QualType CondTy) {
+ if (!CondTy->isVectorType() || CondTy->isExtVectorType())
+ return false;
+ const QualType EltTy =
+ cast<VectorType>(CondTy.getCanonicalType())->getElementType();
+
+ assert(!EltTy->isBooleanType() && !EltTy->isEnumeralType() &&
+ "Vectors cant be boolean or enum types");
+ return EltTy->isIntegralType(Ctx);
+}
+
+QualType Sema::CheckGNUVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS,
+ ExprResult &RHS,
+ SourceLocation QuestionLoc) {
+ LHS = DefaultFunctionArrayLvalueConversion(LHS.get());
+ RHS = DefaultFunctionArrayLvalueConversion(RHS.get());
+
+ QualType CondType = Cond.get()->getType();
+ const auto *CondVT = CondType->getAs<VectorType>();
+ QualType CondElementTy = CondVT->getElementType();
+ unsigned CondElementCount = CondVT->getNumElements();
+ QualType LHSType = LHS.get()->getType();
+ const auto *LHSVT = LHSType->getAs<VectorType>();
+ QualType RHSType = RHS.get()->getType();
+ const auto *RHSVT = RHSType->getAs<VectorType>();
+
+ QualType ResultType;
+
+ // FIXME: In the future we should define what the Extvector conditional
+ // operator looks like.
+ if (LHSVT && isa<ExtVectorType>(LHSVT)) {
+ Diag(QuestionLoc, diag::err_conditional_vector_operand_type)
+ << /*isExtVector*/ true << LHSType;
+ return {};
+ }
+
+ if (RHSVT && isa<ExtVectorType>(RHSVT)) {
+ Diag(QuestionLoc, diag::err_conditional_vector_operand_type)
+ << /*isExtVector*/ true << RHSType;
+ return {};
+ }
+
+ if (LHSVT && RHSVT) {
+ // If both are vector types, they must be the same type.
+ if (!Context.hasSameType(LHSType, RHSType)) {
+ Diag(QuestionLoc, diag::err_conditional_vector_mismatched_vectors)
+ << LHSType << RHSType;
+ return {};
+ }
+ ResultType = LHSType;
+ } else if (LHSVT || RHSVT) {
+ ResultType = CheckVectorOperands(
+ LHS, RHS, QuestionLoc, /*isCompAssign*/ false, /*AllowBothBool*/ true,
+ /*AllowBoolConversions*/ false);
+ if (ResultType.isNull())
+ 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);
+
+ if (ResultElementTy->isEnumeralType()) {
+ Diag(QuestionLoc, diag::err_conditional_vector_operand_type)
+ << /*isExtVector*/ false << ResultElementTy;
+ return {};
+ }
+ ResultType = Context.getVectorType(
+ ResultElementTy, CondType->getAs<VectorType>()->getNumElements(),
+ VectorType::GenericVector);
+
+ LHS = ImpCastExprToType(LHS.get(), ResultType, CK_VectorSplat);
+ RHS = ImpCastExprToType(RHS.get(), ResultType, CK_VectorSplat);
+ }
+
+ assert(!ResultType.isNull() && ResultType->isVectorType() &&
+ "Result should have been a vector type");
+ QualType ResultElementTy = ResultType->getAs<VectorType>()->getElementType();
+ unsigned ResultElementCount =
+ ResultType->getAs<VectorType>()->getNumElements();
+
+ if (ResultElementCount != CondElementCount) {
+ Diag(QuestionLoc, diag::err_conditional_vector_size) << CondType
+ << ResultType;
+ return {};
+ }
+
+ if (Context.getTypeSize(ResultElementTy) !=
+ Context.getTypeSize(CondElementTy)) {
+ Diag(QuestionLoc, diag::err_conditional_vector_element_size) << CondType
+ << ResultType;
+ return {};
+ }
+
+ return ResultType;
+}
+
/// Check the operands of ?: under C++ semantics.
///
/// See C++ [expr.cond]. Note that LHS is never null, even for the GNU x ?: y
/// extension. In this case, LHS == Cond. (But they're not aliases.)
+///
+/// This function also implements GCC's vector extension for conditionals.
+/// GCC's vector extension permits the use of a?b:c where the type of
+/// a is that of a integer vector with the same number of elements and
+/// size as the vectors of b and c. If one of either b or c is a scalar
+/// it is implicitly converted to match the type of the vector.
+/// Otherwise the expression is ill-formed. If both b and c are scalars,
+/// then b and c are checked and converted to the type of a if possible.
+/// Unlike the OpenCL ?: operator, the expression is evaluated as
+/// (a[0] != 0 ? b[0] : c[0], .. , a[n] != 0 ? b[n] : c[n]).
QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
ExprResult &RHS, ExprValueKind &VK,
ExprObjectKind &OK,
SourceLocation QuestionLoc) {
- // FIXME: Handle C99's complex types, vector types, block pointers and Obj-C++
- // interface pointers.
+ // FIXME: Handle C99's complex types, block pointers and Obj-C++ interface
+ // pointers.
+
+ // Assume r-value.
+ VK = VK_RValue;
+ OK = OK_Ordinary;
+ bool IsVectorConditional =
+ isValidVectorForConditionalCondition(Context, Cond.get()->getType());
// C++11 [expr.cond]p1
// The first expression is contextually converted to bool.
- //
- // FIXME; GCC's vector extension permits the use of a?b:c where the type of
- // a is that of a integer vector with the same number of elements and
- // size as the vectors of b and c. If one of either b or c is a scalar
- // it is implicitly converted to match the type of the vector.
- // Otherwise the expression is ill-formed. If both b and c are scalars,
- // then b and c are checked and converted to the type of a if possible.
- // Unlike the OpenCL ?: operator, the expression is evaluated as
- // (a[0] != 0 ? b[0] : c[0], .. , a[n] != 0 ? b[n] : c[n]).
if (!Cond.get()->isTypeDependent()) {
- ExprResult CondRes = CheckCXXBooleanCondition(Cond.get());
+ ExprResult CondRes = IsVectorConditional
+ ? DefaultFunctionArrayLvalueConversion(Cond.get())
+ : CheckCXXBooleanCondition(Cond.get());
if (CondRes.isInvalid())
return QualType();
Cond = CondRes;
+ } else {
+ // To implement C++, the first expression typically doesn't alter the result
+ // type of the conditional, however the GCC compatible vector extension
+ // changes the result type to be that of the conditional. Since we cannot
+ // know if this is a vector extension here, delay the conversion of the
+ // LHS/RHS below until later.
+ return Context.DependentTy;
}
- // Assume r-value.
- VK = VK_RValue;
- OK = OK_Ordinary;
// Either of the arguments dependent?
if (LHS.get()->isTypeDependent() || RHS.get()->isTypeDependent())
@@ -5780,6 +5916,17 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// and value category of the other.
bool LThrow = isa<CXXThrowExpr>(LHS.get()->IgnoreParenImpCasts());
bool RThrow = isa<CXXThrowExpr>(RHS.get()->IgnoreParenImpCasts());
+
+ // Void expressions aren't legal in the vector-conditional expressions.
+ if (IsVectorConditional) {
+ SourceRange DiagLoc =
+ LVoid ? LHS.get()->getSourceRange() : RHS.get()->getSourceRange();
+ bool IsThrow = LVoid ? LThrow : RThrow;
+ Diag(DiagLoc.getBegin(), diag::err_conditional_vector_has_void)
+ << DiagLoc << IsThrow;
+ return QualType();
+ }
+
if (LThrow != RThrow) {
Expr *NonThrow = LThrow ? RHS.get() : LHS.get();
VK = NonThrow->getValueKind();
@@ -5802,6 +5949,8 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
}
// Neither is void.
+ if (IsVectorConditional)
+ return CheckGNUVectorConditionalTypes(Cond, LHS, RHS, QuestionLoc);
// C++11 [expr.cond]p3
// Otherwise, if the second and third operand have different types, and
@@ -5845,29 +5994,33 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// FIXME:
// Resolving a defect in P0012R1: we extend this to cover all cases where
// one of the operands is reference-compatible with the other, in order
- // to support conditionals between functions differing in noexcept.
+ // to support conditionals between functions differing in noexcept. This
+ // will similarly cover difference in array bounds after P0388R4.
+ // FIXME: If LTy and RTy have a composite pointer type, should we convert to
+ // that instead?
ExprValueKind LVK = LHS.get()->getValueKind();
ExprValueKind RVK = RHS.get()->getValueKind();
if (!Context.hasSameType(LTy, RTy) &&
LVK == RVK && LVK != VK_RValue) {
// DerivedToBase was already handled by the class-specific case above.
// FIXME: Should we allow ObjC conversions here?
- bool DerivedToBase, ObjCConversion, ObjCLifetimeConversion,
- FunctionConversion;
- if (CompareReferenceRelationship(QuestionLoc, LTy, RTy, DerivedToBase,
- ObjCConversion, ObjCLifetimeConversion,
- FunctionConversion) == Ref_Compatible &&
- !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion &&
+ const ReferenceConversions AllowedConversions =
+ ReferenceConversions::Qualification |
+ ReferenceConversions::NestedQualification |
+ ReferenceConversions::Function;
+
+ ReferenceConversions RefConv;
+ if (CompareReferenceRelationship(QuestionLoc, LTy, RTy, &RefConv) ==
+ Ref_Compatible &&
+ !(RefConv & ~AllowedConversions) &&
// [...] subject to the constraint that the reference must bind
// directly [...]
!RHS.get()->refersToBitField() && !RHS.get()->refersToVectorElement()) {
RHS = ImpCastExprToType(RHS.get(), LTy, CK_NoOp, RVK);
RTy = RHS.get()->getType();
- } else if (CompareReferenceRelationship(
- QuestionLoc, RTy, LTy, DerivedToBase, ObjCConversion,
- ObjCLifetimeConversion,
- FunctionConversion) == Ref_Compatible &&
- !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion &&
+ } else if (CompareReferenceRelationship(QuestionLoc, RTy, LTy, &RefConv) ==
+ Ref_Compatible &&
+ !(RefConv & ~AllowedConversions) &&
!LHS.get()->refersToBitField() &&
!LHS.get()->refersToVectorElement()) {
LHS = ImpCastExprToType(LHS.get(), RTy, CK_NoOp, LVK);
@@ -5976,7 +6129,8 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// the usual arithmetic conversions are performed to bring them to a
// common type, and the result is of that type.
if (LTy->isArithmeticType() && RTy->isArithmeticType()) {
- QualType ResTy = UsualArithmeticConversions(LHS, RHS);
+ QualType ResTy =
+ UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
if (ResTy.isNull()) {
@@ -6098,10 +6252,10 @@ mergeExceptionSpecs(Sema &S, FunctionProtoType::ExceptionSpecInfo ESI1,
/// Find a merged pointer type and convert the two expressions to it.
///
-/// This finds the composite pointer type (or member pointer type) for @p E1
-/// and @p E2 according to C++1z 5p14. It converts both expressions to this
-/// type and returns it.
-/// It does not emit diagnostics.
+/// This finds the composite pointer type for \p E1 and \p E2 according to
+/// C++2a [expr.type]p3. It converts both expressions to this type and returns
+/// it. It does not emit diagnostics (FIXME: that's not true if \p ConvertArgs
+/// is \c true).
///
/// \param Loc The location of the operator requiring these two expressions to
/// be converted to the composite pointer type.
@@ -6154,60 +6308,117 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
assert(!T1->isNullPtrType() && !T2->isNullPtrType() &&
"nullptr_t should be a null pointer constant");
- // - if T1 or T2 is "pointer to cv1 void" and the other type is
- // "pointer to cv2 T", "pointer to cv12 void", where cv12 is
- // the union of cv1 and cv2;
- // - if T1 or T2 is "pointer to noexcept function" and the other type is
- // "pointer to function", where the function types are otherwise the same,
- // "pointer to function";
- // FIXME: This rule is defective: it should also permit removing noexcept
- // from a pointer to member function. As a Clang extension, we also
- // permit removing 'noreturn', so we generalize this rule to;
- // - [Clang] If T1 and T2 are both of type "pointer to function" or
- // "pointer to member function" and the pointee types can be unified
- // by a function pointer conversion, that conversion is applied
- // before checking the following rules.
+ struct Step {
+ enum Kind { Pointer, ObjCPointer, MemberPointer, Array } K;
+ // Qualifiers to apply under the step kind.
+ Qualifiers Quals;
+ /// The class for a pointer-to-member; a constant array type with a bound
+ /// (if any) for an array.
+ const Type *ClassOrBound;
+
+ Step(Kind K, const Type *ClassOrBound = nullptr)
+ : K(K), Quals(), ClassOrBound(ClassOrBound) {}
+ QualType rebuild(ASTContext &Ctx, QualType T) const {
+ T = Ctx.getQualifiedType(T, Quals);
+ switch (K) {
+ case Pointer:
+ return Ctx.getPointerType(T);
+ case MemberPointer:
+ return Ctx.getMemberPointerType(T, ClassOrBound);
+ case ObjCPointer:
+ return Ctx.getObjCObjectPointerType(T);
+ case Array:
+ if (auto *CAT = cast_or_null<ConstantArrayType>(ClassOrBound))
+ return Ctx.getConstantArrayType(T, CAT->getSize(), nullptr,
+ ArrayType::Normal, 0);
+ else
+ return Ctx.getIncompleteArrayType(T, ArrayType::Normal, 0);
+ }
+ llvm_unreachable("unknown step kind");
+ }
+ };
+
+ SmallVector<Step, 8> Steps;
+
// - if T1 is "pointer to cv1 C1" and T2 is "pointer to cv2 C2", where C1
// is reference-related to C2 or C2 is reference-related to C1 (8.6.3),
// the cv-combined type of T1 and T2 or the cv-combined type of T2 and T1,
// respectively;
// - if T1 is "pointer to member of C1 of type cv1 U1" and T2 is "pointer
- // to member of C2 of type cv2 U2" where C1 is reference-related to C2 or
- // C2 is reference-related to C1 (8.6.3), the cv-combined type of T2 and
- // T1 or the cv-combined type of T1 and T2, respectively;
+ // to member of C2 of type cv2 U2" for some non-function type U, where
+ // C1 is reference-related to C2 or C2 is reference-related to C1, the
+ // cv-combined type of T2 and T1 or the cv-combined type of T1 and T2,
+ // respectively;
// - if T1 and T2 are similar types (4.5), the cv-combined type of T1 and
// T2;
//
- // If looked at in the right way, these bullets all do the same thing.
- // What we do here is, we build the two possible cv-combined types, and try
- // the conversions in both directions. If only one works, or if the two
- // composite types are the same, we have succeeded.
- // FIXME: extended qualifiers?
- //
- // Note that this will fail to find a composite pointer type for "pointer
- // to void" and "pointer to function". We can't actually perform the final
- // conversion in this case, even though a composite pointer type formally
- // exists.
- SmallVector<unsigned, 4> QualifierUnion;
- SmallVector<std::pair<const Type *, const Type *>, 4> MemberOfClass;
+ // Dismantle T1 and T2 to simultaneously determine whether they are similar
+ // and to prepare to form the cv-combined type if so.
QualType Composite1 = T1;
QualType Composite2 = T2;
unsigned NeedConstBefore = 0;
while (true) {
+ assert(!Composite1.isNull() && !Composite2.isNull());
+
+ Qualifiers Q1, Q2;
+ Composite1 = Context.getUnqualifiedArrayType(Composite1, Q1);
+ Composite2 = Context.getUnqualifiedArrayType(Composite2, Q2);
+
+ // Top-level qualifiers are ignored. Merge at all lower levels.
+ if (!Steps.empty()) {
+ // Find the qualifier union: (approximately) the unique minimal set of
+ // qualifiers that is compatible with both types.
+ Qualifiers Quals = Qualifiers::fromCVRUMask(Q1.getCVRUQualifiers() |
+ Q2.getCVRUQualifiers());
+
+ // Under one level of pointer or pointer-to-member, we can change to an
+ // unambiguous compatible address space.
+ if (Q1.getAddressSpace() == Q2.getAddressSpace()) {
+ Quals.setAddressSpace(Q1.getAddressSpace());
+ } else if (Steps.size() == 1) {
+ bool MaybeQ1 = Q1.isAddressSpaceSupersetOf(Q2);
+ bool MaybeQ2 = Q2.isAddressSpaceSupersetOf(Q1);
+ if (MaybeQ1 == MaybeQ2)
+ return QualType(); // No unique best address space.
+ Quals.setAddressSpace(MaybeQ1 ? Q1.getAddressSpace()
+ : Q2.getAddressSpace());
+ } else {
+ return QualType();
+ }
+
+ // FIXME: In C, we merge __strong and none to __strong at the top level.
+ if (Q1.getObjCGCAttr() == Q2.getObjCGCAttr())
+ Quals.setObjCGCAttr(Q1.getObjCGCAttr());
+ else
+ return QualType();
+
+ // Mismatched lifetime qualifiers never compatibly include each other.
+ if (Q1.getObjCLifetime() == Q2.getObjCLifetime())
+ Quals.setObjCLifetime(Q1.getObjCLifetime());
+ else
+ return QualType();
+
+ Steps.back().Quals = Quals;
+ if (Q1 != Quals || Q2 != Quals)
+ NeedConstBefore = Steps.size() - 1;
+ }
+
+ // FIXME: Can we unify the following with UnwrapSimilarTypes?
const PointerType *Ptr1, *Ptr2;
if ((Ptr1 = Composite1->getAs<PointerType>()) &&
(Ptr2 = Composite2->getAs<PointerType>())) {
Composite1 = Ptr1->getPointeeType();
Composite2 = Ptr2->getPointeeType();
+ Steps.emplace_back(Step::Pointer);
+ continue;
+ }
- // If we're allowed to create a non-standard composite type, keep track
- // of where we need to fill in additional 'const' qualifiers.
- if (Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers())
- NeedConstBefore = QualifierUnion.size();
-
- QualifierUnion.push_back(
- Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
- MemberOfClass.push_back(std::make_pair(nullptr, nullptr));
+ const ObjCObjectPointerType *ObjPtr1, *ObjPtr2;
+ if ((ObjPtr1 = Composite1->getAs<ObjCObjectPointerType>()) &&
+ (ObjPtr2 = Composite2->getAs<ObjCObjectPointerType>())) {
+ Composite1 = ObjPtr1->getPointeeType();
+ Composite2 = ObjPtr2->getPointeeType();
+ Steps.emplace_back(Step::ObjCPointer);
continue;
}
@@ -6217,34 +6428,79 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
Composite1 = MemPtr1->getPointeeType();
Composite2 = MemPtr2->getPointeeType();
- // If we're allowed to create a non-standard composite type, keep track
- // of where we need to fill in additional 'const' qualifiers.
- if (Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers())
- NeedConstBefore = QualifierUnion.size();
+ // At the top level, we can perform a base-to-derived pointer-to-member
+ // conversion:
+ //
+ // - [...] where C1 is reference-related to C2 or C2 is
+ // reference-related to C1
+ //
+ // (Note that the only kinds of reference-relatedness in scope here are
+ // "same type or derived from".) At any other level, the class must
+ // exactly match.
+ const Type *Class = nullptr;
+ QualType Cls1(MemPtr1->getClass(), 0);
+ QualType Cls2(MemPtr2->getClass(), 0);
+ if (Context.hasSameType(Cls1, Cls2))
+ Class = MemPtr1->getClass();
+ else if (Steps.empty())
+ Class = IsDerivedFrom(Loc, Cls1, Cls2) ? MemPtr1->getClass() :
+ IsDerivedFrom(Loc, Cls2, Cls1) ? MemPtr2->getClass() : nullptr;
+ if (!Class)
+ return QualType();
+
+ Steps.emplace_back(Step::MemberPointer, Class);
+ continue;
+ }
- QualifierUnion.push_back(
- Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
- MemberOfClass.push_back(std::make_pair(MemPtr1->getClass(),
- MemPtr2->getClass()));
+ // Special case: at the top level, we can decompose an Objective-C pointer
+ // and a 'cv void *'. Unify the qualifiers.
+ if (Steps.empty() && ((Composite1->isVoidPointerType() &&
+ Composite2->isObjCObjectPointerType()) ||
+ (Composite1->isObjCObjectPointerType() &&
+ Composite2->isVoidPointerType()))) {
+ Composite1 = Composite1->getPointeeType();
+ Composite2 = Composite2->getPointeeType();
+ Steps.emplace_back(Step::Pointer);
continue;
}
+ // FIXME: arrays
+
// FIXME: block pointer types?
// Cannot unwrap any more types.
break;
}
- // Apply the function pointer conversion to unify the types. We've already
- // unwrapped down to the function types, and we want to merge rather than
- // just convert, so do this ourselves rather than calling
+ // - if T1 or T2 is "pointer to noexcept function" and the other type is
+ // "pointer to function", where the function types are otherwise the same,
+ // "pointer to function";
+ // - if T1 or T2 is "pointer to member of C1 of type function", the other
+ // type is "pointer to member of C2 of type noexcept function", and C1
+ // is reference-related to C2 or C2 is reference-related to C1, where
+ // the function types are otherwise the same, "pointer to member of C2 of
+ // type function" or "pointer to member of C1 of type function",
+ // respectively;
+ //
+ // We also support 'noreturn' here, so as a Clang extension we generalize the
+ // above to:
+ //
+ // - [Clang] If T1 and T2 are both of type "pointer to function" or
+ // "pointer to member function" and the pointee types can be unified
+ // by a function pointer conversion, that conversion is applied
+ // before checking the following rules.
+ //
+ // We've already unwrapped down to the function types, and we want to merge
+ // rather than just convert, so do this ourselves rather than calling
// IsFunctionConversion.
//
// FIXME: In order to match the standard wording as closely as possible, we
// currently only do this under a single level of pointers. Ideally, we would
// allow this in general, and set NeedConstBefore to the relevant depth on
- // the side(s) where we changed anything.
- if (QualifierUnion.size() == 1) {
+ // the side(s) where we changed anything. If we permit that, we should also
+ // consider this conversion when determining type similarity and model it as
+ // a qualification conversion.
+ if (Steps.size() == 1) {
if (auto *FPT1 = Composite1->getAs<FunctionProtoType>()) {
if (auto *FPT2 = Composite2->getAs<FunctionProtoType>()) {
FunctionProtoType::ExtProtoInfo EPI1 = FPT1->getExtProtoInfo();
@@ -6270,88 +6526,72 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
}
}
- if (NeedConstBefore) {
- // Extension: Add 'const' to qualifiers that come before the first qualifier
- // mismatch, so that our (non-standard!) composite type meets the
- // requirements of C++ [conv.qual]p4 bullet 3.
- for (unsigned I = 0; I != NeedConstBefore; ++I)
- if ((QualifierUnion[I] & Qualifiers::Const) == 0)
- QualifierUnion[I] = QualifierUnion[I] | Qualifiers::Const;
+ // There are some more conversions we can perform under exactly one pointer.
+ if (Steps.size() == 1 && Steps.front().K == Step::Pointer &&
+ !Context.hasSameType(Composite1, Composite2)) {
+ // - if T1 or T2 is "pointer to cv1 void" and the other type is
+ // "pointer to cv2 T", where T is an object type or void,
+ // "pointer to cv12 void", where cv12 is the union of cv1 and cv2;
+ if (Composite1->isVoidType() && Composite2->isObjectType())
+ Composite2 = Composite1;
+ else if (Composite2->isVoidType() && Composite1->isObjectType())
+ Composite1 = Composite2;
+ // - if T1 is "pointer to cv1 C1" and T2 is "pointer to cv2 C2", where C1
+ // is reference-related to C2 or C2 is reference-related to C1 (8.6.3),
+ // the cv-combined type of T1 and T2 or the cv-combined type of T2 and
+ // T1, respectively;
+ //
+ // The "similar type" handling covers all of this except for the "T1 is a
+ // base class of T2" case in the definition of reference-related.
+ else if (IsDerivedFrom(Loc, Composite1, Composite2))
+ Composite1 = Composite2;
+ else if (IsDerivedFrom(Loc, Composite2, Composite1))
+ Composite2 = Composite1;
}
- // Rewrap the composites as pointers or member pointers with the union CVRs.
- auto MOC = MemberOfClass.rbegin();
- for (unsigned CVR : llvm::reverse(QualifierUnion)) {
- Qualifiers Quals = Qualifiers::fromCVRMask(CVR);
- auto Classes = *MOC++;
- if (Classes.first && Classes.second) {
- // Rebuild member pointer type
- Composite1 = Context.getMemberPointerType(
- Context.getQualifiedType(Composite1, Quals), Classes.first);
- Composite2 = Context.getMemberPointerType(
- Context.getQualifiedType(Composite2, Quals), Classes.second);
- } else {
- // Rebuild pointer type
- Composite1 =
- Context.getPointerType(Context.getQualifiedType(Composite1, Quals));
- Composite2 =
- Context.getPointerType(Context.getQualifiedType(Composite2, Quals));
- }
- }
+ // At this point, either the inner types are the same or we have failed to
+ // find a composite pointer type.
+ if (!Context.hasSameType(Composite1, Composite2))
+ return QualType();
- struct Conversion {
- Sema &S;
- Expr *&E1, *&E2;
- QualType Composite;
- InitializedEntity Entity;
- InitializationKind Kind;
- InitializationSequence E1ToC, E2ToC;
- bool Viable;
+ // Per C++ [conv.qual]p3, add 'const' to every level before the last
+ // differing qualifier.
+ for (unsigned I = 0; I != NeedConstBefore; ++I)
+ Steps[I].Quals.addConst();
- Conversion(Sema &S, SourceLocation Loc, Expr *&E1, Expr *&E2,
- QualType Composite)
- : S(S), E1(E1), E2(E2), Composite(Composite),
- Entity(InitializedEntity::InitializeTemporary(Composite)),
- Kind(InitializationKind::CreateCopy(Loc, SourceLocation())),
- E1ToC(S, Entity, Kind, E1), E2ToC(S, Entity, Kind, E2),
- Viable(E1ToC && E2ToC) {}
+ // Rebuild the composite type.
+ QualType Composite = Composite1;
+ for (auto &S : llvm::reverse(Steps))
+ Composite = S.rebuild(Context, Composite);
- bool perform() {
- ExprResult E1Result = E1ToC.Perform(S, Entity, Kind, E1);
- if (E1Result.isInvalid())
- return true;
- E1 = E1Result.getAs<Expr>();
+ if (ConvertArgs) {
+ // Convert the expressions to the composite pointer type.
+ InitializedEntity Entity =
+ InitializedEntity::InitializeTemporary(Composite);
+ InitializationKind Kind =
+ InitializationKind::CreateCopy(Loc, SourceLocation());
- ExprResult E2Result = E2ToC.Perform(S, Entity, Kind, E2);
- if (E2Result.isInvalid())
- return true;
- E2 = E2Result.getAs<Expr>();
+ InitializationSequence E1ToC(*this, Entity, Kind, E1);
+ if (!E1ToC)
+ return QualType();
- return false;
- }
- };
+ InitializationSequence E2ToC(*this, Entity, Kind, E2);
+ if (!E2ToC)
+ return QualType();
- // Try to convert to each composite pointer type.
- Conversion C1(*this, Loc, E1, E2, Composite1);
- if (C1.Viable && Context.hasSameType(Composite1, Composite2)) {
- if (ConvertArgs && C1.perform())
+ // FIXME: Let the caller know if these fail to avoid duplicate diagnostics.
+ ExprResult E1Result = E1ToC.Perform(*this, Entity, Kind, E1);
+ if (E1Result.isInvalid())
return QualType();
- return C1.Composite;
- }
- Conversion C2(*this, Loc, E1, E2, Composite2);
+ E1 = E1Result.get();
- if (C1.Viable == C2.Viable) {
- // Either Composite1 and Composite2 are viable and are different, or
- // neither is viable.
- // FIXME: How both be viable and different?
- return QualType();
+ ExprResult E2Result = E2ToC.Perform(*this, Entity, Kind, E2);
+ if (E2Result.isInvalid())
+ return QualType();
+ E2 = E2Result.get();
}
- // Convert to the chosen type.
- if (ConvertArgs && (C1.Viable ? C1 : C2).perform())
- return QualType();
-
- return C1.Viable ? C1.Composite : C2.Composite;
+ return Composite;
}
ExprResult Sema::MaybeBindToTemporary(Expr *E) {
@@ -7780,8 +8020,9 @@ class TransformTypos : public TreeTransform<TransformTypos> {
// If we found a valid result, double check to make sure it's not ambiguous.
if (!IsAmbiguous && !Res.isInvalid() && !AmbiguousTypoExprs.empty()) {
- auto SavedTransformCache = std::move(TransformCache);
- TransformCache.clear();
+ auto SavedTransformCache =
+ llvm::SmallDenseMap<TypoExpr *, ExprResult, 2>(TransformCache);
+
// Ensure none of the TypoExprs have multiple typo correction candidates
// with the same edit length that pass all the checks and filters.
while (!AmbiguousTypoExprs.empty()) {
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 87114a0fac63..ebfc1ec4b974 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -919,6 +919,18 @@ MemberExpr *Sema::BuildMemberExpr(
VK, OK, getNonOdrUseReasonInCurrentContext(Member));
E->setHadMultipleCandidates(HadMultipleCandidates);
MarkMemberReferenced(E);
+
+ // C++ [except.spec]p17:
+ // An exception-specification is considered to be needed when:
+ // - in an expression the function is the unique lookup result or the
+ // selected member of a set of overloaded functions
+ if (auto *FPT = Ty->getAs<FunctionProtoType>()) {
+ if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
+ if (auto *NewFPT = ResolveExceptionSpec(MemberNameInfo.getLoc(), FPT))
+ E->setType(Context.getQualifiedType(NewFPT, Ty.getQualifiers()));
+ }
+ }
+
return E;
}
diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp
index e18621e42a6b..c61b13cf5980 100644
--- a/clang/lib/Sema/SemaExprObjC.cpp
+++ b/clang/lib/Sema/SemaExprObjC.cpp
@@ -10,13 +10,13 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Sema/SemaInternal.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
+#include "clang/Basic/Builtins.h"
#include "clang/Edit/Commit.h"
#include "clang/Edit/Rewriters.h"
#include "clang/Lex/Preprocessor.h"
@@ -24,6 +24,7 @@
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ConvertUTF.h"
@@ -288,6 +289,7 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
S.NSNumberPointer, ReturnTInfo, S.NSNumberDecl,
/*isInstance=*/false, /*isVariadic=*/false,
/*isPropertyAccessor=*/false,
+ /*isSynthesizedAccessorStub=*/false,
/*isImplicitlyDeclared=*/true,
/*isDefined=*/false, ObjCMethodDecl::Required,
/*HasRelatedResultType=*/false);
@@ -563,6 +565,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
NSStringPointer, ReturnTInfo, NSStringDecl,
/*isInstance=*/false, /*isVariadic=*/false,
/*isPropertyAccessor=*/false,
+ /*isSynthesizedAccessorStub=*/false,
/*isImplicitlyDeclared=*/true,
/*isDefined=*/false, ObjCMethodDecl::Required,
/*HasRelatedResultType=*/false);
@@ -671,20 +674,15 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
// Debugger needs to work even if NSValue hasn't been defined.
TypeSourceInfo *ReturnTInfo = nullptr;
ObjCMethodDecl *M = ObjCMethodDecl::Create(
- Context,
- SourceLocation(),
- SourceLocation(),
- ValueWithBytesObjCType,
- NSValuePointer,
- ReturnTInfo,
- NSValueDecl,
- /*isInstance=*/false,
- /*isVariadic=*/false,
- /*isPropertyAccessor=*/false,
- /*isImplicitlyDeclared=*/true,
- /*isDefined=*/false,
- ObjCMethodDecl::Required,
- /*HasRelatedResultType=*/false);
+ Context, SourceLocation(), SourceLocation(), ValueWithBytesObjCType,
+ NSValuePointer, ReturnTInfo, NSValueDecl,
+ /*isInstance=*/false,
+ /*isVariadic=*/false,
+ /*isPropertyAccessor=*/false,
+ /*isSynthesizedAccessorStub=*/false,
+ /*isImplicitlyDeclared=*/true,
+ /*isDefined=*/false, ObjCMethodDecl::Required,
+ /*HasRelatedResultType=*/false);
SmallVector<ParmVarDecl *, 2> Params;
@@ -815,7 +813,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
Context, SourceLocation(), SourceLocation(), Sel, IdT, ReturnTInfo,
Context.getTranslationUnitDecl(), false /*Instance*/,
false /*isVariadic*/,
- /*isPropertyAccessor=*/false,
+ /*isPropertyAccessor=*/false, /*isSynthesizedAccessorStub=*/false,
/*isImplicitlyDeclared=*/true, /*isDefined=*/false,
ObjCMethodDecl::Required, false);
SmallVector<ParmVarDecl *, 2> Params;
@@ -916,16 +914,14 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
NSAPI::NSDict_dictionaryWithObjectsForKeysCount);
ObjCMethodDecl *Method = NSDictionaryDecl->lookupClassMethod(Sel);
if (!Method && getLangOpts().DebuggerObjCLiteral) {
- Method = ObjCMethodDecl::Create(Context,
- SourceLocation(), SourceLocation(), Sel,
- IdT,
- nullptr /*TypeSourceInfo */,
- Context.getTranslationUnitDecl(),
- false /*Instance*/, false/*isVariadic*/,
- /*isPropertyAccessor=*/false,
- /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
- ObjCMethodDecl::Required,
- false);
+ Method = ObjCMethodDecl::Create(
+ Context, SourceLocation(), SourceLocation(), Sel, IdT,
+ nullptr /*TypeSourceInfo */, Context.getTranslationUnitDecl(),
+ false /*Instance*/, false /*isVariadic*/,
+ /*isPropertyAccessor=*/false,
+ /*isSynthesizedAccessorStub=*/false,
+ /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
+ ObjCMethodDecl::Required, false);
SmallVector<ParmVarDecl *, 3> Params;
ParmVarDecl *objects = ParmVarDecl::Create(Context, Method,
SourceLocation(),
@@ -1174,6 +1170,35 @@ static void DiagnoseMismatchedSelectors(Sema &S, SourceLocation AtLoc,
}
}
+static void HelperToDiagnoseDirectSelectorsExpr(Sema &S, SourceLocation AtLoc,
+ Selector Sel,
+ ObjCMethodList &MethList,
+ bool &onlyDirect) {
+ ObjCMethodList *M = &MethList;
+ for (M = M->getNext(); M; M = M->getNext()) {
+ ObjCMethodDecl *Method = M->getMethod();
+ if (Method->getSelector() != Sel)
+ continue;
+ if (!Method->isDirectMethod())
+ onlyDirect = false;
+ }
+}
+
+static void DiagnoseDirectSelectorsExpr(Sema &S, SourceLocation AtLoc,
+ Selector Sel, bool &onlyDirect) {
+ for (Sema::GlobalMethodPool::iterator b = S.MethodPool.begin(),
+ e = S.MethodPool.end(); b != e; b++) {
+ // first, instance methods
+ ObjCMethodList &InstMethList = b->second.first;
+ HelperToDiagnoseDirectSelectorsExpr(S, AtLoc, Sel, InstMethList,
+ onlyDirect);
+
+ // second, class methods
+ ObjCMethodList &ClsMethList = b->second.second;
+ HelperToDiagnoseDirectSelectorsExpr(S, AtLoc, Sel, ClsMethList, onlyDirect);
+ }
+}
+
ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
SourceLocation AtLoc,
SourceLocation SelLoc,
@@ -1196,9 +1221,18 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
} else
Diag(SelLoc, diag::warn_undeclared_selector) << Sel;
- } else
+ } else {
+ bool onlyDirect = Method->isDirectMethod();
+ DiagnoseDirectSelectorsExpr(*this, AtLoc, Sel, onlyDirect);
DiagnoseMismatchedSelectors(*this, AtLoc, Method, LParenLoc, RParenLoc,
WarnMultipleSelectors);
+ if (onlyDirect) {
+ Diag(AtLoc, diag::err_direct_selector_expression)
+ << Method->getSelector();
+ Diag(Method->getLocation(), diag::note_direct_method_declared_at)
+ << Method->getDeclName();
+ }
+ }
if (Method &&
Method->getImplementationControl() != ObjCMethodDecl::Optional &&
@@ -1608,15 +1642,14 @@ bool Sema::CheckMessageArgumentTypes(
<< Sel << isClassMessage << SourceRange(SelectorLocs.front(),
SelectorLocs.back());
// Find the class to which we are sending this message.
- if (ReceiverType->isObjCObjectPointerType()) {
- if (ObjCInterfaceDecl *ThisClass =
- ReceiverType->getAs<ObjCObjectPointerType>()->getInterfaceDecl()) {
+ if (auto *ObjPT = ReceiverType->getAs<ObjCObjectPointerType>()) {
+ if (ObjCInterfaceDecl *ThisClass = ObjPT->getInterfaceDecl()) {
Diag(ThisClass->getLocation(), diag::note_receiver_class_declared);
if (!RecRange.isInvalid())
if (ThisClass->lookupClassMethod(Sel))
- Diag(RecRange.getBegin(),diag::note_receiver_expr_here)
- << FixItHint::CreateReplacement(RecRange,
- ThisClass->getNameAsString());
+ Diag(RecRange.getBegin(), diag::note_receiver_expr_here)
+ << FixItHint::CreateReplacement(RecRange,
+ ThisClass->getNameAsString());
}
}
}
@@ -2365,7 +2398,6 @@ static void checkFoundationAPI(Sema &S, SourceLocation Loc,
return;
QualType Ret = ImpliedMethod->getReturnType();
if (Ret->isRecordType() || Ret->isVectorType() || Ret->isExtVectorType()) {
- QualType Ret = ImpliedMethod->getReturnType();
S.Diag(Loc, diag::warn_objc_unsafe_perform_selector)
<< Method->getSelector()
<< (!Ret->isRecordType()
@@ -2771,9 +2803,6 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
}
}
- if (ReceiverType->isObjCIdType() && !isImplicit)
- Diag(Receiver->getExprLoc(), diag::warn_messaging_unqualified_id);
-
// There's a somewhat weird interaction here where we assume that we
// won't actually have a method unless we also don't need to do some
// of the more detailed type-checking on the receiver.
@@ -2975,6 +3004,30 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
(Method && Method->getMethodFamily() == OMF_init)
? getEnclosingFunction() : nullptr;
+ if (Method && Method->isDirectMethod()) {
+ if (ReceiverType->isObjCIdType() && !isImplicit) {
+ Diag(Receiver->getExprLoc(),
+ diag::err_messaging_unqualified_id_with_direct_method);
+ Diag(Method->getLocation(), diag::note_direct_method_declared_at)
+ << Method->getDeclName();
+ }
+
+ if (ReceiverType->isObjCClassType() && !isImplicit) {
+ Diag(Receiver->getExprLoc(),
+ diag::err_messaging_class_with_direct_method);
+ Diag(Method->getLocation(), diag::note_direct_method_declared_at)
+ << Method->getDeclName();
+ }
+
+ if (SuperLoc.isValid()) {
+ Diag(SuperLoc, diag::err_messaging_super_with_direct_method);
+ Diag(Method->getLocation(), diag::note_direct_method_declared_at)
+ << Method->getDeclName();
+ }
+ } else if (ReceiverType->isObjCIdType() && !isImplicit) {
+ Diag(Receiver->getExprLoc(), diag::warn_messaging_unqualified_id);
+ }
+
if (DIFunctionScopeInfo &&
DIFunctionScopeInfo->ObjCIsDesignatedInit &&
(SuperLoc.isValid() || isSelfExpr(Receiver))) {
@@ -4358,7 +4411,7 @@ Expr *Sema::stripARCUnbridgedCast(Expr *e) {
SmallVector<TypeSourceInfo *, 4> subTypes;
subExprs.reserve(n);
subTypes.reserve(n);
- for (const GenericSelectionExpr::Association &assoc : gse->associations()) {
+ for (const GenericSelectionExpr::Association assoc : gse->associations()) {
subTypes.push_back(assoc.getTypeSourceInfo());
Expr *sub = assoc.getAssociationExpr();
if (assoc.isSelected())
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 10cb7acad567..785637761e71 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -3877,9 +3877,6 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
if (!Info.Constructor || Info.Constructor->isInvalidDecl())
continue;
- if (!AllowExplicit && Info.Constructor->isExplicit())
- continue;
-
if (OnlyListConstructors && !S.isInitListConstructor(Info.Constructor))
continue;
@@ -3951,18 +3948,16 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
else
Conv = cast<CXXConversionDecl>(D);
- if (AllowExplicit || !Conv->isExplicit()) {
- if (ConvTemplate)
- S.AddTemplateConversionCandidate(
- ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
- CandidateSet, AllowExplicit, AllowExplicit,
- /*AllowResultConversion*/ false);
- else
- S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
- DestType, CandidateSet, AllowExplicit,
- AllowExplicit,
- /*AllowResultConversion*/ false);
- }
+ if (ConvTemplate)
+ S.AddTemplateConversionCandidate(
+ ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
+ CandidateSet, AllowExplicit, AllowExplicit,
+ /*AllowResultConversion*/ false);
+ else
+ S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
+ DestType, CandidateSet, AllowExplicit,
+ AllowExplicit,
+ /*AllowResultConversion*/ false);
}
}
}
@@ -4064,7 +4059,7 @@ static void TryConstructorInitialization(Sema &S,
// If the initializer list has no elements and T has a default constructor,
// the first phase is omitted.
- if (!(UnwrappedArgs.empty() && DestRecordDecl->hasDefaultConstructor()))
+ if (!(UnwrappedArgs.empty() && S.LookupDefaultConstructor(DestRecordDecl)))
Result = ResolveConstructorOverload(S, Kind.getLocation(), Args,
CandidateSet, DestType, Ctors, Best,
CopyInitialization, AllowExplicit,
@@ -4229,10 +4224,8 @@ static void TryReferenceListInitialization(Sema &S,
return;
SourceLocation DeclLoc = Initializer->getBeginLoc();
- bool dummy1, dummy2, dummy3, dummy4;
Sema::ReferenceCompareResult RefRelationship
- = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, dummy1,
- dummy2, dummy3, dummy4);
+ = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2);
if (RefRelationship >= Sema::Ref_Related) {
// Try to bind the reference here.
TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1,
@@ -4350,7 +4343,7 @@ static void TryListInitialization(Sema &S,
// value-initialized.
if (InitList->getNumInits() == 0) {
CXXRecordDecl *RD = DestType->getAsCXXRecordDecl();
- if (RD->hasDefaultConstructor()) {
+ if (S.LookupDefaultConstructor(RD)) {
TryValueInitialization(S, Entity, Kind, Sequence, InitList);
return;
}
@@ -4469,18 +4462,8 @@ static OverloadingResult TryRefInitWithConversionFunction(
QualType cv2T2 = Initializer->getType();
QualType T2 = cv2T2.getUnqualifiedType();
- bool DerivedToBase;
- bool ObjCConversion;
- bool ObjCLifetimeConversion;
- bool FunctionConversion;
- assert(!S.CompareReferenceRelationship(
- Initializer->getBeginLoc(), T1, T2, DerivedToBase, ObjCConversion,
- ObjCLifetimeConversion, FunctionConversion) &&
+ assert(!S.CompareReferenceRelationship(Initializer->getBeginLoc(), T1, T2) &&
"Must have incompatible references when binding via conversion");
- (void)DerivedToBase;
- (void)ObjCConversion;
- (void)ObjCLifetimeConversion;
- (void)FunctionConversion;
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
@@ -4507,7 +4490,7 @@ static OverloadingResult TryRefInitWithConversionFunction(
continue;
if (!Info.Constructor->isInvalidDecl() &&
- Info.Constructor->isConvertingConstructor(AllowExplicitCtors)) {
+ Info.Constructor->isConvertingConstructor(/*AllowExplicit*/true)) {
if (Info.ConstructorTmpl)
S.AddTemplateOverloadCandidate(
Info.ConstructorTmpl, Info.FoundDecl,
@@ -4552,8 +4535,7 @@ static OverloadingResult TryRefInitWithConversionFunction(
// FIXME: Do we need to make sure that we only consider conversion
// candidates with reference-compatible results? That might be needed to
// break recursion.
- if ((AllowExplicitConvs || !Conv->isExplicit()) &&
- (AllowRValues ||
+ if ((AllowRValues ||
Conv->getConversionType()->isLValueReferenceType())) {
if (ConvTemplate)
S.AddTemplateConversionCandidate(
@@ -4604,14 +4586,9 @@ static OverloadingResult TryRefInitWithConversionFunction(
// Determine whether we'll need to perform derived-to-base adjustments or
// other conversions.
- bool NewDerivedToBase = false;
- bool NewObjCConversion = false;
- bool NewObjCLifetimeConversion = false;
- bool NewFunctionConversion = false;
+ Sema::ReferenceConversions RefConv;
Sema::ReferenceCompareResult NewRefRelationship =
- S.CompareReferenceRelationship(
- DeclLoc, T1, cv3T3, NewDerivedToBase, NewObjCConversion,
- NewObjCLifetimeConversion, NewFunctionConversion);
+ S.CompareReferenceRelationship(DeclLoc, T1, cv3T3, &RefConv);
// Add the final conversion sequence, if necessary.
if (NewRefRelationship == Sema::Ref_Incompatible) {
@@ -4641,12 +4618,16 @@ static OverloadingResult TryRefInitWithConversionFunction(
Sequence.AddReferenceBindingStep(cv1T4, VK == VK_RValue);
VK = IsLValueRef ? VK_LValue : VK_XValue;
- if (NewDerivedToBase)
+ if (RefConv & Sema::ReferenceConversions::DerivedToBase)
Sequence.AddDerivedToBaseCastStep(cv1T1, VK);
- else if (NewObjCConversion)
+ else if (RefConv & Sema::ReferenceConversions::ObjC)
Sequence.AddObjCObjectConversionStep(cv1T1);
- else if (NewFunctionConversion)
+ else if (RefConv & Sema::ReferenceConversions::Function)
Sequence.AddQualificationConversionStep(cv1T1, VK);
+ else if (RefConv & Sema::ReferenceConversions::Qualification) {
+ if (!S.Context.hasSameType(cv1T4, cv1T1))
+ Sequence.AddQualificationConversionStep(cv1T1, VK);
+ }
return OR_Success;
}
@@ -4700,17 +4681,15 @@ static void TryReferenceInitializationCore(Sema &S,
InitializationSequence &Sequence) {
QualType DestType = Entity.getType();
SourceLocation DeclLoc = Initializer->getBeginLoc();
+
// Compute some basic properties of the types and the initializer.
bool isLValueRef = DestType->isLValueReferenceType();
bool isRValueRef = !isLValueRef;
- bool DerivedToBase = false;
- bool ObjCConversion = false;
- bool ObjCLifetimeConversion = false;
- bool FunctionConversion = false;
Expr::Classification InitCategory = Initializer->Classify(S.Context);
- Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship(
- DeclLoc, cv1T1, cv2T2, DerivedToBase, ObjCConversion,
- ObjCLifetimeConversion, FunctionConversion);
+
+ Sema::ReferenceConversions RefConv;
+ Sema::ReferenceCompareResult RefRelationship =
+ S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, &RefConv);
// C++0x [dcl.init.ref]p5:
// A reference to type "cv1 T1" is initialized by an expression of type
@@ -4730,19 +4709,25 @@ static void TryReferenceInitializationCore(Sema &S,
RefRelationship == Sema::Ref_Related))) {
// - is an lvalue (but is not a bit-field), and "cv1 T1" is
// reference-compatible with "cv2 T2," or
- if (T1Quals != T2Quals)
- // Convert to cv1 T2. This should only add qualifiers unless this is a
- // c-style cast. The removal of qualifiers in that case notionally
- // happens after the reference binding, but that doesn't matter.
- Sequence.AddQualificationConversionStep(
- S.Context.getQualifiedType(T2, T1Quals),
- Initializer->getValueKind());
- if (DerivedToBase)
- Sequence.AddDerivedToBaseCastStep(cv1T1, VK_LValue);
- else if (ObjCConversion)
- Sequence.AddObjCObjectConversionStep(cv1T1);
- else if (FunctionConversion)
- Sequence.AddQualificationConversionStep(cv1T1, VK_LValue);
+ if (RefConv & (Sema::ReferenceConversions::DerivedToBase |
+ Sema::ReferenceConversions::ObjC)) {
+ // If we're converting the pointee, add any qualifiers first;
+ // these qualifiers must all be top-level, so just convert to "cv1 T2".
+ if (RefConv & (Sema::ReferenceConversions::Qualification))
+ Sequence.AddQualificationConversionStep(
+ S.Context.getQualifiedType(T2, T1Quals),
+ Initializer->getValueKind());
+ if (RefConv & Sema::ReferenceConversions::DerivedToBase)
+ Sequence.AddDerivedToBaseCastStep(cv1T1, VK_LValue);
+ else
+ Sequence.AddObjCObjectConversionStep(cv1T1);
+ } else if (RefConv & (Sema::ReferenceConversions::Qualification |
+ Sema::ReferenceConversions::Function)) {
+ // Perform a (possibly multi-level) qualification conversion.
+ // FIXME: Should we use a different step kind for function conversions?
+ Sequence.AddQualificationConversionStep(cv1T1,
+ Initializer->getValueKind());
+ }
// We only create a temporary here when binding a reference to a
// bit-field or vector element. Those cases are't supposed to be
@@ -4873,14 +4858,19 @@ static void TryReferenceInitializationCore(Sema &S,
T4Quals.addAddressSpace(T1Quals.getAddressSpace());
QualType cv1T4WithAS = S.Context.getQualifiedType(T2, T4Quals);
Sequence.AddQualificationConversionStep(cv1T4WithAS, ValueKind);
+ cv1T4 = cv1T4WithAS;
}
// In any case, the reference is bound to the resulting glvalue (or to
// an appropriate base class subobject).
- if (DerivedToBase)
+ if (RefConv & Sema::ReferenceConversions::DerivedToBase)
Sequence.AddDerivedToBaseCastStep(cv1T1, ValueKind);
- else if (ObjCConversion)
+ else if (RefConv & Sema::ReferenceConversions::ObjC)
Sequence.AddObjCObjectConversionStep(cv1T1);
+ else if (RefConv & Sema::ReferenceConversions::Qualification) {
+ if (!S.Context.hasSameType(cv1T4, cv1T1))
+ Sequence.AddQualificationConversionStep(cv1T1, ValueKind);
+ }
return;
}
@@ -5157,7 +5147,7 @@ static void TryUserDefinedConversion(Sema &S,
continue;
if (!Info.Constructor->isInvalidDecl() &&
- Info.Constructor->isConvertingConstructor(AllowExplicit)) {
+ Info.Constructor->isConvertingConstructor(/*AllowExplicit*/true)) {
if (Info.ConstructorTmpl)
S.AddTemplateOverloadCandidate(
Info.ConstructorTmpl, Info.FoundDecl,
@@ -5201,16 +5191,14 @@ static void TryUserDefinedConversion(Sema &S,
else
Conv = cast<CXXConversionDecl>(D);
- if (AllowExplicit || !Conv->isExplicit()) {
- if (ConvTemplate)
- S.AddTemplateConversionCandidate(
- ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
- CandidateSet, AllowExplicit, AllowExplicit);
- else
- S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
- DestType, CandidateSet, AllowExplicit,
- AllowExplicit);
- }
+ if (ConvTemplate)
+ S.AddTemplateConversionCandidate(
+ ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
+ CandidateSet, AllowExplicit, AllowExplicit);
+ else
+ S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
+ DestType, CandidateSet, AllowExplicit,
+ AllowExplicit);
}
}
}
@@ -6154,7 +6142,7 @@ static ExprResult CopyObject(Sema &S,
<< (int)Entity.getKind()
<< CurInitExpr->getType()
<< CurInitExpr->getSourceRange()),
- S, OCD_ViableCandidates, CurInitExpr);
+ S, OCD_AmbiguousCandidates, CurInitExpr);
return ExprError();
case OR_Deleted:
@@ -6295,7 +6283,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
case OR_Ambiguous:
CandidateSet.NoteCandidates(PartialDiagnosticAt(Loc, Diag), S,
- OCD_ViableCandidates, CurInitExpr);
+ OCD_AmbiguousCandidates, CurInitExpr);
break;
case OR_Deleted:
@@ -6653,6 +6641,7 @@ struct IndirectLocalPathEntry {
VarInit,
LValToRVal,
LifetimeBoundCall,
+ GslReferenceInit,
GslPointerInit
} Kind;
Expr *E;
@@ -6783,12 +6772,24 @@ static bool shouldTrackFirstArgument(const FunctionDecl *FD) {
static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call,
LocalVisitor Visit) {
- auto VisitPointerArg = [&](const Decl *D, Expr *Arg) {
+ auto VisitPointerArg = [&](const Decl *D, Expr *Arg, bool Value) {
// We are not interested in the temporary base objects of gsl Pointers:
// Temp().ptr; // Here ptr might not dangle.
if (isa<MemberExpr>(Arg->IgnoreImpCasts()))
return;
- Path.push_back({IndirectLocalPathEntry::GslPointerInit, Arg, D});
+ // Once we initialized a value with a reference, it can no longer dangle.
+ if (!Value) {
+ for (auto It = Path.rbegin(), End = Path.rend(); It != End; ++It) {
+ if (It->Kind == IndirectLocalPathEntry::GslReferenceInit)
+ continue;
+ if (It->Kind == IndirectLocalPathEntry::GslPointerInit)
+ return;
+ break;
+ }
+ }
+ Path.push_back({Value ? IndirectLocalPathEntry::GslPointerInit
+ : IndirectLocalPathEntry::GslReferenceInit,
+ Arg, D});
if (Arg->isGLValue())
visitLocalsRetainedByReferenceBinding(Path, Arg, RK_ReferenceBinding,
Visit,
@@ -6802,18 +6803,21 @@ static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call,
if (auto *MCE = dyn_cast<CXXMemberCallExpr>(Call)) {
const auto *MD = cast_or_null<CXXMethodDecl>(MCE->getDirectCallee());
if (MD && shouldTrackImplicitObjectArg(MD))
- VisitPointerArg(MD, MCE->getImplicitObjectArgument());
+ VisitPointerArg(MD, MCE->getImplicitObjectArgument(),
+ !MD->getReturnType()->isReferenceType());
return;
} else if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(Call)) {
FunctionDecl *Callee = OCE->getDirectCallee();
if (Callee && Callee->isCXXInstanceMember() &&
shouldTrackImplicitObjectArg(cast<CXXMethodDecl>(Callee)))
- VisitPointerArg(Callee, OCE->getArg(0));
+ VisitPointerArg(Callee, OCE->getArg(0),
+ !Callee->getReturnType()->isReferenceType());
return;
} else if (auto *CE = dyn_cast<CallExpr>(Call)) {
FunctionDecl *Callee = CE->getDirectCallee();
if (Callee && shouldTrackFirstArgument(Callee))
- VisitPointerArg(Callee, CE->getArg(0));
+ VisitPointerArg(Callee, CE->getArg(0),
+ !Callee->getReturnType()->isReferenceType());
return;
}
@@ -6821,7 +6825,7 @@ static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call,
const auto *Ctor = CCE->getConstructor();
const CXXRecordDecl *RD = Ctor->getParent();
if (CCE->getNumArgs() > 0 && RD->hasAttr<PointerAttr>())
- VisitPointerArg(Ctor->getParamDecl(0), CCE->getArgs()[0]);
+ VisitPointerArg(Ctor->getParamDecl(0), CCE->getArgs()[0], true);
}
}
@@ -6946,8 +6950,8 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init)) {
if (Visit(Path, Local(MTE), RK))
- visitLocalsRetainedByInitializer(Path, MTE->GetTemporaryExpr(), Visit,
- true, EnableLifetimeWarnings);
+ visitLocalsRetainedByInitializer(Path, MTE->getSubExpr(), Visit, true,
+ EnableLifetimeWarnings);
}
if (isa<CallExpr>(Init)) {
@@ -7067,9 +7071,8 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
}
} else if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L)) {
if (MTE->getType().isConstQualified())
- visitLocalsRetainedByInitializer(Path, MTE->GetTemporaryExpr(),
- Visit, true,
- EnableLifetimeWarnings);
+ visitLocalsRetainedByInitializer(Path, MTE->getSubExpr(), Visit,
+ true, EnableLifetimeWarnings);
}
return false;
}, EnableLifetimeWarnings);
@@ -7288,6 +7291,7 @@ static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I,
case IndirectLocalPathEntry::AddressOf:
case IndirectLocalPathEntry::LValToRVal:
case IndirectLocalPathEntry::LifetimeBoundCall:
+ case IndirectLocalPathEntry::GslReferenceInit:
case IndirectLocalPathEntry::GslPointerInit:
// These exist primarily to mark the path as not permitting or
// supporting lifetime extension.
@@ -7310,7 +7314,8 @@ static bool pathOnlyInitializesGslPointer(IndirectLocalPath &Path) {
continue;
if (It->Kind == IndirectLocalPathEntry::AddressOf)
continue;
- return It->Kind == IndirectLocalPathEntry::GslPointerInit;
+ return It->Kind == IndirectLocalPathEntry::GslPointerInit ||
+ It->Kind == IndirectLocalPathEntry::GslReferenceInit;
}
return false;
}
@@ -7533,6 +7538,7 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
case IndirectLocalPathEntry::LifetimeBoundCall:
case IndirectLocalPathEntry::GslPointerInit:
+ case IndirectLocalPathEntry::GslReferenceInit:
// FIXME: Consider adding a note for these.
break;
@@ -7835,9 +7841,8 @@ ExprResult InitializationSequence::Perform(Sema &S,
// OpenCL v2.0 s6.13.11.1. atomic variables can be initialized in global scope
QualType ETy = Entity.getType();
- Qualifiers TyQualifiers = ETy.getQualifiers();
- bool HasGlobalAS = TyQualifiers.hasAddressSpace() &&
- TyQualifiers.getAddressSpace() == LangAS::opencl_global;
+ bool HasGlobalAS = ETy.hasAddressSpace() &&
+ ETy.getAddressSpace() == LangAS::opencl_global;
if (S.getLangOpts().OpenCLVersion >= 200 &&
ETy->isAtomicType() && !HasGlobalAS &&
@@ -8806,7 +8811,7 @@ bool InitializationSequence::Diagnose(Sema &S,
: (S.PDiag(diag::err_ref_init_ambiguous)
<< DestType << OnlyArg->getType()
<< Args[0]->getSourceRange())),
- S, OCD_ViableCandidates, Args);
+ S, OCD_AmbiguousCandidates, Args);
break;
case OR_No_Viable_Function: {
@@ -8906,11 +8911,17 @@ bool InitializationSequence::Diagnose(Sema &S,
S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
<< NonRefType << SourceType << 1 /*addr space*/
<< Args[0]->getSourceRange();
- else
+ else if (DroppedQualifiers.hasQualifiers())
S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
<< NonRefType << SourceType << 0 /*cv quals*/
<< Qualifiers::fromCVRMask(DroppedQualifiers.getCVRQualifiers())
<< DroppedQualifiers.getCVRQualifiers() << Args[0]->getSourceRange();
+ else
+ // FIXME: Consider decomposing the type and explaining which qualifiers
+ // were dropped where, or on which level a 'const' is missing, etc.
+ S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
+ << NonRefType << SourceType << 2 /*incompatible quals*/
+ << Args[0]->getSourceRange();
break;
}
@@ -9000,7 +9011,7 @@ bool InitializationSequence::Diagnose(Sema &S,
PartialDiagnosticAt(Kind.getLocation(),
S.PDiag(diag::err_ovl_ambiguous_init)
<< DestType << ArgsRange),
- S, OCD_ViableCandidates, Args);
+ S, OCD_AmbiguousCandidates, Args);
break;
case OR_No_Viable_Function:
@@ -9765,9 +9776,8 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
// C++ [over.match.copy]p1: (non-list copy-initialization from class)
// The converting constructors of T are candidate functions.
if (!AllowExplicit) {
- // Only consider converting constructors.
- if (GD->isExplicit())
- continue;
+ // Overload resolution checks whether the deduction guide is declared
+ // explicit for us.
// When looking for a converting constructor, deduction guides that
// could never be called with one argument are not interesting to
@@ -9863,7 +9873,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
Kind.getLocation(),
PDiag(diag::err_deduced_class_template_ctor_ambiguous)
<< TemplateName),
- *this, OCD_ViableCandidates, Inits);
+ *this, OCD_AmbiguousCandidates, Inits);
return QualType();
case OR_No_Viable_Function: {
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index c6b19a0b195c..c2d14a44f53d 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -361,7 +361,8 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
TypeSourceInfo *MethodTypeInfo,
SourceLocation EndLoc,
ArrayRef<ParmVarDecl *> Params,
- ConstexprSpecKind ConstexprKind) {
+ ConstexprSpecKind ConstexprKind,
+ Expr *TrailingRequiresClause) {
QualType MethodType = MethodTypeInfo->getType();
TemplateParameterList *TemplateParams =
getGenericLambdaTemplateParameterList(getCurLambda(), *this);
@@ -395,7 +396,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
DeclarationNameInfo(MethodName, IntroducerRange.getBegin(),
MethodNameLoc),
MethodType, MethodTypeInfo, SC_None,
- /*isInline=*/true, ConstexprKind, EndLoc);
+ /*isInline=*/true, ConstexprKind, EndLoc, TrailingRequiresClause);
Method->setAccess(AS_public);
if (!TemplateParams)
Class->addDecl(Method);
@@ -917,6 +918,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
/*IsVariadic=*/false, /*IsCXXMethod=*/true));
EPI.HasTrailingReturn = true;
EPI.TypeQuals.addConst();
+ LangAS AS = getDefaultCXXMethodAddrSpace();
+ if (AS != LangAS::Default)
+ EPI.TypeQuals.addAddressSpace(AS);
+
// C++1y [expr.prim.lambda]:
// The lambda return type is 'auto', which is replaced by the
// trailing-return type if provided and/or deduced from 'return'
@@ -968,7 +973,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
KnownDependent, Intro.Default);
CXXMethodDecl *Method =
startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params,
- ParamInfo.getDeclSpec().getConstexprSpecifier());
+ ParamInfo.getDeclSpec().getConstexprSpecifier(),
+ ParamInfo.getTrailingRequiresClause());
if (ExplicitParams)
CheckCXXDefaultArguments(Method);
@@ -1248,7 +1254,7 @@ void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope,
SmallVector<Decl*, 4> Fields(Class->fields());
ActOnFields(nullptr, Class->getLocation(), Class, Fields, SourceLocation(),
SourceLocation(), ParsedAttributesView());
- CheckCompletedCXXClass(Class);
+ CheckCompletedCXXClass(nullptr, Class);
PopFunctionScopeInfo();
}
@@ -1794,7 +1800,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
SmallVector<Decl*, 4> Fields(Class->fields());
ActOnFields(nullptr, Class->getLocation(), Class, Fields, SourceLocation(),
SourceLocation(), ParsedAttributesView());
- CheckCompletedCXXClass(Class);
+ CheckCompletedCXXClass(nullptr, Class);
}
Cleanup.mergeFrom(LambdaCleanup);
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index d56c5980237c..0ed51de0cc13 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -739,6 +739,18 @@ static void GetOpenCLBuiltinFctOverloads(
}
}
+/// Add extensions to the function declaration.
+/// \param S (in/out) The Sema instance.
+/// \param BIDecl (in) Description of the builtin.
+/// \param FDecl (in/out) FunctionDecl instance.
+static void AddOpenCLExtensions(Sema &S, const OpenCLBuiltinStruct &BIDecl,
+ FunctionDecl *FDecl) {
+ // Fetch extension associated with a function prototype.
+ StringRef E = FunctionExtensionTable[BIDecl.Extension];
+ if (E != "")
+ S.setOpenCLExtensionForDecl(FDecl, E);
+}
+
/// When trying to resolve a function name, if isOpenCLBuiltin() returns a
/// non-null <Index, Len> pair, then the name is referencing an OpenCL
/// builtin function. Add all candidate signatures to the LookUpResult.
@@ -765,10 +777,13 @@ static void InsertOCLBuiltinDeclarationsFromTable(Sema &S, LookupResult &LR,
ASTContext &Context = S.Context;
// Ignore this BIF if its version does not match the language options.
- if (Context.getLangOpts().OpenCLVersion < OpenCLBuiltin.MinVersion)
+ unsigned OpenCLVersion = Context.getLangOpts().OpenCLVersion;
+ if (Context.getLangOpts().OpenCLCPlusPlus)
+ OpenCLVersion = 200;
+ if (OpenCLVersion < OpenCLBuiltin.MinVersion)
continue;
if ((OpenCLBuiltin.MaxVersion != 0) &&
- (Context.getLangOpts().OpenCLVersion >= OpenCLBuiltin.MaxVersion))
+ (OpenCLVersion >= OpenCLBuiltin.MaxVersion))
continue;
SmallVector<QualType, 1> RetTypes;
@@ -812,9 +827,20 @@ static void InsertOCLBuiltinDeclarationsFromTable(Sema &S, LookupResult &LR,
}
NewOpenCLBuiltin->setParams(ParmList);
}
- if (!S.getLangOpts().OpenCLCPlusPlus) {
+
+ // Add function attributes.
+ if (OpenCLBuiltin.IsPure)
+ NewOpenCLBuiltin->addAttr(PureAttr::CreateImplicit(Context));
+ if (OpenCLBuiltin.IsConst)
+ NewOpenCLBuiltin->addAttr(ConstAttr::CreateImplicit(Context));
+ if (OpenCLBuiltin.IsConv)
+ NewOpenCLBuiltin->addAttr(ConvergentAttr::CreateImplicit(Context));
+
+ if (!S.getLangOpts().OpenCLCPlusPlus)
NewOpenCLBuiltin->addAttr(OverloadableAttr::CreateImplicit(Context));
- }
+
+ AddOpenCLExtensions(S, OpenCLBuiltin, NewOpenCLBuiltin);
+
LR.addDecl(NewOpenCLBuiltin);
}
}
@@ -3101,11 +3127,10 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
});
}
CXXDestructorDecl *DD = RD->getDestructor();
- assert(DD && "record without a destructor");
Result->setMethod(DD);
- Result->setKind(DD->isDeleted() ?
- SpecialMemberOverloadResult::NoMemberOrDeleted :
- SpecialMemberOverloadResult::Success);
+ Result->setKind(DD && !DD->isDeleted()
+ ? SpecialMemberOverloadResult::Success
+ : SpecialMemberOverloadResult::NoMemberOrDeleted);
return *Result;
}
diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp
index 1fca351bfb09..10de0ca91221 100644
--- a/clang/lib/Sema/SemaModule.cpp
+++ b/clang/lib/Sema/SemaModule.cpp
@@ -31,8 +31,6 @@ static void checkModuleImportContext(Sema &S, Module *M,
ExternCLoc = LSD->getBeginLoc();
break;
case LinkageSpecDecl::lang_cxx:
- case LinkageSpecDecl::lang_cxx_11:
- case LinkageSpecDecl::lang_cxx_14:
break;
}
DC = LSD->getParent();
diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp
index ac810745d2f5..f6717f4cbe5e 100644
--- a/clang/lib/Sema/SemaObjCProperty.cpp
+++ b/clang/lib/Sema/SemaObjCProperty.cpp
@@ -306,6 +306,8 @@ makePropertyAttributesAsWritten(unsigned Attributes) {
attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_atomic;
if (Attributes & ObjCDeclSpec::DQ_PR_class)
attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_class;
+ if (Attributes & ObjCDeclSpec::DQ_PR_direct)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_direct;
return (ObjCPropertyDecl::PropertyAttributeKind)attributesAsWritten;
}
@@ -705,9 +707,21 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
if (Attributes & ObjCDeclSpec::DQ_PR_null_resettable)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_null_resettable);
- if (Attributes & ObjCDeclSpec::DQ_PR_class)
+ if (Attributes & ObjCDeclSpec::DQ_PR_class)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_class);
+ if ((Attributes & ObjCDeclSpec::DQ_PR_direct) ||
+ CDecl->hasAttr<ObjCDirectMembersAttr>()) {
+ if (isa<ObjCProtocolDecl>(CDecl)) {
+ Diag(PDecl->getLocation(), diag::err_objc_direct_on_protocol) << true;
+ } else if (getLangOpts().ObjCRuntime.allowsDirectDispatch()) {
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_direct);
+ } else {
+ Diag(PDecl->getLocation(), diag::warn_objc_direct_property_ignored)
+ << PDecl->getDeclName();
+ }
+ }
+
return PDecl;
}
@@ -1037,6 +1051,33 @@ static bool hasWrittenStorageAttribute(ObjCPropertyDecl *Prop,
return false;
}
+/// Create a synthesized property accessor stub inside the \@implementation.
+static ObjCMethodDecl *
+RedeclarePropertyAccessor(ASTContext &Context, ObjCImplementationDecl *Impl,
+ ObjCMethodDecl *AccessorDecl, SourceLocation AtLoc,
+ SourceLocation PropertyLoc) {
+ ObjCMethodDecl *Decl = AccessorDecl;
+ ObjCMethodDecl *ImplDecl = ObjCMethodDecl::Create(
+ Context, AtLoc.isValid() ? AtLoc : Decl->getBeginLoc(),
+ PropertyLoc.isValid() ? PropertyLoc : Decl->getEndLoc(),
+ Decl->getSelector(), Decl->getReturnType(),
+ Decl->getReturnTypeSourceInfo(), Impl, Decl->isInstanceMethod(),
+ Decl->isVariadic(), Decl->isPropertyAccessor(),
+ /* isSynthesized*/ true, Decl->isImplicit(), Decl->isDefined(),
+ Decl->getImplementationControl(), Decl->hasRelatedResultType());
+ ImplDecl->getMethodFamily();
+ if (Decl->hasAttrs())
+ ImplDecl->setAttrs(Decl->getAttrs());
+ ImplDecl->setSelfDecl(Decl->getSelfDecl());
+ ImplDecl->setCmdDecl(Decl->getCmdDecl());
+ SmallVector<SourceLocation, 1> SelLocs;
+ Decl->getSelectorLocs(SelLocs);
+ ImplDecl->setMethodParams(Context, Decl->parameters(), SelLocs);
+ ImplDecl->setLexicalDeclContext(Impl);
+ ImplDecl->setDefined(false);
+ return ImplDecl;
+}
+
/// ActOnPropertyImplDecl - This routine performs semantic checks and
/// builds the AST node for a property implementation declaration; declared
/// as \@synthesize or \@dynamic.
@@ -1404,6 +1445,18 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
if (ObjCMethodDecl *getterMethod = property->getGetterMethodDecl()) {
getterMethod->createImplicitParams(Context, IDecl);
+
+ // Redeclare the getter within the implementation as DeclContext.
+ if (Synthesize) {
+ // If the method hasn't been overridden, create a synthesized implementation.
+ ObjCMethodDecl *OMD = ClassImpDecl->getMethod(
+ getterMethod->getSelector(), getterMethod->isInstanceMethod());
+ if (!OMD)
+ OMD = RedeclarePropertyAccessor(Context, IC, getterMethod, AtLoc,
+ PropertyLoc);
+ PIDecl->setGetterMethodDecl(OMD);
+ }
+
if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr &&
Ivar->getType()->isRecordType()) {
// For Objective-C++, need to synthesize the AST for the IVAR object to be
@@ -1456,8 +1509,20 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
break;
}
}
+
if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) {
setterMethod->createImplicitParams(Context, IDecl);
+
+ // Redeclare the setter within the implementation as DeclContext.
+ if (Synthesize) {
+ ObjCMethodDecl *OMD = ClassImpDecl->getMethod(
+ setterMethod->getSelector(), setterMethod->isInstanceMethod());
+ if (!OMD)
+ OMD = RedeclarePropertyAccessor(Context, IC, setterMethod,
+ AtLoc, PropertyLoc);
+ PIDecl->setSetterMethodDecl(OMD);
+ }
+
if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr &&
Ivar->getType()->isRecordType()) {
// FIXME. Eventually we want to do this for Objective-C as well.
@@ -1852,10 +1917,12 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl,
if (IMPDecl->FindPropertyImplDecl(
Prop->getIdentifier(), Prop->getQueryKind()))
continue;
- if (IMPDecl->getInstanceMethod(Prop->getGetterName())) {
+ ObjCMethodDecl *ImpMethod = IMPDecl->getInstanceMethod(Prop->getGetterName());
+ if (ImpMethod && !ImpMethod->getBody()) {
if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readonly)
continue;
- if (IMPDecl->getInstanceMethod(Prop->getSetterName()))
+ ImpMethod = IMPDecl->getInstanceMethod(Prop->getSetterName());
+ if (ImpMethod && !ImpMethod->getBody())
continue;
}
if (ObjCPropertyImplDecl *PID =
@@ -2083,7 +2150,6 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
void Sema::diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl *impDecl) {
for (const auto *propertyImpl : impDecl->property_impls()) {
const auto *property = propertyImpl->getPropertyDecl();
-
// Warn about null_resettable properties with synthesized setters,
// because the setter won't properly handle nil.
if (propertyImpl->getPropertyImplementation()
@@ -2092,16 +2158,16 @@ void Sema::diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl *impDecl)
ObjCPropertyDecl::OBJC_PR_null_resettable) &&
property->getGetterMethodDecl() &&
property->getSetterMethodDecl()) {
- auto *getterMethod = property->getGetterMethodDecl();
- auto *setterMethod = property->getSetterMethodDecl();
- if (!impDecl->getInstanceMethod(setterMethod->getSelector()) &&
- !impDecl->getInstanceMethod(getterMethod->getSelector())) {
+ auto *getterImpl = propertyImpl->getGetterMethodDecl();
+ auto *setterImpl = propertyImpl->getSetterMethodDecl();
+ if ((!getterImpl || getterImpl->isSynthesizedAccessorStub()) &&
+ (!setterImpl || setterImpl->isSynthesizedAccessorStub())) {
SourceLocation loc = propertyImpl->getLocation();
if (loc.isInvalid())
loc = impDecl->getBeginLoc();
Diag(loc, diag::warn_null_resettable_setter)
- << setterMethod->getSelector() << property->getDeclName();
+ << setterImpl->getSelector() << property->getDeclName();
}
}
}
@@ -2125,7 +2191,6 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
const ObjCPropertyDecl *Property = I->second;
ObjCMethodDecl *GetterMethod = nullptr;
ObjCMethodDecl *SetterMethod = nullptr;
- bool LookedUpGetterSetter = false;
unsigned Attributes = Property->getPropertyAttributes();
unsigned AttributesAsWritten = Property->getPropertyAttributesAsWritten();
@@ -2138,7 +2203,10 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
SetterMethod = Property->isClassProperty() ?
IMPDecl->getClassMethod(Property->getSetterName()) :
IMPDecl->getInstanceMethod(Property->getSetterName());
- LookedUpGetterSetter = true;
+ if (GetterMethod && GetterMethod->isSynthesizedAccessorStub())
+ GetterMethod = nullptr;
+ if (SetterMethod && SetterMethod->isSynthesizedAccessorStub())
+ SetterMethod = nullptr;
if (GetterMethod) {
Diag(GetterMethod->getLocation(),
diag::warn_default_atomic_custom_getter_setter)
@@ -2161,15 +2229,13 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
Property->getIdentifier(), Property->getQueryKind())) {
if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
continue;
- if (!LookedUpGetterSetter) {
- GetterMethod = Property->isClassProperty() ?
- IMPDecl->getClassMethod(Property->getGetterName()) :
- IMPDecl->getInstanceMethod(Property->getGetterName());
- SetterMethod = Property->isClassProperty() ?
- IMPDecl->getClassMethod(Property->getSetterName()) :
- IMPDecl->getInstanceMethod(Property->getSetterName());
- }
- if ((GetterMethod && !SetterMethod) || (!GetterMethod && SetterMethod)) {
+ GetterMethod = PIDecl->getGetterMethodDecl();
+ SetterMethod = PIDecl->getSetterMethodDecl();
+ if (GetterMethod && GetterMethod->isSynthesizedAccessorStub())
+ GetterMethod = nullptr;
+ if (SetterMethod && SetterMethod->isSynthesizedAccessorStub())
+ SetterMethod = nullptr;
+ if ((bool)GetterMethod ^ (bool)SetterMethod) {
SourceLocation MethodLoc =
(GetterMethod ? GetterMethod->getLocation()
: SetterMethod->getLocation());
@@ -2210,8 +2276,10 @@ void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D
for (const auto *PID : D->property_impls()) {
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
if (PD && !PD->hasAttr<NSReturnsNotRetainedAttr>() &&
- !PD->isClassProperty() &&
- !D->getInstanceMethod(PD->getGetterName())) {
+ !PD->isClassProperty()) {
+ ObjCMethodDecl *IM = PID->getGetterMethodDecl();
+ if (IM && !IM->isSynthesizedAccessorStub())
+ continue;
ObjCMethodDecl *method = PD->getGetterMethodDecl();
if (!method)
continue;
@@ -2396,20 +2464,21 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
}
}
- GetterMethod = ObjCMethodDecl::Create(Context, Loc, Loc,
- property->getGetterName(),
- resultTy, nullptr, CD,
- !IsClassProperty, /*isVariadic=*/false,
- /*isPropertyAccessor=*/true,
- /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
- (property->getPropertyImplementation() ==
- ObjCPropertyDecl::Optional) ?
- ObjCMethodDecl::Optional :
- ObjCMethodDecl::Required);
+ GetterMethod = ObjCMethodDecl::Create(
+ Context, Loc, Loc, property->getGetterName(), resultTy, nullptr, CD,
+ !IsClassProperty, /*isVariadic=*/false,
+ /*isPropertyAccessor=*/true, /*isSynthesizedAccessorStub=*/false,
+ /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
+ (property->getPropertyImplementation() == ObjCPropertyDecl::Optional)
+ ? ObjCMethodDecl::Optional
+ : ObjCMethodDecl::Required);
CD->addDecl(GetterMethod);
AddPropertyAttrs(*this, GetterMethod, property);
+ if (property->isDirectProperty())
+ GetterMethod->addAttr(ObjCDirectAttr::CreateImplicit(Context, Loc));
+
if (property->hasAttr<NSReturnsNotRetainedAttr>())
GetterMethod->addAttr(NSReturnsNotRetainedAttr::CreateImplicit(Context,
Loc));
@@ -2429,6 +2498,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
// A user declared getter will be synthesize when @synthesize of
// the property with the same name is seen in the @implementation
GetterMethod->setPropertyAccessor(true);
+
+ GetterMethod->createImplicitParams(Context,
+ GetterMethod->getClassInterface());
property->setGetterMethodDecl(GetterMethod);
// Skip setter if property is read-only.
@@ -2447,6 +2519,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
nullptr, CD, !IsClassProperty,
/*isVariadic=*/false,
/*isPropertyAccessor=*/true,
+ /*isSynthesizedAccessorStub=*/false,
/*isImplicitlyDeclared=*/true,
/*isDefined=*/false,
(property->getPropertyImplementation() ==
@@ -2483,6 +2556,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
AddPropertyAttrs(*this, SetterMethod, property);
+ if (property->isDirectProperty())
+ SetterMethod->addAttr(ObjCDirectAttr::CreateImplicit(Context, Loc));
+
CD->addDecl(SetterMethod);
if (const SectionAttr *SA = property->getAttr<SectionAttr>())
SetterMethod->addAttr(SectionAttr::CreateImplicit(
@@ -2496,6 +2572,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
// A user declared setter will be synthesize when @synthesize of
// the property with the same name is seen in the @implementation
SetterMethod->setPropertyAccessor(true);
+
+ SetterMethod->createImplicitParams(Context,
+ SetterMethod->getClassInterface());
property->setSetterMethodDecl(SetterMethod);
}
// Add any synthesized methods to the global pool. This allows us to
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index c7e0d2aee036..3fce0e27e9b3 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -23,13 +23,17 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/OpenMPKinds.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
+#include "llvm/ADT/IndexedMap.h"
#include "llvm/ADT/PointerEmbeddedInt.h"
+#include "llvm/Frontend/OpenMP/OMPConstants.h"
using namespace clang;
+using namespace llvm::omp;
//===----------------------------------------------------------------------===//
// Stack of data-sharing attributes for variables
@@ -48,12 +52,6 @@ enum DefaultDataSharingAttributes {
DSA_shared = 1 << 1, /// Default data sharing attribute 'shared'.
};
-/// Attributes of the defaultmap clause.
-enum DefaultMapAttributes {
- DMA_unspecified, /// Default mapping is not specified.
- DMA_tofrom_scalar, /// Default mapping is 'tofrom:scalar'.
-};
-
/// Stack for tracking declarations used in OpenMP directives and
/// clauses and their data-sharing attributes.
class DSAStackTy {
@@ -85,7 +83,7 @@ private:
DeclRefExpr *PrivateCopy = nullptr;
};
using DeclSAMapTy = llvm::SmallDenseMap<const ValueDecl *, DSAInfo, 8>;
- using AlignedMapTy = llvm::SmallDenseMap<const ValueDecl *, const Expr *, 8>;
+ using UsedRefMapTy = llvm::SmallDenseMap<const ValueDecl *, const Expr *, 8>;
using LCDeclInfo = std::pair<unsigned, VarDecl *>;
using LoopControlVariablesMapTy =
llvm::SmallDenseMap<const ValueDecl *, LCDeclInfo, 8>;
@@ -115,17 +113,25 @@ private:
};
using DeclReductionMapTy =
llvm::SmallDenseMap<const ValueDecl *, ReductionData, 4>;
+ struct DefaultmapInfo {
+ OpenMPDefaultmapClauseModifier ImplicitBehavior =
+ OMPC_DEFAULTMAP_MODIFIER_unknown;
+ SourceLocation SLoc;
+ DefaultmapInfo() = default;
+ DefaultmapInfo(OpenMPDefaultmapClauseModifier M, SourceLocation Loc)
+ : ImplicitBehavior(M), SLoc(Loc) {}
+ };
struct SharingMapTy {
DeclSAMapTy SharingMap;
DeclReductionMapTy ReductionMap;
- AlignedMapTy AlignedMap;
+ UsedRefMapTy AlignedMap;
+ UsedRefMapTy NontemporalMap;
MappedExprComponentsTy MappedExprComponents;
LoopControlVariablesMapTy LCVMap;
DefaultDataSharingAttributes DefaultAttr = DSA_unspecified;
SourceLocation DefaultAttrLoc;
- DefaultMapAttributes DefaultMapAttr = DMA_unspecified;
- SourceLocation DefaultMapAttrLoc;
+ DefaultmapInfo DefaultmapMap[OMPC_DEFAULTMAP_unknown];
OpenMPDirectiveKind Directive = OMPD_unknown;
DeclarationNameInfo DirectiveName;
Scope *CurScope = nullptr;
@@ -416,6 +422,10 @@ public:
/// add it and return NULL; otherwise return previous occurrence's expression
/// for diagnostics.
const Expr *addUniqueAligned(const ValueDecl *D, const Expr *NewDE);
+ /// If 'nontemporal' declaration for given variable \a D was not seen yet,
+ /// add it and return NULL; otherwise return previous occurrence's expression
+ /// for diagnostics.
+ const Expr *addUniqueNontemporal(const ValueDecl *D, const Expr *NewDE);
/// Register specified variable as loop control variable.
void addLoopControlVariable(const ValueDecl *D, VarDecl *Capture);
@@ -592,10 +602,18 @@ public:
getTopOfStack().DefaultAttr = DSA_shared;
getTopOfStack().DefaultAttrLoc = Loc;
}
- /// Set default data mapping attribute to 'tofrom:scalar'.
- void setDefaultDMAToFromScalar(SourceLocation Loc) {
- getTopOfStack().DefaultMapAttr = DMA_tofrom_scalar;
- getTopOfStack().DefaultMapAttrLoc = Loc;
+ /// Set default data mapping attribute to Modifier:Kind
+ void setDefaultDMAAttr(OpenMPDefaultmapClauseModifier M,
+ OpenMPDefaultmapClauseKind Kind,
+ SourceLocation Loc) {
+ DefaultmapInfo &DMI = getTopOfStack().DefaultmapMap[Kind];
+ DMI.ImplicitBehavior = M;
+ DMI.SLoc = Loc;
+ }
+ /// Check whether the implicit-behavior has been set in defaultmap
+ bool checkDefaultmapCategory(OpenMPDefaultmapClauseKind VariableCategory) {
+ return getTopOfStack().DefaultmapMap[VariableCategory].ImplicitBehavior !=
+ OMPC_DEFAULTMAP_MODIFIER_unknown;
}
DefaultDataSharingAttributes getDefaultDSA() const {
@@ -606,16 +624,53 @@ public:
return isStackEmpty() ? SourceLocation()
: getTopOfStack().DefaultAttrLoc;
}
- DefaultMapAttributes getDefaultDMA() const {
- return isStackEmpty() ? DMA_unspecified
- : getTopOfStack().DefaultMapAttr;
+ OpenMPDefaultmapClauseModifier
+ getDefaultmapModifier(OpenMPDefaultmapClauseKind Kind) const {
+ return isStackEmpty()
+ ? OMPC_DEFAULTMAP_MODIFIER_unknown
+ : getTopOfStack().DefaultmapMap[Kind].ImplicitBehavior;
}
- DefaultMapAttributes getDefaultDMAAtLevel(unsigned Level) const {
- return getStackElemAtLevel(Level).DefaultMapAttr;
+ OpenMPDefaultmapClauseModifier
+ getDefaultmapModifierAtLevel(unsigned Level,
+ OpenMPDefaultmapClauseKind Kind) const {
+ return getStackElemAtLevel(Level).DefaultmapMap[Kind].ImplicitBehavior;
}
- SourceLocation getDefaultDMALocation() const {
- return isStackEmpty() ? SourceLocation()
- : getTopOfStack().DefaultMapAttrLoc;
+ bool isDefaultmapCapturedByRef(unsigned Level,
+ OpenMPDefaultmapClauseKind Kind) const {
+ OpenMPDefaultmapClauseModifier M =
+ getDefaultmapModifierAtLevel(Level, Kind);
+ if (Kind == OMPC_DEFAULTMAP_scalar || Kind == OMPC_DEFAULTMAP_pointer) {
+ return (M == OMPC_DEFAULTMAP_MODIFIER_alloc) ||
+ (M == OMPC_DEFAULTMAP_MODIFIER_to) ||
+ (M == OMPC_DEFAULTMAP_MODIFIER_from) ||
+ (M == OMPC_DEFAULTMAP_MODIFIER_tofrom);
+ }
+ return true;
+ }
+ static bool mustBeFirstprivateBase(OpenMPDefaultmapClauseModifier M,
+ OpenMPDefaultmapClauseKind Kind) {
+ switch (Kind) {
+ case OMPC_DEFAULTMAP_scalar:
+ case OMPC_DEFAULTMAP_pointer:
+ return (M == OMPC_DEFAULTMAP_MODIFIER_unknown) ||
+ (M == OMPC_DEFAULTMAP_MODIFIER_firstprivate) ||
+ (M == OMPC_DEFAULTMAP_MODIFIER_default);
+ case OMPC_DEFAULTMAP_aggregate:
+ return M == OMPC_DEFAULTMAP_MODIFIER_firstprivate;
+ default:
+ break;
+ }
+ llvm_unreachable("Unexpected OpenMPDefaultmapClauseKind enum");
+ }
+ bool mustBeFirstprivateAtLevel(unsigned Level,
+ OpenMPDefaultmapClauseKind Kind) const {
+ OpenMPDefaultmapClauseModifier M =
+ getDefaultmapModifierAtLevel(Level, Kind);
+ return mustBeFirstprivateBase(M, Kind);
+ }
+ bool mustBeFirstprivate(OpenMPDefaultmapClauseKind Kind) const {
+ OpenMPDefaultmapClauseModifier M = getDefaultmapModifier(Kind);
+ return mustBeFirstprivateBase(M, Kind);
}
/// Checks if the specified variable is a threadprivate.
@@ -862,7 +917,7 @@ static const Expr *getExprAsWritten(const Expr *E) {
E = FE->getSubExpr();
if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
- E = MTE->GetTemporaryExpr();
+ E = MTE->getSubExpr();
while (const auto *Binder = dyn_cast<CXXBindTemporaryExpr>(E))
E = Binder->getSubExpr();
@@ -1023,6 +1078,21 @@ const Expr *DSAStackTy::addUniqueAligned(const ValueDecl *D,
return It->second;
}
+const Expr *DSAStackTy::addUniqueNontemporal(const ValueDecl *D,
+ const Expr *NewDE) {
+ assert(!isStackEmpty() && "Data sharing attributes stack is empty");
+ D = getCanonicalDecl(D);
+ SharingMapTy &StackElem = getTopOfStack();
+ auto It = StackElem.NontemporalMap.find(D);
+ if (It == StackElem.NontemporalMap.end()) {
+ assert(NewDE && "Unexpected nullptr expr to be added into aligned map");
+ StackElem.NontemporalMap[D] = NewDE;
+ return nullptr;
+ }
+ assert(It->second && "Unexpected nullptr expr in the aligned map");
+ return It->second;
+}
+
void DSAStackTy::addLoopControlVariable(const ValueDecl *D, VarDecl *Capture) {
assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
D = getCanonicalDecl(D);
@@ -1716,6 +1786,20 @@ void Sema::checkOpenMPDeviceExpr(const Expr *E) {
<< Context.getTargetInfo().getTriple().str() << E->getSourceRange();
}
+static OpenMPDefaultmapClauseKind
+getVariableCategoryFromDecl(const LangOptions &LO, const ValueDecl *VD) {
+ if (LO.OpenMP <= 45) {
+ if (VD->getType().getNonReferenceType()->isScalarType())
+ return OMPC_DEFAULTMAP_scalar;
+ return OMPC_DEFAULTMAP_aggregate;
+ }
+ if (VD->getType().getNonReferenceType()->isAnyPointerType())
+ return OMPC_DEFAULTMAP_pointer;
+ if (VD->getType().getNonReferenceType()->isScalarType())
+ return OMPC_DEFAULTMAP_scalar;
+ return OMPC_DEFAULTMAP_aggregate;
+}
+
bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level,
unsigned OpenMPCaptureLevel) const {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
@@ -1834,11 +1918,13 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level,
} else {
// By default, all the data that has a scalar type is mapped by copy
// (except for reduction variables).
+ // Defaultmap scalar is mutual exclusive to defaultmap pointer
IsByRef =
(DSAStack->isForceCaptureByReferenceInTargetExecutable() &&
!Ty->isAnyPointerType()) ||
!Ty->isScalarType() ||
- DSAStack->getDefaultDMAAtLevel(Level) == DMA_tofrom_scalar ||
+ DSAStack->isDefaultmapCapturedByRef(
+ Level, getVariableCategoryFromDecl(LangOpts, D)) ||
DSAStack->hasExplicitDSA(
D, [](OpenMPClauseKind K) { return K == OMPC_reduction; }, Level);
}
@@ -1894,6 +1980,11 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo,
assert(LangOpts.OpenMP && "OpenMP is not allowed");
D = getCanonicalDecl(D);
+ auto *VD = dyn_cast<VarDecl>(D);
+ // Do not capture constexpr variables.
+ if (VD && VD->isConstexpr())
+ return nullptr;
+
// If we want to determine whether the variable should be captured from the
// perspective of the current capturing scope, and we've already left all the
// capturing scopes of the top directive on the stack, check from the
@@ -1904,7 +1995,6 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo,
// If we are attempting to capture a global variable in a directive with
// 'target' we return true so that this global is also mapped to the device.
//
- auto *VD = dyn_cast<VarDecl>(D);
if (VD && !VD->hasLocalStorage() &&
(getCurCapturedRegion() || getCurBlock() || getCurLambda())) {
if (isInOpenMPDeclareTargetContext()) {
@@ -2051,9 +2141,8 @@ void Sema::setOpenMPCaptureKind(FieldDecl *FD, const ValueDecl *D,
if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective,
NewLevel)) {
OMPC = OMPC_map;
- if (D->getType()->isScalarType() &&
- DSAStack->getDefaultDMAAtLevel(NewLevel) !=
- DefaultMapAttributes::DMA_tofrom_scalar)
+ if (DSAStack->mustBeFirstprivateAtLevel(
+ NewLevel, getVariableCategoryFromDecl(LangOpts, D)))
OMPC = OMPC_firstprivate;
break;
}
@@ -2141,6 +2230,11 @@ void Sema::EndOpenMPClause() {
static void checkAllocateClauses(Sema &S, DSAStackTy *Stack,
ArrayRef<OMPClause *> Clauses);
+static std::pair<ValueDecl *, bool>
+getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc,
+ SourceRange &ERange, bool AllowArraySection = false);
+static DeclRefExpr *buildCapture(Sema &S, ValueDecl *D, Expr *CaptureExpr,
+ bool WithInit);
void Sema::EndOpenMPDSABlock(Stmt *CurDirective) {
// OpenMP [2.14.3.5, Restrictions, C/C++, p.1]
@@ -2185,6 +2279,31 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) {
}
}
Clause->setPrivateCopies(PrivateCopies);
+ continue;
+ }
+ // Finalize nontemporal clause by handling private copies, if any.
+ if (auto *Clause = dyn_cast<OMPNontemporalClause>(C)) {
+ SmallVector<Expr *, 8> PrivateRefs;
+ for (Expr *RefExpr : Clause->varlists()) {
+ assert(RefExpr && "NULL expr in OpenMP nontemporal clause.");
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
+ if (Res.second)
+ // It will be analyzed later.
+ PrivateRefs.push_back(RefExpr);
+ ValueDecl *D = Res.first;
+ if (!D)
+ continue;
+
+ const DSAStackTy::DSAVarData DVar =
+ DSAStack->getTopDSA(D, /*FromParent=*/false);
+ PrivateRefs.push_back(DVar.PrivateCopy ? DVar.PrivateCopy
+ : SimpleRefExpr);
+ }
+ Clause->setPrivateRefs(PrivateRefs);
+ continue;
}
}
// Check allocate clauses.
@@ -2759,14 +2878,51 @@ static void reportOriginalDsa(Sema &SemaRef, const DSAStackTy *Stack,
}
}
+static OpenMPMapClauseKind
+getMapClauseKindFromModifier(OpenMPDefaultmapClauseModifier M,
+ bool IsAggregateOrDeclareTarget) {
+ OpenMPMapClauseKind Kind = OMPC_MAP_unknown;
+ switch (M) {
+ case OMPC_DEFAULTMAP_MODIFIER_alloc:
+ Kind = OMPC_MAP_alloc;
+ break;
+ case OMPC_DEFAULTMAP_MODIFIER_to:
+ Kind = OMPC_MAP_to;
+ break;
+ case OMPC_DEFAULTMAP_MODIFIER_from:
+ Kind = OMPC_MAP_from;
+ break;
+ case OMPC_DEFAULTMAP_MODIFIER_tofrom:
+ Kind = OMPC_MAP_tofrom;
+ break;
+ case OMPC_DEFAULTMAP_MODIFIER_firstprivate:
+ case OMPC_DEFAULTMAP_MODIFIER_last:
+ llvm_unreachable("Unexpected defaultmap implicit behavior");
+ case OMPC_DEFAULTMAP_MODIFIER_none:
+ case OMPC_DEFAULTMAP_MODIFIER_default:
+ case OMPC_DEFAULTMAP_MODIFIER_unknown:
+ // IsAggregateOrDeclareTarget could be true if:
+ // 1. the implicit behavior for aggregate is tofrom
+ // 2. it's a declare target link
+ if (IsAggregateOrDeclareTarget) {
+ Kind = OMPC_MAP_tofrom;
+ break;
+ }
+ llvm_unreachable("Unexpected defaultmap implicit behavior");
+ }
+ assert(Kind != OMPC_MAP_unknown && "Expect map kind to be known");
+ return Kind;
+}
+
namespace {
class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
DSAStackTy *Stack;
Sema &SemaRef;
bool ErrorFound = false;
+ bool TryCaptureCXXThisMembers = false;
CapturedStmt *CS = nullptr;
llvm::SmallVector<Expr *, 4> ImplicitFirstprivate;
- llvm::SmallVector<Expr *, 4> ImplicitMap;
+ llvm::SmallVector<Expr *, 4> ImplicitMap[OMPC_MAP_delete];
Sema::VarsWithInheritedDSAType VarsWithInheritedDSA;
llvm::SmallDenseSet<const ValueDecl *, 4> ImplicitDeclarations;
@@ -2775,12 +2931,26 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
if (!S->hasAssociatedStmt() || !S->getAssociatedStmt())
return;
visitSubCaptures(S->getInnermostCapturedStmt());
+ // Try to capture inner this->member references to generate correct mappings
+ // and diagnostics.
+ if (TryCaptureCXXThisMembers ||
+ (isOpenMPTargetExecutionDirective(Stack->getCurrentDirective()) &&
+ llvm::any_of(S->getInnermostCapturedStmt()->captures(),
+ [](const CapturedStmt::Capture &C) {
+ return C.capturesThis();
+ }))) {
+ bool SavedTryCaptureCXXThisMembers = TryCaptureCXXThisMembers;
+ TryCaptureCXXThisMembers = true;
+ Visit(S->getInnermostCapturedStmt()->getCapturedStmt());
+ TryCaptureCXXThisMembers = SavedTryCaptureCXXThisMembers;
+ }
}
public:
void VisitDeclRefExpr(DeclRefExpr *E) {
- if (E->isTypeDependent() || E->isValueDependent() ||
- E->containsUnexpandedParameterPack() || E->isInstantiationDependent())
+ if (TryCaptureCXXThisMembers || E->isTypeDependent() ||
+ E->isValueDependent() || E->containsUnexpandedParameterPack() ||
+ E->isInstantiationDependent())
return;
if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) {
// Check the datasharing rules for the expressions in the clauses.
@@ -2825,6 +2995,39 @@ public:
return;
}
+ // OpenMP 5.0 [2.19.7.2, defaultmap clause, Description]
+ // If implicit-behavior is none, each variable referenced in the
+ // construct that does not have a predetermined data-sharing attribute
+ // and does not appear in a to or link clause on a declare target
+ // directive must be listed in a data-mapping attribute clause, a
+ // data-haring attribute clause (including a data-sharing attribute
+ // clause on a combined construct where target. is one of the
+ // constituent constructs), or an is_device_ptr clause.
+ OpenMPDefaultmapClauseKind ClauseKind =
+ getVariableCategoryFromDecl(SemaRef.getLangOpts(), VD);
+ if (SemaRef.getLangOpts().OpenMP >= 50) {
+ bool IsModifierNone = Stack->getDefaultmapModifier(ClauseKind) ==
+ OMPC_DEFAULTMAP_MODIFIER_none;
+ if (DVar.CKind == OMPC_unknown && IsModifierNone &&
+ VarsWithInheritedDSA.count(VD) == 0 && !Res) {
+ // Only check for data-mapping attribute and is_device_ptr here
+ // since we have already make sure that the declaration does not
+ // have a data-sharing attribute above
+ if (!Stack->checkMappableExprComponentListsForDecl(
+ VD, /*CurrentRegionOnly=*/true,
+ [VD](OMPClauseMappableExprCommon::MappableExprComponentListRef
+ MapExprComponents,
+ OpenMPClauseKind) {
+ auto MI = MapExprComponents.rbegin();
+ auto ME = MapExprComponents.rend();
+ return MI != ME && MI->getAssociatedDeclaration() == VD;
+ })) {
+ VarsWithInheritedDSA[VD] = E;
+ return;
+ }
+ }
+ }
+
if (isOpenMPTargetExecutionDirective(DKind) &&
!Stack->isLoopControlVariable(VD).first) {
if (!Stack->checkMappableExprComponentListsForDecl(
@@ -2854,13 +3057,16 @@ public:
VD->getType().getNonReferenceType()->getAsCXXRecordDecl())
IsFirstprivate = RD->isLambda();
IsFirstprivate =
- IsFirstprivate ||
- (VD->getType().getNonReferenceType()->isScalarType() &&
- Stack->getDefaultDMA() != DMA_tofrom_scalar && !Res);
- if (IsFirstprivate)
+ IsFirstprivate || (Stack->mustBeFirstprivate(ClauseKind) && !Res);
+ if (IsFirstprivate) {
ImplicitFirstprivate.emplace_back(E);
- else
- ImplicitMap.emplace_back(E);
+ } else {
+ OpenMPDefaultmapClauseModifier M =
+ Stack->getDefaultmapModifier(ClauseKind);
+ OpenMPMapClauseKind Kind = getMapClauseKindFromModifier(
+ M, ClauseKind == OMPC_DEFAULTMAP_aggregate || Res);
+ ImplicitMap[Kind].emplace_back(E);
+ }
return;
}
}
@@ -2939,7 +3145,11 @@ public:
if (Stack->isClassPreviouslyMapped(TE->getType()))
return;
- ImplicitMap.emplace_back(E);
+ OpenMPDefaultmapClauseModifier Modifier =
+ Stack->getDefaultmapModifier(OMPC_DEFAULTMAP_aggregate);
+ OpenMPMapClauseKind Kind = getMapClauseKindFromModifier(
+ Modifier, /*IsAggregateOrDeclareTarget*/ true);
+ ImplicitMap[Kind].emplace_back(E);
return;
}
@@ -3014,7 +3224,7 @@ public:
})) {
Visit(E->getBase());
}
- } else {
+ } else if (!TryCaptureCXXThisMembers) {
Visit(E->getBase());
}
}
@@ -3068,7 +3278,9 @@ public:
ArrayRef<Expr *> getImplicitFirstprivate() const {
return ImplicitFirstprivate;
}
- ArrayRef<Expr *> getImplicitMap() const { return ImplicitMap; }
+ ArrayRef<Expr *> getImplicitMap(OpenMPDefaultmapClauseKind Kind) const {
+ return ImplicitMap[Kind];
+ }
const Sema::VarsWithInheritedDSAType &getVarsWithInheritedDSA() const {
return VarsWithInheritedDSA;
}
@@ -3090,6 +3302,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
case OMPD_parallel_sections:
+ case OMPD_parallel_master:
case OMPD_teams:
case OMPD_teams_distribute:
case OMPD_teams_distribute_simd: {
@@ -3282,7 +3495,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
AlwaysInlineAttr::Keyword_forceinline));
break;
}
- case OMPD_parallel_master_taskloop: {
+ case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_master_taskloop_simd: {
QualType KmpInt32Ty =
Context.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1)
.withConst();
@@ -3779,7 +3993,10 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
ShouldBeInTargetRegion,
ShouldBeInTeamsRegion
} Recommend = NoRecommend;
- if (isOpenMPSimdDirective(ParentRegion) && CurrentRegion != OMPD_ordered) {
+ if (isOpenMPSimdDirective(ParentRegion) &&
+ ((SemaRef.LangOpts.OpenMP <= 45 && CurrentRegion != OMPD_ordered) ||
+ (SemaRef.LangOpts.OpenMP >= 50 && CurrentRegion != OMPD_ordered &&
+ CurrentRegion != OMPD_simd && CurrentRegion != OMPD_atomic))) {
// OpenMP [2.16, Nesting of Regions]
// OpenMP constructs may not be nested inside a simd region.
// OpenMP [2.8.1,simd Construct, Restrictions]
@@ -3788,9 +4005,14 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
// Allowing a SIMD construct nested in another SIMD construct is an
// extension. The OpenMP 4.5 spec does not allow it. Issue a warning
// message.
+ // OpenMP 5.0 [2.9.3.1, simd Construct, Restrictions]
+ // The only OpenMP constructs that can be encountered during execution of
+ // a simd region are the atomic construct, the loop construct, the simd
+ // construct and the ordered construct with the simd clause.
SemaRef.Diag(StartLoc, (CurrentRegion != OMPD_simd)
? diag::err_omp_prohibited_region_simd
- : diag::warn_omp_nesting_simd);
+ : diag::warn_omp_nesting_simd)
+ << (SemaRef.LangOpts.OpenMP >= 50 ? 1 : 0);
return CurrentRegion != OMPD_simd;
}
if (ParentRegion == OMPD_atomic) {
@@ -3888,6 +4110,7 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) ||
isOpenMPTaskingDirective(ParentRegion) ||
ParentRegion == OMPD_master ||
+ ParentRegion == OMPD_parallel_master ||
ParentRegion == OMPD_critical ||
ParentRegion == OMPD_ordered;
} else if (isOpenMPWorksharingDirective(CurrentRegion) &&
@@ -3899,6 +4122,7 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) ||
isOpenMPTaskingDirective(ParentRegion) ||
ParentRegion == OMPD_master ||
+ ParentRegion == OMPD_parallel_master ||
ParentRegion == OMPD_critical ||
ParentRegion == OMPD_ordered;
Recommend = ShouldBeInParallelRegion;
@@ -3982,13 +4206,17 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
return false;
}
+struct Kind2Unsigned {
+ using argument_type = OpenMPDirectiveKind;
+ unsigned operator()(argument_type DK) { return unsigned(DK); }
+};
static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind,
ArrayRef<OMPClause *> Clauses,
ArrayRef<OpenMPDirectiveKind> AllowedNameModifiers) {
bool ErrorFound = false;
unsigned NamedModifiersNumber = 0;
- SmallVector<const OMPIfClause *, OMPC_unknown + 1> FoundNameModifiers(
- OMPD_unknown + 1);
+ llvm::IndexedMap<const OMPIfClause *, Kind2Unsigned> FoundNameModifiers;
+ FoundNameModifiers.resize(unsigned(OMPD_unknown) + 1);
SmallVector<SourceLocation, 4> NameModifierLoc;
for (const OMPClause *C : Clauses) {
if (const auto *IC = dyn_cast_or_null<OMPIfClause>(C)) {
@@ -4064,9 +4292,10 @@ static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind,
return ErrorFound;
}
-static std::pair<ValueDecl *, bool>
-getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc,
- SourceRange &ERange, bool AllowArraySection = false) {
+static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr,
+ SourceLocation &ELoc,
+ SourceRange &ERange,
+ bool AllowArraySection) {
if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() ||
RefExpr->containsUnexpandedParameterPack())
return std::make_pair(nullptr, true);
@@ -4271,8 +4500,12 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
SmallVector<Expr *, 4> ImplicitFirstprivates(
DSAChecker.getImplicitFirstprivate().begin(),
DSAChecker.getImplicitFirstprivate().end());
- SmallVector<Expr *, 4> ImplicitMaps(DSAChecker.getImplicitMap().begin(),
- DSAChecker.getImplicitMap().end());
+ SmallVector<Expr *, 4> ImplicitMaps[OMPC_MAP_delete];
+ for (unsigned I = 0; I < OMPC_MAP_delete; ++I) {
+ ArrayRef<Expr *> ImplicitMap =
+ DSAChecker.getImplicitMap(static_cast<OpenMPDefaultmapClauseKind>(I));
+ ImplicitMaps[I].append(ImplicitMap.begin(), ImplicitMap.end());
+ }
// Mark taskgroup task_reduction descriptors as implicitly firstprivate.
for (OMPClause *C : Clauses) {
if (auto *IRC = dyn_cast<OMPInReductionClause>(C)) {
@@ -4292,16 +4525,21 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
ErrorFound = true;
}
}
- if (!ImplicitMaps.empty()) {
+ int ClauseKindCnt = -1;
+ for (ArrayRef<Expr *> ImplicitMap : ImplicitMaps) {
+ ++ClauseKindCnt;
+ if (ImplicitMap.empty())
+ continue;
CXXScopeSpec MapperIdScopeSpec;
DeclarationNameInfo MapperId;
+ auto Kind = static_cast<OpenMPMapClauseKind>(ClauseKindCnt);
if (OMPClause *Implicit = ActOnOpenMPMapClause(
- llvm::None, llvm::None, MapperIdScopeSpec, MapperId,
- OMPC_MAP_tofrom, /*IsMapTypeImplicit=*/true, SourceLocation(),
- SourceLocation(), ImplicitMaps, OMPVarListLocTy())) {
+ llvm::None, llvm::None, MapperIdScopeSpec, MapperId, Kind,
+ /*IsMapTypeImplicit=*/true, SourceLocation(), SourceLocation(),
+ ImplicitMap, OMPVarListLocTy())) {
ClausesWithImplicit.emplace_back(Implicit);
ErrorFound |=
- cast<OMPMapClause>(Implicit)->varlist_size() != ImplicitMaps.size();
+ cast<OMPMapClause>(Implicit)->varlist_size() != ImplicitMap.size();
} else {
ErrorFound = true;
}
@@ -4318,6 +4556,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPD_simd:
Res = ActOnOpenMPSimdDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc,
VarsWithInheritedDSA);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
break;
case OMPD_for:
Res = ActOnOpenMPForDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc,
@@ -4326,6 +4566,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPD_for_simd:
Res = ActOnOpenMPForSimdDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc, VarsWithInheritedDSA);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
break;
case OMPD_sections:
Res = ActOnOpenMPSectionsDirective(ClausesWithImplicit, AStmt, StartLoc,
@@ -4358,6 +4600,13 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
Res = ActOnOpenMPParallelForSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_parallel);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
+ break;
+ case OMPD_parallel_master:
+ Res = ActOnOpenMPParallelMasterDirective(ClausesWithImplicit, AStmt,
+ StartLoc, EndLoc);
+ AllowedNameModifiers.push_back(OMPD_parallel);
break;
case OMPD_parallel_sections:
Res = ActOnOpenMPParallelSectionsDirective(ClausesWithImplicit, AStmt,
@@ -4466,6 +4715,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
Res = ActOnOpenMPTaskLoopSimdDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_taskloop);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
break;
case OMPD_master_taskloop:
Res = ActOnOpenMPMasterTaskLoopDirective(
@@ -4476,6 +4727,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
Res = ActOnOpenMPMasterTaskLoopSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_taskloop);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
break;
case OMPD_parallel_master_taskloop:
Res = ActOnOpenMPParallelMasterTaskLoopDirective(
@@ -4483,6 +4736,14 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
AllowedNameModifiers.push_back(OMPD_taskloop);
AllowedNameModifiers.push_back(OMPD_parallel);
break;
+ case OMPD_parallel_master_taskloop_simd:
+ Res = ActOnOpenMPParallelMasterTaskLoopSimdDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ AllowedNameModifiers.push_back(OMPD_taskloop);
+ AllowedNameModifiers.push_back(OMPD_parallel);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
+ break;
case OMPD_distribute:
Res = ActOnOpenMPDistributeDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc, VarsWithInheritedDSA);
@@ -4501,21 +4762,29 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
Res = ActOnOpenMPDistributeParallelForSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_parallel);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
break;
case OMPD_distribute_simd:
Res = ActOnOpenMPDistributeSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
break;
case OMPD_target_parallel_for_simd:
Res = ActOnOpenMPTargetParallelForSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_target);
AllowedNameModifiers.push_back(OMPD_parallel);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
break;
case OMPD_target_simd:
Res = ActOnOpenMPTargetSimdDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_target);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
break;
case OMPD_teams_distribute:
Res = ActOnOpenMPTeamsDistributeDirective(
@@ -4524,11 +4793,15 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPD_teams_distribute_simd:
Res = ActOnOpenMPTeamsDistributeSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
break;
case OMPD_teams_distribute_parallel_for_simd:
Res = ActOnOpenMPTeamsDistributeParallelForSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_parallel);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
break;
case OMPD_teams_distribute_parallel_for:
Res = ActOnOpenMPTeamsDistributeParallelForDirective(
@@ -4556,11 +4829,15 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_target);
AllowedNameModifiers.push_back(OMPD_parallel);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
break;
case OMPD_target_teams_distribute_simd:
Res = ActOnOpenMPTargetTeamsDistributeSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_target);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
break;
case OMPD_declare_target:
case OMPD_end_declare_target:
@@ -4586,13 +4863,17 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPC_num_threads:
case OMPC_dist_schedule:
// Do not analyse if no parent teams directive.
- if (isOpenMPTeamsDirective(DSAStack->getCurrentDirective()))
+ if (isOpenMPTeamsDirective(Kind))
break;
continue;
case OMPC_if:
- if (isOpenMPTeamsDirective(DSAStack->getCurrentDirective()) &&
+ if (isOpenMPTeamsDirective(Kind) &&
cast<OMPIfClause>(C)->getNameModifier() != OMPD_target)
break;
+ if (isOpenMPParallelDirective(Kind) &&
+ isOpenMPTaskLoopDirective(Kind) &&
+ cast<OMPIfClause>(C)->getNameModifier() != OMPD_parallel)
+ break;
continue;
case OMPC_schedule:
break;
@@ -4601,7 +4882,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPC_final:
case OMPC_priority:
// Do not analyze if no parent parallel directive.
- if (isOpenMPParallelDirective(DSAStack->getCurrentDirective()))
+ if (isOpenMPParallelDirective(Kind))
break;
continue;
case OMPC_ordered:
@@ -4644,6 +4925,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPC_from:
case OMPC_use_device_ptr:
case OMPC_is_device_ptr:
+ case OMPC_nontemporal:
continue;
case OMPC_allocator:
case OMPC_flush:
@@ -4671,9 +4953,17 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
if (P.getFirst()->isImplicit() || isa<OMPCapturedExprDecl>(P.getFirst()))
continue;
ErrorFound = true;
- Diag(P.second->getExprLoc(), diag::err_omp_no_dsa_for_variable)
- << P.first << P.second->getSourceRange();
- Diag(DSAStack->getDefaultDSALocation(), diag::note_omp_default_dsa_none);
+ if (DSAStack->getDefaultDSA() == DSA_none) {
+ Diag(P.second->getExprLoc(), diag::err_omp_no_dsa_for_variable)
+ << P.first << P.second->getSourceRange();
+ Diag(DSAStack->getDefaultDSALocation(), diag::note_omp_default_dsa_none);
+ } else if (getLangOpts().OpenMP >= 50) {
+ Diag(P.second->getExprLoc(),
+ diag::err_omp_defaultmap_no_attr_for_variable)
+ << P.first << P.second->getSourceRange();
+ Diag(DSAStack->getDefaultDSALocation(),
+ diag::note_omp_defaultmap_attr_none);
+ }
}
if (!AllowedNameModifiers.empty())
@@ -4781,8 +5071,9 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
// OpenMP [2.8.1, simd construct, Restrictions]
// A list-item cannot appear in more than one aligned clause.
if (AlignedArgs.count(CanonPVD) > 0) {
- Diag(E->getExprLoc(), diag::err_omp_aligned_twice)
- << 1 << E->getSourceRange();
+ Diag(E->getExprLoc(), diag::err_omp_used_in_clause_twice)
+ << 1 << getOpenMPClauseName(OMPC_aligned)
+ << E->getSourceRange();
Diag(AlignedArgs[CanonPVD]->getExprLoc(),
diag::note_omp_explicit_dsa)
<< getOpenMPClauseName(OMPC_aligned);
@@ -4804,8 +5095,8 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
}
if (isa<CXXThisExpr>(E)) {
if (AlignedThis) {
- Diag(E->getExprLoc(), diag::err_omp_aligned_twice)
- << 2 << E->getSourceRange();
+ Diag(E->getExprLoc(), diag::err_omp_used_in_clause_twice)
+ << 2 << getOpenMPClauseName(OMPC_aligned) << E->getSourceRange();
Diag(AlignedThis->getExprLoc(), diag::note_omp_explicit_dsa)
<< getOpenMPClauseName(OMPC_aligned);
}
@@ -4950,6 +5241,29 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
return DG;
}
+static void setPrototype(Sema &S, FunctionDecl *FD, FunctionDecl *FDWithProto,
+ QualType NewType) {
+ assert(NewType->isFunctionProtoType() &&
+ "Expected function type with prototype.");
+ assert(FD->getType()->isFunctionNoProtoType() &&
+ "Expected function with type with no prototype.");
+ assert(FDWithProto->getType()->isFunctionProtoType() &&
+ "Expected function with prototype.");
+ // Synthesize parameters with the same types.
+ FD->setType(NewType);
+ SmallVector<ParmVarDecl *, 16> Params;
+ for (const ParmVarDecl *P : FDWithProto->parameters()) {
+ auto *Param = ParmVarDecl::Create(S.getASTContext(), FD, SourceLocation(),
+ SourceLocation(), nullptr, P->getType(),
+ /*TInfo=*/nullptr, SC_None, nullptr);
+ Param->setScopeInfo(0, Params.size());
+ Param->setImplicit();
+ Params.push_back(Param);
+ }
+
+ FD->setParams(Params);
+}
+
Optional<std::pair<FunctionDecl *, Expr *>>
Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
Expr *VariantRef, SourceRange SR) {
@@ -5048,7 +5362,9 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
if (ICS.isFailure()) {
Diag(VariantRef->getExprLoc(),
diag::err_omp_declare_variant_incompat_types)
- << VariantRef->getType() << FnPtrType << VariantRef->getSourceRange();
+ << VariantRef->getType()
+ << ((Method && !Method->isStatic()) ? FnPtrType : FD->getType())
+ << VariantRef->getSourceRange();
return None;
}
VariantRefCast = PerformImplicitConversion(
@@ -5088,6 +5404,24 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
return None;
}
+ // Check if function types are compatible in C.
+ if (!LangOpts.CPlusPlus) {
+ QualType NewType =
+ Context.mergeFunctionTypes(FD->getType(), NewFD->getType());
+ if (NewType.isNull()) {
+ Diag(VariantRef->getExprLoc(),
+ diag::err_omp_declare_variant_incompat_types)
+ << NewFD->getType() << FD->getType() << VariantRef->getSourceRange();
+ return None;
+ }
+ if (NewType->isFunctionProtoType()) {
+ if (FD->getType()->isFunctionNoProtoType())
+ setPrototype(*this, FD, NewFD, NewType);
+ else if (NewFD->getType()->isFunctionNoProtoType())
+ setPrototype(*this, NewFD, FD, NewType);
+ }
+ }
+
// Check if variant function is not marked with declare variant directive.
if (NewFD->hasAttrs() && NewFD->hasAttr<OMPDeclareVariantAttr>()) {
Diag(VariantRef->getExprLoc(),
@@ -5148,10 +5482,9 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
// Check general compatibility.
if (areMultiversionVariantFunctionsCompatible(
- FD, NewFD, PDiag(diag::err_omp_declare_variant_noproto),
- PartialDiagnosticAt(
- SR.getBegin(),
- PDiag(diag::note_omp_declare_variant_specified_here) << SR),
+ FD, NewFD, PartialDiagnostic::NullDiagnostic(),
+ PartialDiagnosticAt(SourceLocation(),
+ PartialDiagnostic::NullDiagnostic()),
PartialDiagnosticAt(
VariantRef->getExprLoc(),
PDiag(diag::err_omp_declare_variant_doesnt_support)),
@@ -5166,28 +5499,73 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
void Sema::ActOnOpenMPDeclareVariantDirective(
FunctionDecl *FD, Expr *VariantRef, SourceRange SR,
- const Sema::OpenMPDeclareVariantCtsSelectorData &Data) {
- if (Data.CtxSet == OMPDeclareVariantAttr::CtxSetUnknown ||
- Data.Ctx == OMPDeclareVariantAttr::CtxUnknown)
+ ArrayRef<OMPCtxSelectorData> Data) {
+ if (Data.empty())
return;
- Expr *Score = nullptr;
- OMPDeclareVariantAttr::ScoreType ST = OMPDeclareVariantAttr::ScoreUnknown;
- if (Data.CtxScore.isUsable()) {
- ST = OMPDeclareVariantAttr::ScoreSpecified;
- Score = Data.CtxScore.get();
- if (!Score->isTypeDependent() && !Score->isValueDependent() &&
- !Score->isInstantiationDependent() &&
- !Score->containsUnexpandedParameterPack()) {
- llvm::APSInt Result;
- ExprResult ICE = VerifyIntegerConstantExpression(Score, &Result);
- if (ICE.isInvalid())
- return;
+ SmallVector<Expr *, 4> CtxScores;
+ SmallVector<unsigned, 4> CtxSets;
+ SmallVector<unsigned, 4> Ctxs;
+ SmallVector<StringRef, 4> ImplVendors, DeviceKinds;
+ bool IsError = false;
+ for (const OMPCtxSelectorData &D : Data) {
+ OpenMPContextSelectorSetKind CtxSet = D.CtxSet;
+ OpenMPContextSelectorKind Ctx = D.Ctx;
+ if (CtxSet == OMP_CTX_SET_unknown || Ctx == OMP_CTX_unknown)
+ return;
+ Expr *Score = nullptr;
+ if (D.Score.isUsable()) {
+ Score = D.Score.get();
+ if (!Score->isTypeDependent() && !Score->isValueDependent() &&
+ !Score->isInstantiationDependent() &&
+ !Score->containsUnexpandedParameterPack()) {
+ Score =
+ PerformOpenMPImplicitIntegerConversion(Score->getExprLoc(), Score)
+ .get();
+ if (Score)
+ Score = VerifyIntegerConstantExpression(Score).get();
+ }
+ } else {
+ // OpenMP 5.0, 2.3.3 Matching and Scoring Context Selectors.
+ // The kind, arch, and isa selectors are given the values 2^l, 2^(l+1) and
+ // 2^(l+2), respectively, where l is the number of traits in the construct
+ // set.
+ // TODO: implement correct logic for isa and arch traits.
+ // TODO: take the construct context set into account when it is
+ // implemented.
+ int L = 0; // Currently set the number of traits in construct set to 0,
+ // since the construct trait set in not supported yet.
+ if (CtxSet == OMP_CTX_SET_device && Ctx == OMP_CTX_kind)
+ Score = ActOnIntegerConstant(SourceLocation(), std::pow(2, L)).get();
+ else
+ Score = ActOnIntegerConstant(SourceLocation(), 0).get();
+ }
+ switch (Ctx) {
+ case OMP_CTX_vendor:
+ assert(CtxSet == OMP_CTX_SET_implementation &&
+ "Expected implementation context selector set.");
+ ImplVendors.append(D.Names.begin(), D.Names.end());
+ break;
+ case OMP_CTX_kind:
+ assert(CtxSet == OMP_CTX_SET_device &&
+ "Expected device context selector set.");
+ DeviceKinds.append(D.Names.begin(), D.Names.end());
+ break;
+ case OMP_CTX_unknown:
+ llvm_unreachable("Unknown context selector kind.");
}
+ IsError = IsError || !Score;
+ CtxSets.push_back(CtxSet);
+ Ctxs.push_back(Ctx);
+ CtxScores.push_back(Score);
+ }
+ if (!IsError) {
+ auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit(
+ Context, VariantRef, CtxScores.begin(), CtxScores.size(),
+ CtxSets.begin(), CtxSets.size(), Ctxs.begin(), Ctxs.size(),
+ ImplVendors.begin(), ImplVendors.size(), DeviceKinds.begin(),
+ DeviceKinds.size(), SR);
+ FD->addAttr(NewAttr);
}
- auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit(
- Context, VariantRef, Score, Data.CtxSet, ST, Data.Ctx,
- Data.ImplVendors.begin(), Data.ImplVendors.size(), SR);
- FD->addAttr(NewAttr);
}
void Sema::markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc,
@@ -5200,7 +5578,7 @@ void Sema::markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc,
Func->specific_attrs<OMPDeclareVariantAttr>()) {
// TODO: add checks for active OpenMP context where possible.
Expr *VariantRef = A->getVariantFuncRef();
- auto *DRE = dyn_cast<DeclRefExpr>(VariantRef->IgnoreParenImpCasts());
+ auto *DRE = cast<DeclRefExpr>(VariantRef->IgnoreParenImpCasts());
auto *F = cast<FunctionDecl>(DRE->getDecl());
if (!F->isDefined() && F->isTemplateInstantiation())
InstantiateFunctionDefinition(Loc, F->getFirstDecl());
@@ -6953,7 +7331,8 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
"Expected canonical for or range-based for loops.");
CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody();
}
- CurStmt = CurStmt->IgnoreContainers();
+ CurStmt = OMPLoopDirective::tryToFindNextInnerLoop(
+ CurStmt, SemaRef.LangOpts.OpenMP >= 50);
}
for (unsigned Cnt = NestedLoopCount; Cnt < OrderedLoopCount; ++Cnt) {
if (checkOpenMPIterationSpace(
@@ -6980,7 +7359,8 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
"Expected canonical for or range-based for loops.");
CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody();
}
- CurStmt = CurStmt->IgnoreContainers();
+ CurStmt = OMPLoopDirective::tryToFindNextInnerLoop(
+ CurStmt, SemaRef.LangOpts.OpenMP >= 50);
}
Built.clear(/* size */ NestedLoopCount);
@@ -7995,6 +8375,28 @@ StmtResult Sema::ActOnOpenMPParallelForSimdDirective(
}
StmtResult
+Sema::ActOnOpenMPParallelMasterDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ if (!AStmt)
+ return StmtError();
+
+ assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ auto *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+
+ setFunctionHasBranchProtectedScope();
+
+ return OMPParallelMasterDirective::Create(Context, StartLoc, EndLoc, Clauses,
+ AStmt);
+}
+
+StmtResult
Sema::ActOnOpenMPParallelSectionsDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc) {
@@ -8137,7 +8539,8 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses,
// OpenMP [2.8.1,simd Construct, Restrictions]
// An ordered construct with the simd clause is the only OpenMP construct
// that can appear in the simd region.
- Diag(StartLoc, diag::err_omp_prohibited_region_simd);
+ Diag(StartLoc, diag::err_omp_prohibited_region_simd)
+ << (LangOpts.OpenMP >= 50 ? 1 : 0);
ErrorFound = true;
} else if (DependFound && (TC || SC)) {
Diag(DependFound->getBeginLoc(), diag::err_omp_depend_clause_thread_simd)
@@ -9467,6 +9870,74 @@ StmtResult Sema::ActOnOpenMPParallelMasterTaskLoopDirective(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
}
+StmtResult Sema::ActOnOpenMPParallelMasterTaskLoopSimdDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ auto *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel =
+ getOpenMPCaptureLevels(OMPD_parallel_master_taskloop_simd);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
+
+ OMPLoopDirective::HelperExprs B;
+ // In presence of clause 'collapse' or 'ordered' with number of loops, it will
+ // define the nested loops number.
+ unsigned NestedLoopCount = checkOpenMPLoop(
+ OMPD_parallel_master_taskloop_simd, getCollapseNumberExpr(Clauses),
+ /*OrderedLoopCountExpr=*/nullptr, CS, *this, *DSAStack,
+ VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp for loop exprs were not built");
+
+ if (!CurContext->isDependentContext()) {
+ // Finalize the clauses that need pre-built expressions for CodeGen.
+ for (OMPClause *C : Clauses) {
+ if (auto *LC = dyn_cast<OMPLinearClause>(C))
+ if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
+ B.NumIterations, *this, CurScope,
+ DSAStack))
+ return StmtError();
+ }
+ }
+
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // The grainsize clause and num_tasks clause are mutually exclusive and may
+ // not appear on the same taskloop directive.
+ if (checkGrainsizeNumTasksClauses(*this, Clauses))
+ return StmtError();
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // If a reduction clause is present on the taskloop directive, the nogroup
+ // clause must not be specified.
+ if (checkReductionClauseWithNogroup(*this, Clauses))
+ return StmtError();
+ if (checkSimdlenSafelenSpecified(*this, Clauses))
+ return StmtError();
+
+ setFunctionHasBranchProtectedScope();
+ return OMPParallelMasterTaskLoopSimdDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+}
+
StmtResult Sema::ActOnOpenMPDistributeDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
@@ -10317,6 +10788,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_atomic_default_mem_order:
case OMPC_device_type:
case OMPC_match:
+ case OMPC_nontemporal:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -10328,29 +10800,47 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
// A return value of OMPD_unknown signifies that the expression should not
// be captured.
static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
- OpenMPDirectiveKind DKind, OpenMPClauseKind CKind,
+ OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, unsigned OpenMPVersion,
OpenMPDirectiveKind NameModifier = OMPD_unknown) {
OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
switch (CKind) {
case OMPC_if:
switch (DKind) {
+ case OMPD_target_parallel_for_simd:
+ if (OpenMPVersion >= 50 &&
+ (NameModifier == OMPD_unknown || NameModifier == OMPD_simd)) {
+ CaptureRegion = OMPD_parallel;
+ break;
+ }
+ LLVM_FALLTHROUGH;
case OMPD_target_parallel:
case OMPD_target_parallel_for:
- case OMPD_target_parallel_for_simd:
// If this clause applies to the nested 'parallel' region, capture within
// the 'target' region, otherwise do not capture.
if (NameModifier == OMPD_unknown || NameModifier == OMPD_parallel)
CaptureRegion = OMPD_target;
break;
- case OMPD_target_teams_distribute_parallel_for:
case OMPD_target_teams_distribute_parallel_for_simd:
+ if (OpenMPVersion >= 50 &&
+ (NameModifier == OMPD_unknown || NameModifier == OMPD_simd)) {
+ CaptureRegion = OMPD_parallel;
+ break;
+ }
+ LLVM_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.
if (NameModifier == OMPD_unknown || NameModifier == OMPD_parallel)
CaptureRegion = OMPD_teams;
break;
- case OMPD_teams_distribute_parallel_for:
case OMPD_teams_distribute_parallel_for_simd:
+ if (OpenMPVersion >= 50 &&
+ (NameModifier == OMPD_unknown || NameModifier == OMPD_simd)) {
+ CaptureRegion = OMPD_parallel;
+ break;
+ }
+ LLVM_FALLTHROUGH;
+ case OMPD_teams_distribute_parallel_for:
CaptureRegion = OMPD_teams;
break;
case OMPD_target_update:
@@ -10362,24 +10852,63 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
if (NameModifier == OMPD_unknown || NameModifier == OMPD_taskloop)
CaptureRegion = OMPD_parallel;
break;
+ case OMPD_parallel_master_taskloop_simd:
+ if ((OpenMPVersion <= 45 && NameModifier == OMPD_unknown) ||
+ NameModifier == OMPD_taskloop) {
+ CaptureRegion = OMPD_parallel;
+ break;
+ }
+ if (OpenMPVersion <= 45)
+ break;
+ if (NameModifier == OMPD_unknown || NameModifier == OMPD_simd)
+ CaptureRegion = OMPD_taskloop;
+ break;
+ case OMPD_parallel_for_simd:
+ if (OpenMPVersion <= 45)
+ break;
+ if (NameModifier == OMPD_unknown || NameModifier == OMPD_simd)
+ CaptureRegion = OMPD_parallel;
+ break;
+ case OMPD_taskloop_simd:
+ case OMPD_master_taskloop_simd:
+ if (OpenMPVersion <= 45)
+ break;
+ if (NameModifier == OMPD_unknown || NameModifier == OMPD_simd)
+ CaptureRegion = OMPD_taskloop;
+ break;
+ case OMPD_distribute_parallel_for_simd:
+ if (OpenMPVersion <= 45)
+ break;
+ if (NameModifier == OMPD_unknown || NameModifier == OMPD_simd)
+ CaptureRegion = OMPD_parallel;
+ break;
+ case OMPD_target_simd:
+ if (OpenMPVersion >= 50 &&
+ (NameModifier == OMPD_unknown || NameModifier == OMPD_simd))
+ CaptureRegion = OMPD_target;
+ break;
+ case OMPD_teams_distribute_simd:
+ case OMPD_target_teams_distribute_simd:
+ if (OpenMPVersion >= 50 &&
+ (NameModifier == OMPD_unknown || NameModifier == OMPD_simd))
+ CaptureRegion = OMPD_teams;
+ break;
case OMPD_cancel:
case OMPD_parallel:
+ case OMPD_parallel_master:
case OMPD_parallel_sections:
case OMPD_parallel_for:
- case OMPD_parallel_for_simd:
case OMPD_target:
- case OMPD_target_simd:
case OMPD_target_teams:
case OMPD_target_teams_distribute:
- case OMPD_target_teams_distribute_simd:
case OMPD_distribute_parallel_for:
- case OMPD_distribute_parallel_for_simd:
case OMPD_task:
case OMPD_taskloop:
- case OMPD_taskloop_simd:
case OMPD_master_taskloop:
- case OMPD_master_taskloop_simd:
case OMPD_target_data:
+ case OMPD_simd:
+ case OMPD_for_simd:
+ case OMPD_distribute_simd:
// Do not capture if-clause expressions.
break;
case OMPD_threadprivate:
@@ -10396,9 +10925,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_teams:
- case OMPD_simd:
case OMPD_for:
- case OMPD_for_simd:
case OMPD_sections:
case OMPD_section:
case OMPD_single:
@@ -10408,9 +10935,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_distribute:
case OMPD_ordered:
case OMPD_atomic:
- case OMPD_distribute_simd:
case OMPD_teams_distribute:
- case OMPD_teams_distribute_simd:
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with if-clause");
case OMPD_unknown:
@@ -10431,12 +10956,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
CaptureRegion = OMPD_teams;
break;
case OMPD_parallel:
+ case OMPD_parallel_master:
case OMPD_parallel_sections:
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
case OMPD_distribute_parallel_for:
case OMPD_distribute_parallel_for_simd:
case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_master_taskloop_simd:
// Do not capture num_threads-clause expressions.
break;
case OMPD_target_data:
@@ -10513,12 +11040,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_master_taskloop:
case OMPD_master_taskloop_simd:
case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_master_taskloop_simd:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
case OMPD_target_update:
case OMPD_cancel:
case OMPD_parallel:
+ case OMPD_parallel_master:
case OMPD_parallel_sections:
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
@@ -10583,12 +11112,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_master_taskloop:
case OMPD_master_taskloop_simd:
case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_master_taskloop_simd:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
case OMPD_target_update:
case OMPD_cancel:
case OMPD_parallel:
+ case OMPD_parallel_master:
case OMPD_parallel_sections:
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
@@ -10653,6 +11184,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_master_taskloop:
case OMPD_master_taskloop_simd:
case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_master_taskloop_simd:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
@@ -10667,6 +11199,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_target_parallel:
case OMPD_cancel:
case OMPD_parallel:
+ case OMPD_parallel_master:
case OMPD_parallel_sections:
case OMPD_threadprivate:
case OMPD_allocate:
@@ -10727,6 +11260,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_master_taskloop:
case OMPD_master_taskloop_simd:
case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_master_taskloop_simd:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
@@ -10737,6 +11271,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_target_parallel:
case OMPD_cancel:
case OMPD_parallel:
+ case OMPD_parallel_master:
case OMPD_parallel_sections:
case OMPD_threadprivate:
case OMPD_allocate:
@@ -10802,8 +11337,10 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_master_taskloop:
case OMPD_master_taskloop_simd:
case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_master_taskloop_simd:
case OMPD_cancel:
case OMPD_parallel:
+ case OMPD_parallel_master:
case OMPD_parallel_sections:
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
@@ -10851,6 +11388,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_master_taskloop_simd:
break;
case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_master_taskloop_simd:
CaptureRegion = OMPD_parallel;
break;
case OMPD_target_update:
@@ -10876,6 +11414,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_distribute_parallel_for_simd:
case OMPD_cancel:
case OMPD_parallel:
+ case OMPD_parallel_master:
case OMPD_parallel_sections:
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
@@ -10960,6 +11499,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_atomic_default_mem_order:
case OMPC_device_type:
case OMPC_match:
+ case OMPC_nontemporal:
llvm_unreachable("Unexpected OpenMP clause.");
}
return CaptureRegion;
@@ -10984,8 +11524,8 @@ OMPClause *Sema::ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier,
ValExpr = Val.get();
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
- CaptureRegion =
- getOpenMPCaptureRegionForClause(DKind, OMPC_if, NameModifier);
+ CaptureRegion = getOpenMPCaptureRegionForClause(
+ DKind, OMPC_if, LangOpts.OpenMP, NameModifier);
if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
ValExpr = MakeFullExpr(ValExpr).get();
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
@@ -11016,7 +11556,8 @@ OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition,
ValExpr = MakeFullExpr(Val.get()).get();
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
- CaptureRegion = getOpenMPCaptureRegionForClause(DKind, OMPC_final);
+ CaptureRegion =
+ getOpenMPCaptureRegionForClause(DKind, OMPC_final, LangOpts.OpenMP);
if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
ValExpr = MakeFullExpr(ValExpr).get();
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
@@ -11101,7 +11642,8 @@ isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef, OpenMPClauseKind CKind,
}
if (!BuildCapture)
return true;
- *CaptureRegion = getOpenMPCaptureRegionForClause(DKind, CKind);
+ *CaptureRegion =
+ getOpenMPCaptureRegionForClause(DKind, CKind, SemaRef.LangOpts.OpenMP);
if (*CaptureRegion != OMPD_unknown &&
!SemaRef.CurContext->isDependentContext()) {
ValExpr = SemaRef.MakeFullExpr(ValExpr).get();
@@ -11128,7 +11670,7 @@ OMPClause *Sema::ActOnOpenMPNumThreadsClause(Expr *NumThreads,
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
OpenMPDirectiveKind CaptureRegion =
- getOpenMPCaptureRegionForClause(DKind, OMPC_num_threads);
+ getOpenMPCaptureRegionForClause(DKind, OMPC_num_threads, LangOpts.OpenMP);
if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
ValExpr = MakeFullExpr(ValExpr).get();
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
@@ -11315,9 +11857,8 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
ArgumentLoc, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_proc_bind:
- Res = ActOnOpenMPProcBindClause(
- static_cast<OpenMPProcBindClauseKind>(Argument), ArgumentLoc, StartLoc,
- LParenLoc, EndLoc);
+ Res = ActOnOpenMPProcBindClause(static_cast<ProcBindKind>(Argument),
+ ArgumentLoc, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_atomic_default_mem_order:
Res = ActOnOpenMPAtomicDefaultMemOrderClause(
@@ -11381,6 +11922,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_dynamic_allocators:
case OMPC_device_type:
case OMPC_match:
+ case OMPC_nontemporal:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -11391,7 +11933,6 @@ getListOfPossibleValues(OpenMPClauseKind K, unsigned First, unsigned Last,
ArrayRef<unsigned> Exclude = llvm::None) {
SmallString<256> Buffer;
llvm::raw_svector_ostream Out(Buffer);
- unsigned Bound = Last >= 2 ? Last - 2 : 0;
unsigned Skipped = Exclude.size();
auto S = Exclude.begin(), E = Exclude.end();
for (unsigned I = First; I < Last; ++I) {
@@ -11400,9 +11941,9 @@ getListOfPossibleValues(OpenMPClauseKind K, unsigned First, unsigned Last,
continue;
}
Out << "'" << getOpenMPSimpleClauseTypeName(K, I) << "'";
- if (I == Bound - Skipped)
+ if (I + Skipped + 2 == Last)
Out << " or ";
- else if (I != Bound + 1 - Skipped)
+ else if (I + Skipped + 1 != Last)
Out << ", ";
}
return Out.str();
@@ -11437,15 +11978,16 @@ OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind,
OMPDefaultClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
}
-OMPClause *Sema::ActOnOpenMPProcBindClause(OpenMPProcBindClauseKind Kind,
+OMPClause *Sema::ActOnOpenMPProcBindClause(ProcBindKind Kind,
SourceLocation KindKwLoc,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
- if (Kind == OMPC_PROC_BIND_unknown) {
+ if (Kind == OMP_PROC_BIND_unknown) {
Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
- << getListOfPossibleValues(OMPC_proc_bind, /*First=*/0,
- /*Last=*/OMPC_PROC_BIND_unknown)
+ << getListOfPossibleValues(OMPC_proc_bind,
+ /*First=*/unsigned(OMP_PROC_BIND_master),
+ /*Last=*/5)
<< getOpenMPClauseName(OMPC_proc_bind);
return nullptr;
}
@@ -11561,6 +12103,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_atomic_default_mem_order:
case OMPC_device_type:
case OMPC_match:
+ case OMPC_nontemporal:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -11659,8 +12202,8 @@ OMPClause *Sema::ActOnOpenMPScheduleClause(
return nullptr;
}
} else if (getOpenMPCaptureRegionForClause(
- DSAStack->getCurrentDirective(), OMPC_schedule) !=
- OMPD_unknown &&
+ DSAStack->getCurrentDirective(), OMPC_schedule,
+ LangOpts.OpenMP) != OMPD_unknown &&
!CurContext->isDependentContext()) {
ValExpr = MakeFullExpr(ValExpr).get();
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
@@ -11772,6 +12315,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_atomic_default_mem_order:
case OMPC_device_type:
case OMPC_match:
+ case OMPC_nontemporal:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -11857,11 +12401,10 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr,
const OMPVarListLocTy &Locs, SourceLocation ColonLoc,
CXXScopeSpec &ReductionOrMapperIdScopeSpec,
- DeclarationNameInfo &ReductionOrMapperId, OpenMPDependClauseKind DepKind,
- OpenMPLinearClauseKind LinKind,
+ DeclarationNameInfo &ReductionOrMapperId, int ExtraModifier,
ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
- ArrayRef<SourceLocation> MapTypeModifiersLoc, OpenMPMapClauseKind MapType,
- bool IsMapTypeImplicit, SourceLocation DepLinMapLoc) {
+ ArrayRef<SourceLocation> MapTypeModifiersLoc, bool IsMapTypeImplicit,
+ SourceLocation DepLinMapLastLoc) {
SourceLocation StartLoc = Locs.StartLoc;
SourceLocation LParenLoc = Locs.LParenLoc;
SourceLocation EndLoc = Locs.EndLoc;
@@ -11874,7 +12417,11 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
Res = ActOnOpenMPFirstprivateClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_lastprivate:
- Res = ActOnOpenMPLastprivateClause(VarList, StartLoc, LParenLoc, EndLoc);
+ assert(0 <= ExtraModifier && ExtraModifier <= OMPC_LASTPRIVATE_unknown &&
+ "Unexpected lastprivate modifier.");
+ Res = ActOnOpenMPLastprivateClause(
+ VarList, static_cast<OpenMPLastprivateModifier>(ExtraModifier),
+ DepLinMapLastLoc, ColonLoc, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_shared:
Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc);
@@ -11895,8 +12442,12 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
ReductionOrMapperId);
break;
case OMPC_linear:
- Res = ActOnOpenMPLinearClause(VarList, TailExpr, StartLoc, LParenLoc,
- LinKind, DepLinMapLoc, ColonLoc, EndLoc);
+ assert(0 <= ExtraModifier && ExtraModifier <= OMPC_LINEAR_unknown &&
+ "Unexpected linear modifier.");
+ Res = ActOnOpenMPLinearClause(
+ VarList, TailExpr, StartLoc, LParenLoc,
+ static_cast<OpenMPLinearClauseKind>(ExtraModifier), DepLinMapLastLoc,
+ ColonLoc, EndLoc);
break;
case OMPC_aligned:
Res = ActOnOpenMPAlignedClause(VarList, TailExpr, StartLoc, LParenLoc,
@@ -11912,14 +12463,19 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
Res = ActOnOpenMPFlushClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_depend:
- Res = ActOnOpenMPDependClause(DepKind, DepLinMapLoc, ColonLoc, VarList,
- StartLoc, LParenLoc, EndLoc);
+ assert(0 <= ExtraModifier && ExtraModifier <= OMPC_DEPEND_unknown &&
+ "Unexpected depend modifier.");
+ Res = ActOnOpenMPDependClause(
+ static_cast<OpenMPDependClauseKind>(ExtraModifier), DepLinMapLastLoc,
+ ColonLoc, VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_map:
- Res = ActOnOpenMPMapClause(MapTypeModifiers, MapTypeModifiersLoc,
- ReductionOrMapperIdScopeSpec,
- ReductionOrMapperId, MapType, IsMapTypeImplicit,
- DepLinMapLoc, ColonLoc, VarList, Locs);
+ assert(0 <= ExtraModifier && ExtraModifier <= OMPC_MAP_unknown &&
+ "Unexpected map modifier.");
+ Res = ActOnOpenMPMapClause(
+ MapTypeModifiers, MapTypeModifiersLoc, ReductionOrMapperIdScopeSpec,
+ ReductionOrMapperId, static_cast<OpenMPMapClauseKind>(ExtraModifier),
+ IsMapTypeImplicit, DepLinMapLastLoc, ColonLoc, VarList, Locs);
break;
case OMPC_to:
Res = ActOnOpenMPToClause(VarList, ReductionOrMapperIdScopeSpec,
@@ -11939,6 +12495,9 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
Res = ActOnOpenMPAllocateClause(TailExpr, VarList, StartLoc, LParenLoc,
ColonLoc, EndLoc);
break;
+ case OMPC_nontemporal:
+ Res = ActOnOpenMPNontemporalClause(VarList, StartLoc, LParenLoc, EndLoc);
+ break;
case OMPC_if:
case OMPC_final:
case OMPC_num_threads:
@@ -12442,10 +13001,19 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
buildPreInits(Context, ExprCaptures));
}
-OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc) {
+OMPClause *Sema::ActOnOpenMPLastprivateClause(
+ ArrayRef<Expr *> VarList, OpenMPLastprivateModifier LPKind,
+ SourceLocation LPKindLoc, SourceLocation ColonLoc, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc) {
+ if (LPKind == OMPC_LASTPRIVATE_unknown && LPKindLoc.isValid()) {
+ assert(ColonLoc.isValid() && "Colon location must be valid.");
+ Diag(LPKindLoc, diag::err_omp_unexpected_clause_value)
+ << getListOfPossibleValues(OMPC_lastprivate, /*First=*/0,
+ /*Last=*/OMPC_LASTPRIVATE_unknown)
+ << getOpenMPClauseName(OMPC_lastprivate);
+ return nullptr;
+ }
+
SmallVector<Expr *, 8> Vars;
SmallVector<Expr *, 8> SrcExprs;
SmallVector<Expr *, 8> DstExprs;
@@ -12491,6 +13059,19 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
if (rejectConstNotMutableType(*this, D, Type, OMPC_lastprivate, ELoc))
continue;
+ // OpenMP 5.0 [2.19.4.5 lastprivate Clause, Restrictions]
+ // A list item that appears in a lastprivate clause with the conditional
+ // modifier must be a scalar variable.
+ if (LPKind == OMPC_LASTPRIVATE_conditional && !Type->isScalarType()) {
+ Diag(ELoc, diag::err_omp_lastprivate_conditional_non_scalar);
+ bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(D->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << D;
+ continue;
+ }
+
OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
// OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct]
@@ -12599,6 +13180,7 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
return OMPLastprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc,
Vars, SrcExprs, DstExprs, AssignmentOps,
+ LPKind, LPKindLoc, ColonLoc,
buildPreInits(Context, ExprCaptures),
buildPostUpdate(*this, ExprPostUpdates));
}
@@ -12916,7 +13498,8 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
}
}
if (ReductionIdScopeSpec.isSet()) {
- SemaRef.Diag(Loc, diag::err_omp_not_resolved_reduction_identifier) << Range;
+ SemaRef.Diag(Loc, diag::err_omp_not_resolved_reduction_identifier)
+ << Ty << Range;
return ExprError();
}
return ExprEmpty();
@@ -13771,8 +14354,8 @@ bool Sema::CheckOpenMPLinearDecl(const ValueDecl *D, SourceLocation ELoc,
// A list item must be of integral or pointer type.
Type = Type.getUnqualifiedType().getCanonicalType();
const auto *Ty = Type.getTypePtrOrNull();
- if (!Ty || (!Ty->isDependentType() && !Ty->isIntegralType(Context) &&
- !Ty->isPointerType())) {
+ if (!Ty || (LinKind != OMPC_LINEAR_ref && !Ty->isDependentType() &&
+ !Ty->isIntegralType(Context) && !Ty->isPointerType())) {
Diag(ELoc, diag::err_omp_linear_expected_int_or_ptr) << Type;
if (D) {
bool IsDecl =
@@ -14066,7 +14649,8 @@ OMPClause *Sema::ActOnOpenMPAlignedClause(
// OpenMP [2.8.1, simd construct, Restrictions]
// A list-item cannot appear in more than one aligned clause.
if (const Expr *PrevRef = DSAStack->addUniqueAligned(D, SimpleRefExpr)) {
- Diag(ELoc, diag::err_omp_aligned_twice) << 0 << ERange;
+ Diag(ELoc, diag::err_omp_used_in_clause_twice)
+ << 0 << getOpenMPClauseName(OMPC_aligned) << ERange;
Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa)
<< getOpenMPClauseName(OMPC_aligned);
continue;
@@ -14437,6 +15021,22 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
}
OpsOffs.emplace_back(RHS, OOK);
} else {
+ // OpenMP 5.0 [2.17.11, Restrictions]
+ // List items used in depend clauses cannot be zero-length array sections.
+ const auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr);
+ if (OASE) {
+ const Expr *Length = OASE->getLength();
+ Expr::EvalResult Result;
+ if (Length && !Length->isValueDependent() &&
+ Length->EvaluateAsInt(Result, Context) &&
+ Result.Val.getInt().isNullValue()) {
+ Diag(ELoc,
+ diag::err_omp_depend_zero_length_array_section_not_allowed)
+ << SimpleExpr->getSourceRange();
+ continue;
+ }
+ }
+
auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr);
if (!RefExpr->IgnoreParenImpCasts()->isLValue() ||
(ASE &&
@@ -14496,7 +15096,7 @@ OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc,
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
OpenMPDirectiveKind CaptureRegion =
- getOpenMPCaptureRegionForClause(DKind, OMPC_device);
+ getOpenMPCaptureRegionForClause(DKind, OMPC_device, LangOpts.OpenMP);
if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
ValExpr = MakeFullExpr(ValExpr).get();
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
@@ -14517,7 +15117,7 @@ static bool checkTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef,
return false;
}
if (FullCheck && !SemaRef.CurContext->isDependentContext() &&
- !QTy.isTrivialType(SemaRef.Context))
+ !QTy.isTriviallyCopyableType(SemaRef.Context))
SemaRef.Diag(SL, diag::warn_omp_non_trivial_type_mapped) << QTy << SR;
return true;
}
@@ -15408,8 +16008,22 @@ static void checkMappableExpressionList(
return MC.getAssociatedDeclaration();
});
assert(I != CurComponents.end() && "Null decl on map clause.");
- QualType Type =
- I->getAssociatedDeclaration()->getType().getNonReferenceType();
+ QualType Type;
+ auto *ASE = dyn_cast<ArraySubscriptExpr>(VE->IgnoreParens());
+ auto *OASE = dyn_cast<OMPArraySectionExpr>(VE->IgnoreParens());
+ if (ASE) {
+ Type = ASE->getType().getNonReferenceType();
+ } else if (OASE) {
+ QualType BaseType =
+ OMPArraySectionExpr::getBaseOriginalType(OASE->getBase());
+ if (const auto *ATy = BaseType->getAsArrayTypeUnsafe())
+ Type = ATy->getElementType();
+ else
+ Type = BaseType->getPointeeType();
+ Type = Type.getNonReferenceType();
+ } else {
+ Type = VE->getType();
+ }
// OpenMP 4.5 [2.10.5, target update Construct, Restrictions, p.4]
// A list item in a to or from clause must have a mappable type.
@@ -15419,6 +16033,8 @@ static void checkMappableExpressionList(
DSAS, Type))
continue;
+ Type = I->getAssociatedDeclaration()->getType().getNonReferenceType();
+
if (CKind == OMPC_map) {
// target enter data
// OpenMP [2.10.2, Restrictions, p. 99]
@@ -15948,7 +16564,7 @@ OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams,
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
OpenMPDirectiveKind CaptureRegion =
- getOpenMPCaptureRegionForClause(DKind, OMPC_num_teams);
+ getOpenMPCaptureRegionForClause(DKind, OMPC_num_teams, LangOpts.OpenMP);
if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
ValExpr = MakeFullExpr(ValExpr).get();
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
@@ -15974,8 +16590,8 @@ OMPClause *Sema::ActOnOpenMPThreadLimitClause(Expr *ThreadLimit,
return nullptr;
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
- OpenMPDirectiveKind CaptureRegion =
- getOpenMPCaptureRegionForClause(DKind, OMPC_thread_limit);
+ OpenMPDirectiveKind CaptureRegion = getOpenMPCaptureRegionForClause(
+ DKind, OMPC_thread_limit, LangOpts.OpenMP);
if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
ValExpr = MakeFullExpr(ValExpr).get();
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
@@ -16100,8 +16716,8 @@ OMPClause *Sema::ActOnOpenMPDistScheduleClause(
return nullptr;
}
} else if (getOpenMPCaptureRegionForClause(
- DSAStack->getCurrentDirective(), OMPC_dist_schedule) !=
- OMPD_unknown &&
+ DSAStack->getCurrentDirective(), OMPC_dist_schedule,
+ LangOpts.OpenMP) != OMPD_unknown &&
!CurContext->isDependentContext()) {
ValExpr = MakeFullExpr(ValExpr).get();
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
@@ -16120,26 +16736,57 @@ OMPClause *Sema::ActOnOpenMPDefaultmapClause(
OpenMPDefaultmapClauseModifier M, OpenMPDefaultmapClauseKind Kind,
SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation MLoc,
SourceLocation KindLoc, SourceLocation EndLoc) {
- // OpenMP 4.5 only supports 'defaultmap(tofrom: scalar)'
- if (M != OMPC_DEFAULTMAP_MODIFIER_tofrom || Kind != OMPC_DEFAULTMAP_scalar) {
- std::string Value;
- SourceLocation Loc;
- Value += "'";
- if (M != OMPC_DEFAULTMAP_MODIFIER_tofrom) {
- Value += getOpenMPSimpleClauseTypeName(OMPC_defaultmap,
- OMPC_DEFAULTMAP_MODIFIER_tofrom);
- Loc = MLoc;
- } else {
- Value += getOpenMPSimpleClauseTypeName(OMPC_defaultmap,
- OMPC_DEFAULTMAP_scalar);
- Loc = KindLoc;
+ if (getLangOpts().OpenMP < 50) {
+ if (M != OMPC_DEFAULTMAP_MODIFIER_tofrom ||
+ Kind != OMPC_DEFAULTMAP_scalar) {
+ std::string Value;
+ SourceLocation Loc;
+ Value += "'";
+ if (M != OMPC_DEFAULTMAP_MODIFIER_tofrom) {
+ Value += getOpenMPSimpleClauseTypeName(OMPC_defaultmap,
+ OMPC_DEFAULTMAP_MODIFIER_tofrom);
+ Loc = MLoc;
+ } else {
+ Value += getOpenMPSimpleClauseTypeName(OMPC_defaultmap,
+ OMPC_DEFAULTMAP_scalar);
+ Loc = KindLoc;
+ }
+ Value += "'";
+ Diag(Loc, diag::err_omp_unexpected_clause_value)
+ << Value << getOpenMPClauseName(OMPC_defaultmap);
+ return nullptr;
+ }
+ } else {
+ bool isDefaultmapModifier = (M != OMPC_DEFAULTMAP_MODIFIER_unknown);
+ bool isDefaultmapKind = (Kind != OMPC_DEFAULTMAP_unknown);
+ if (!isDefaultmapKind || !isDefaultmapModifier) {
+ std::string ModifierValue = "'alloc', 'from', 'to', 'tofrom', "
+ "'firstprivate', 'none', 'default'";
+ std::string KindValue = "'scalar', 'aggregate', 'pointer'";
+ if (!isDefaultmapKind && isDefaultmapModifier) {
+ Diag(KindLoc, diag::err_omp_unexpected_clause_value)
+ << KindValue << getOpenMPClauseName(OMPC_defaultmap);
+ } else if (isDefaultmapKind && !isDefaultmapModifier) {
+ Diag(MLoc, diag::err_omp_unexpected_clause_value)
+ << ModifierValue << getOpenMPClauseName(OMPC_defaultmap);
+ } else {
+ Diag(MLoc, diag::err_omp_unexpected_clause_value)
+ << ModifierValue << getOpenMPClauseName(OMPC_defaultmap);
+ Diag(KindLoc, diag::err_omp_unexpected_clause_value)
+ << KindValue << getOpenMPClauseName(OMPC_defaultmap);
+ }
+ return nullptr;
+ }
+
+ // OpenMP [5.0, 2.12.5, Restrictions, p. 174]
+ // At most one defaultmap clause for each category can appear on the
+ // directive.
+ if (DSAStack->checkDefaultmapCategory(Kind)) {
+ Diag(StartLoc, diag::err_omp_one_defaultmap_each_category);
+ return nullptr;
}
- Value += "'";
- Diag(Loc, diag::err_omp_unexpected_clause_value)
- << Value << getOpenMPClauseName(OMPC_defaultmap);
- return nullptr;
}
- DSAStack->setDefaultDMAToFromScalar(StartLoc);
+ DSAStack->setDefaultDMAAttr(M, Kind, StartLoc);
return new (Context)
OMPDefaultmapClause(StartLoc, LParenLoc, MLoc, KindLoc, EndLoc, Kind, M);
@@ -16604,3 +17251,42 @@ OMPClause *Sema::ActOnOpenMPAllocateClause(
return OMPAllocateClause::Create(Context, StartLoc, LParenLoc, Allocator,
ColonLoc, EndLoc, Vars);
}
+
+OMPClause *Sema::ActOnOpenMPNontemporalClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ SmallVector<Expr *, 8> Vars;
+ for (Expr *RefExpr : VarList) {
+ assert(RefExpr && "NULL expr in OpenMP nontemporal clause.");
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
+ if (Res.second)
+ // It will be analyzed later.
+ Vars.push_back(RefExpr);
+ ValueDecl *D = Res.first;
+ if (!D)
+ continue;
+
+ // OpenMP 5.0, 2.9.3.1 simd Construct, Restrictions.
+ // A list-item cannot appear in more than one nontemporal clause.
+ if (const Expr *PrevRef =
+ DSAStack->addUniqueNontemporal(D, SimpleRefExpr)) {
+ Diag(ELoc, diag::err_omp_used_in_clause_twice)
+ << 0 << getOpenMPClauseName(OMPC_nontemporal) << ERange;
+ Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa)
+ << getOpenMPClauseName(OMPC_nontemporal);
+ continue;
+ }
+
+ Vars.push_back(RefExpr);
+ }
+
+ if (Vars.empty())
+ return nullptr;
+
+ return OMPNontemporalClause::Create(Context, StartLoc, LParenLoc, EndLoc,
+ Vars);
+}
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 47c1e3cec0ea..0fd932fac970 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -60,14 +60,18 @@ CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl,
// being used.
if (FoundDecl != Fn && S.DiagnoseUseOfDecl(Fn, Loc))
return ExprError();
- if (auto *FPT = Fn->getType()->getAs<FunctionProtoType>())
- S.ResolveExceptionSpec(Loc, FPT);
DeclRefExpr *DRE = new (S.Context)
DeclRefExpr(S.Context, Fn, false, Fn->getType(), VK_LValue, Loc, LocInfo);
if (HadMultipleCandidates)
DRE->setHadMultipleCandidates(true);
S.MarkDeclRefReferenced(DRE, Base);
+ if (auto *FPT = DRE->getType()->getAs<FunctionProtoType>()) {
+ if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
+ S.ResolveExceptionSpec(Loc, FPT);
+ DRE->setType(Fn->getType());
+ }
+ }
return S.ImpCastExprToType(DRE, S.Context.getPointerType(DRE->getType()),
CK_FunctionToPointerDecay);
}
@@ -591,6 +595,12 @@ namespace {
TemplateArgumentList *TemplateArgs;
unsigned CallArgIndex;
};
+ // Structure used by DeductionFailureInfo to store information about
+ // unsatisfied constraints.
+ struct CNSInfo {
+ TemplateArgumentList *TemplateArgs;
+ ConstraintSatisfaction Satisfaction;
+ };
}
/// Convert from Sema's representation of template deduction information
@@ -661,6 +671,14 @@ clang::MakeDeductionFailureInfo(ASTContext &Context,
}
break;
+ case Sema::TDK_ConstraintsNotSatisfied: {
+ CNSInfo *Saved = new (Context) CNSInfo;
+ Saved->TemplateArgs = Info.take();
+ Saved->Satisfaction = Info.AssociatedConstraintsSatisfaction;
+ Result.Data = Saved;
+ break;
+ }
+
case Sema::TDK_Success:
case Sema::TDK_NonDependentConversionFailure:
llvm_unreachable("not a deduction failure");
@@ -701,6 +719,15 @@ void DeductionFailureInfo::Destroy() {
}
break;
+ case Sema::TDK_ConstraintsNotSatisfied:
+ // FIXME: Destroy the template argument list?
+ Data = nullptr;
+ if (PartialDiagnosticAt *Diag = getSFINAEDiagnostic()) {
+ Diag->~PartialDiagnosticAt();
+ HasDiagnostic = false;
+ }
+ break;
+
// Unhandled
case Sema::TDK_MiscellaneousDeductionFailure:
break;
@@ -726,6 +753,7 @@ TemplateParameter DeductionFailureInfo::getTemplateParameter() {
case Sema::TDK_NonDeducedMismatch:
case Sema::TDK_CUDATargetMismatch:
case Sema::TDK_NonDependentConversionFailure:
+ case Sema::TDK_ConstraintsNotSatisfied:
return TemplateParameter();
case Sema::TDK_Incomplete:
@@ -769,6 +797,9 @@ TemplateArgumentList *DeductionFailureInfo::getTemplateArgumentList() {
case Sema::TDK_SubstitutionFailure:
return static_cast<TemplateArgumentList*>(Data);
+ case Sema::TDK_ConstraintsNotSatisfied:
+ return static_cast<CNSInfo*>(Data)->TemplateArgs;
+
// Unhandled
case Sema::TDK_MiscellaneousDeductionFailure:
break;
@@ -789,6 +820,7 @@ const TemplateArgument *DeductionFailureInfo::getFirstArg() {
case Sema::TDK_SubstitutionFailure:
case Sema::TDK_CUDATargetMismatch:
case Sema::TDK_NonDependentConversionFailure:
+ case Sema::TDK_ConstraintsNotSatisfied:
return nullptr;
case Sema::TDK_IncompletePack:
@@ -820,6 +852,7 @@ const TemplateArgument *DeductionFailureInfo::getSecondArg() {
case Sema::TDK_SubstitutionFailure:
case Sema::TDK_CUDATargetMismatch:
case Sema::TDK_NonDependentConversionFailure:
+ case Sema::TDK_ConstraintsNotSatisfied:
return nullptr;
case Sema::TDK_Inconsistent:
@@ -1104,7 +1137,8 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old,
}
bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
- bool UseMemberUsingDeclRules, bool ConsiderCudaAttrs) {
+ bool UseMemberUsingDeclRules, bool ConsiderCudaAttrs,
+ bool ConsiderRequiresClauses) {
// C++ [basic.start.main]p2: This function shall not be overloaded.
if (New->isMain())
return false;
@@ -1240,19 +1274,36 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
if (getLangOpts().CUDA && ConsiderCudaAttrs) {
// Don't allow overloading of destructors. (In theory we could, but it
// would be a giant change to clang.)
- if (isa<CXXDestructorDecl>(New))
- return false;
+ if (!isa<CXXDestructorDecl>(New)) {
+ CUDAFunctionTarget NewTarget = IdentifyCUDATarget(New),
+ OldTarget = IdentifyCUDATarget(Old);
+ if (NewTarget != CFT_InvalidTarget) {
+ assert((OldTarget != CFT_InvalidTarget) &&
+ "Unexpected invalid target.");
- CUDAFunctionTarget NewTarget = IdentifyCUDATarget(New),
- OldTarget = IdentifyCUDATarget(Old);
- if (NewTarget == CFT_InvalidTarget)
- return false;
+ // Allow overloading of functions with same signature and different CUDA
+ // target attributes.
+ if (NewTarget != OldTarget)
+ return true;
+ }
+ }
+ }
- assert((OldTarget != CFT_InvalidTarget) && "Unexpected invalid target.");
+ if (ConsiderRequiresClauses) {
+ Expr *NewRC = New->getTrailingRequiresClause(),
+ *OldRC = Old->getTrailingRequiresClause();
+ if ((NewRC != nullptr) != (OldRC != nullptr))
+ // RC are most certainly different - these are overloads.
+ return true;
- // Allow overloading of functions with same signature and different CUDA
- // target attributes.
- return NewTarget != OldTarget;
+ 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.
@@ -1326,7 +1377,7 @@ TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
ICS.Ambiguous.setToType(ToType);
for (OverloadCandidateSet::iterator Cand = Conversions.begin();
Cand != Conversions.end(); ++Cand)
- if (Cand->Viable)
+ if (Cand->Best)
ICS.Ambiguous.addConversion(Cand->FoundDecl, Cand->Function);
break;
@@ -2802,8 +2853,8 @@ void Sema::HandleFunctionTypeMismatch(PartialDiagnostic &PDiag,
// Get the function type from the pointers.
if (FromType->isMemberPointerType() && ToType->isMemberPointerType()) {
- const MemberPointerType *FromMember = FromType->getAs<MemberPointerType>(),
- *ToMember = ToType->getAs<MemberPointerType>();
+ const auto *FromMember = FromType->castAs<MemberPointerType>(),
+ *ToMember = ToType->castAs<MemberPointerType>();
if (!Context.hasSameType(FromMember->getClass(), ToMember->getClass())) {
PDiag << ft_different_class << QualType(ToMember->getClass(), 0)
<< QualType(FromMember->getClass(), 0);
@@ -2898,8 +2949,12 @@ bool Sema::FunctionParamTypesAreEqual(const FunctionProtoType *OldType,
N = NewType->param_type_begin(),
E = OldType->param_type_end();
O && (O != E); ++O, ++N) {
- if (!Context.hasSameType(O->getUnqualifiedType(),
- N->getUnqualifiedType())) {
+ // Ignore address spaces in pointee type. This is to disallow overloading
+ // on __ptr32/__ptr64 address spaces.
+ QualType Old = Context.removePtrSizeAddrSpace(O->getUnqualifiedType());
+ QualType New = Context.removePtrSizeAddrSpace(N->getUnqualifiedType());
+
+ if (!Context.hasSameType(Old, New)) {
if (ArgPos)
*ArgPos = O - OldType->param_type_begin();
return false;
@@ -3114,6 +3169,70 @@ static bool isNonTrivialObjCLifetimeConversion(Qualifiers FromQuals,
return true;
}
+/// Perform a single iteration of the loop for checking if a qualification
+/// conversion is valid.
+///
+/// Specifically, check whether any change between the qualifiers of \p
+/// FromType and \p ToType is permissible, given knowledge about whether every
+/// outer layer is const-qualified.
+static bool isQualificationConversionStep(QualType FromType, QualType ToType,
+ bool CStyle,
+ bool &PreviousToQualsIncludeConst,
+ bool &ObjCLifetimeConversion) {
+ Qualifiers FromQuals = FromType.getQualifiers();
+ Qualifiers ToQuals = ToType.getQualifiers();
+
+ // Ignore __unaligned qualifier if this type is void.
+ if (ToType.getUnqualifiedType()->isVoidType())
+ FromQuals.removeUnaligned();
+
+ // Objective-C ARC:
+ // Check Objective-C lifetime conversions.
+ if (FromQuals.getObjCLifetime() != ToQuals.getObjCLifetime()) {
+ if (ToQuals.compatiblyIncludesObjCLifetime(FromQuals)) {
+ if (isNonTrivialObjCLifetimeConversion(FromQuals, ToQuals))
+ ObjCLifetimeConversion = true;
+ FromQuals.removeObjCLifetime();
+ ToQuals.removeObjCLifetime();
+ } else {
+ // Qualification conversions cannot cast between different
+ // Objective-C lifetime qualifiers.
+ return false;
+ }
+ }
+
+ // Allow addition/removal of GC attributes but not changing GC attributes.
+ if (FromQuals.getObjCGCAttr() != ToQuals.getObjCGCAttr() &&
+ (!FromQuals.hasObjCGCAttr() || !ToQuals.hasObjCGCAttr())) {
+ FromQuals.removeObjCGCAttr();
+ ToQuals.removeObjCGCAttr();
+ }
+
+ // -- for every j > 0, if const is in cv 1,j then const is in cv
+ // 2,j, and similarly for volatile.
+ if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals))
+ return false;
+
+ // For a C-style cast, just require the address spaces to overlap.
+ // FIXME: Does "superset" also imply the representation of a pointer is the
+ // same? We're assuming that it does here and in compatiblyIncludes.
+ if (CStyle && !ToQuals.isAddressSpaceSupersetOf(FromQuals) &&
+ !FromQuals.isAddressSpaceSupersetOf(ToQuals))
+ return false;
+
+ // -- if the cv 1,j and cv 2,j are different, then const is in
+ // every cv for 0 < k < j.
+ if (!CStyle && FromQuals.getCVRQualifiers() != ToQuals.getCVRQualifiers() &&
+ !PreviousToQualsIncludeConst)
+ return false;
+
+ // Keep track of whether all prior cv-qualifiers in the "to" type
+ // include const.
+ PreviousToQualsIncludeConst =
+ PreviousToQualsIncludeConst && ToQuals.hasConst();
+ return true;
+}
+
/// IsQualificationConversion - Determines whether the conversion from
/// an rvalue of type FromType to ToType is a qualification conversion
/// (C++ 4.4).
@@ -3139,73 +3258,16 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
bool PreviousToQualsIncludeConst = true;
bool UnwrappedAnyPointer = false;
while (Context.UnwrapSimilarTypes(FromType, ToType)) {
- // Within each iteration of the loop, we check the qualifiers to
- // determine if this still looks like a qualification
- // conversion. Then, if all is well, we unwrap one more level of
- // pointers or pointers-to-members and do it all again
- // until there are no more pointers or pointers-to-members left to
- // unwrap.
- UnwrappedAnyPointer = true;
-
- Qualifiers FromQuals = FromType.getQualifiers();
- Qualifiers ToQuals = ToType.getQualifiers();
-
- // Ignore __unaligned qualifier if this type is void.
- if (ToType.getUnqualifiedType()->isVoidType())
- FromQuals.removeUnaligned();
-
- // Objective-C ARC:
- // Check Objective-C lifetime conversions.
- if (FromQuals.getObjCLifetime() != ToQuals.getObjCLifetime() &&
- UnwrappedAnyPointer) {
- if (ToQuals.compatiblyIncludesObjCLifetime(FromQuals)) {
- if (isNonTrivialObjCLifetimeConversion(FromQuals, ToQuals))
- ObjCLifetimeConversion = true;
- FromQuals.removeObjCLifetime();
- ToQuals.removeObjCLifetime();
- } else {
- // Qualification conversions cannot cast between different
- // Objective-C lifetime qualifiers.
- return false;
- }
- }
-
- // Allow addition/removal of GC attributes but not changing GC attributes.
- if (FromQuals.getObjCGCAttr() != ToQuals.getObjCGCAttr() &&
- (!FromQuals.hasObjCGCAttr() || !ToQuals.hasObjCGCAttr())) {
- FromQuals.removeObjCGCAttr();
- ToQuals.removeObjCGCAttr();
- }
-
- // -- for every j > 0, if const is in cv 1,j then const is in cv
- // 2,j, and similarly for volatile.
- if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals))
+ if (!isQualificationConversionStep(FromType, ToType, CStyle,
+ PreviousToQualsIncludeConst,
+ ObjCLifetimeConversion))
return false;
-
- // -- if the cv 1,j and cv 2,j are different, then const is in
- // every cv for 0 < k < j.
- if (!CStyle && FromQuals.getCVRQualifiers() != ToQuals.getCVRQualifiers()
- && !PreviousToQualsIncludeConst)
- return false;
-
- // Keep track of whether all prior cv-qualifiers in the "to" type
- // include const.
- PreviousToQualsIncludeConst
- = PreviousToQualsIncludeConst && ToQuals.hasConst();
- }
-
- // Allows address space promotion by language rules implemented in
- // Type::Qualifiers::isAddressSpaceSupersetOf.
- Qualifiers FromQuals = FromType.getQualifiers();
- Qualifiers ToQuals = ToType.getQualifiers();
- if (!ToQuals.isAddressSpaceSupersetOf(FromQuals) &&
- !FromQuals.isAddressSpaceSupersetOf(ToQuals)) {
- return false;
+ UnwrappedAnyPointer = true;
}
// We are left with FromType and ToType being the pointee types
// after unwrapping the original FromType and ToType the same number
- // of types. If we unwrapped any pointers, and if FromType and
+ // of times. If we unwrapped any pointers, and if FromType and
// ToType have the same unqualified type (since we checked
// qualifiers above), then this is a qualification conversion.
return UnwrappedAnyPointer && Context.hasSameUnqualifiedType(FromType,ToType);
@@ -3242,8 +3304,7 @@ static bool tryAtomicConversion(Sema &S, Expr *From, QualType ToType,
static bool isFirstArgumentCompatibleWithType(ASTContext &Context,
CXXConstructorDecl *Constructor,
QualType Type) {
- const FunctionProtoType *CtorType =
- Constructor->getType()->getAs<FunctionProtoType>();
+ const auto *CtorType = Constructor->getType()->castAs<FunctionProtoType>();
if (CtorType->getNumParams() > 0) {
QualType FirstArg = CtorType->getParamType(0);
if (Context.hasSameUnqualifiedType(Type, FirstArg.getNonReferenceType()))
@@ -3265,8 +3326,7 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
continue;
bool Usable = !Info.Constructor->isInvalidDecl() &&
- S.isInitListConstructor(Info.Constructor) &&
- (AllowExplicit || !Info.Constructor->isExplicit());
+ S.isInitListConstructor(Info.Constructor);
if (Usable) {
// If the first argument is (a reference to) the target type,
// suppress conversions.
@@ -3388,11 +3448,9 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
continue;
bool Usable = !Info.Constructor->isInvalidDecl();
- if (ListInitializing)
- Usable = Usable && (AllowExplicit || !Info.Constructor->isExplicit());
- else
- Usable = Usable &&
- Info.Constructor->isConvertingConstructor(AllowExplicit);
+ if (!ListInitializing)
+ Usable = Usable && Info.Constructor->isConvertingConstructor(
+ /*AllowExplicit*/ true);
if (Usable) {
bool SuppressUserConversions = !ConstructorsOnly;
if (SuppressUserConversions && ListInitializing) {
@@ -3446,16 +3504,14 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
else
Conv = cast<CXXConversionDecl>(D);
- if (AllowExplicit || !Conv->isExplicit()) {
- if (ConvTemplate)
- S.AddTemplateConversionCandidate(
- ConvTemplate, FoundDecl, ActingContext, From, ToType,
- CandidateSet, AllowObjCConversionOnExplicit, AllowExplicit);
- else
- S.AddConversionCandidate(
- Conv, FoundDecl, ActingContext, From, ToType, CandidateSet,
- AllowObjCConversionOnExplicit, AllowExplicit);
- }
+ if (ConvTemplate)
+ S.AddTemplateConversionCandidate(
+ ConvTemplate, FoundDecl, ActingContext, From, ToType,
+ CandidateSet, AllowObjCConversionOnExplicit, AllowExplicit);
+ else
+ S.AddConversionCandidate(
+ Conv, FoundDecl, ActingContext, From, ToType, CandidateSet,
+ AllowObjCConversionOnExplicit, AllowExplicit);
}
}
}
@@ -3547,7 +3603,10 @@ Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) {
(OvResult == OR_No_Viable_Function && !CandidateSet.empty())))
return false;
- auto Cands = CandidateSet.CompleteCandidates(*this, OCD_AllCandidates, From);
+ auto Cands = CandidateSet.CompleteCandidates(
+ *this,
+ OvResult == OR_Ambiguous ? OCD_AmbiguousCandidates : OCD_AllCandidates,
+ From);
if (OvResult == OR_Ambiguous)
Diag(From->getBeginLoc(), diag::err_typecheck_ambiguous_condition)
<< From->getType() << ToType << From->getSourceRange();
@@ -3929,19 +3988,21 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
}
}
- // Compare based on qualification conversions (C++ 13.3.3.2p3,
- // bullet 3).
- if (ImplicitConversionSequence::CompareKind QualCK
- = CompareQualificationConversions(S, SCS1, SCS2))
- return QualCK;
-
if (SCS1.ReferenceBinding && SCS2.ReferenceBinding) {
// Check for a better reference binding based on the kind of bindings.
if (isBetterReferenceBindingKind(SCS1, SCS2))
return ImplicitConversionSequence::Better;
else if (isBetterReferenceBindingKind(SCS2, SCS1))
return ImplicitConversionSequence::Worse;
+ }
+ // Compare based on qualification conversions (C++ 13.3.3.2p3,
+ // bullet 3).
+ if (ImplicitConversionSequence::CompareKind QualCK
+ = CompareQualificationConversions(S, SCS1, SCS2))
+ return QualCK;
+
+ if (SCS1.ReferenceBinding && SCS2.ReferenceBinding) {
// C++ [over.ics.rank]p3b4:
// -- S1 and S2 are reference bindings (8.5.3), and the types to
// which the references refer are the same type except for
@@ -3973,7 +4034,7 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
T2 = S.Context.getQualifiedType(UnqualT2, T2Quals);
if (T2.isMoreQualifiedThan(T1))
return ImplicitConversionSequence::Better;
- else if (T1.isMoreQualifiedThan(T2))
+ if (T1.isMoreQualifiedThan(T2))
return ImplicitConversionSequence::Worse;
}
}
@@ -4047,22 +4108,16 @@ CompareQualificationConversions(Sema &S,
QualType T2 = SCS2.getToType(2);
T1 = S.Context.getCanonicalType(T1);
T2 = S.Context.getCanonicalType(T2);
+ assert(!T1->isReferenceType() && !T2->isReferenceType());
Qualifiers T1Quals, T2Quals;
QualType UnqualT1 = S.Context.getUnqualifiedArrayType(T1, T1Quals);
QualType UnqualT2 = S.Context.getUnqualifiedArrayType(T2, T2Quals);
- // If the types are the same, we won't learn anything by unwrapped
+ // If the types are the same, we won't learn anything by unwrapping
// them.
if (UnqualT1 == UnqualT2)
return ImplicitConversionSequence::Indistinguishable;
- // If the type is an array type, promote the element qualifiers to the type
- // for comparison.
- if (isa<ArrayType>(T1) && T1Quals)
- T1 = S.Context.getQualifiedType(UnqualT1, T1Quals);
- if (isa<ArrayType>(T2) && T2Quals)
- T2 = S.Context.getQualifiedType(UnqualT2, T2Quals);
-
ImplicitConversionSequence::CompareKind Result
= ImplicitConversionSequence::Indistinguishable;
@@ -4290,14 +4345,10 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
if (SCS1.Second == ICK_Pointer_Member && SCS2.Second == ICK_Pointer_Member &&
FromType1->isMemberPointerType() && FromType2->isMemberPointerType() &&
ToType1->isMemberPointerType() && ToType2->isMemberPointerType()) {
- const MemberPointerType * FromMemPointer1 =
- FromType1->getAs<MemberPointerType>();
- const MemberPointerType * ToMemPointer1 =
- ToType1->getAs<MemberPointerType>();
- const MemberPointerType * FromMemPointer2 =
- FromType2->getAs<MemberPointerType>();
- const MemberPointerType * ToMemPointer2 =
- ToType2->getAs<MemberPointerType>();
+ const auto *FromMemPointer1 = FromType1->castAs<MemberPointerType>();
+ const auto *ToMemPointer1 = ToType1->castAs<MemberPointerType>();
+ const auto *FromMemPointer2 = FromType2->castAs<MemberPointerType>();
+ const auto *ToMemPointer2 = ToType2->castAs<MemberPointerType>();
const Type *FromPointeeType1 = FromMemPointer1->getClass();
const Type *ToPointeeType1 = ToMemPointer1->getClass();
const Type *FromPointeeType2 = FromMemPointer2->getClass();
@@ -4360,20 +4411,26 @@ static bool isTypeValid(QualType T) {
return true;
}
+static QualType withoutUnaligned(ASTContext &Ctx, QualType T) {
+ if (!T.getQualifiers().hasUnaligned())
+ return T;
+
+ Qualifiers Q;
+ T = Ctx.getUnqualifiedArrayType(T, Q);
+ Q.removeUnaligned();
+ return Ctx.getQualifiedType(T, Q);
+}
+
/// CompareReferenceRelationship - Compare the two types T1 and T2 to
-/// determine whether they are reference-related,
-/// reference-compatible, reference-compatible with added
-/// qualification, or incompatible, for use in C++ initialization by
+/// determine whether they are reference-compatible,
+/// reference-related, or incompatible, for use in C++ initialization by
/// reference (C++ [dcl.ref.init]p4). Neither type can be a reference
/// type, and the first type (T1) is the pointee type of the reference
/// type being initialized.
Sema::ReferenceCompareResult
Sema::CompareReferenceRelationship(SourceLocation Loc,
QualType OrigT1, QualType OrigT2,
- bool &DerivedToBase,
- bool &ObjCConversion,
- bool &ObjCLifetimeConversion,
- bool &FunctionConversion) {
+ ReferenceConversions *ConvOut) {
assert(!OrigT1->isReferenceType() &&
"T1 must be the pointee type of the reference type");
assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type");
@@ -4384,76 +4441,84 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals);
QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals);
- // C++ [dcl.init.ref]p4:
+ ReferenceConversions ConvTmp;
+ ReferenceConversions &Conv = ConvOut ? *ConvOut : ConvTmp;
+ Conv = ReferenceConversions();
+
+ // C++2a [dcl.init.ref]p4:
// Given types "cv1 T1" and "cv2 T2," "cv1 T1" is
- // reference-related to "cv2 T2" if T1 is the same type as T2, or
+ // reference-related to "cv2 T2" if T1 is similar to T2, or
// T1 is a base class of T2.
- DerivedToBase = false;
- ObjCConversion = false;
- ObjCLifetimeConversion = false;
+ // "cv1 T1" is reference-compatible with "cv2 T2" if
+ // a prvalue of type "pointer to cv2 T2" can be converted to the type
+ // "pointer to cv1 T1" via a standard conversion sequence.
+
+ // Check for standard conversions we can apply to pointers: derived-to-base
+ // conversions, ObjC pointer conversions, and function pointer conversions.
+ // (Qualification conversions are checked last.)
QualType ConvertedT2;
if (UnqualT1 == UnqualT2) {
// Nothing to do.
} else if (isCompleteType(Loc, OrigT2) &&
isTypeValid(UnqualT1) && isTypeValid(UnqualT2) &&
IsDerivedFrom(Loc, UnqualT2, UnqualT1))
- DerivedToBase = true;
+ Conv |= ReferenceConversions::DerivedToBase;
else if (UnqualT1->isObjCObjectOrInterfaceType() &&
UnqualT2->isObjCObjectOrInterfaceType() &&
Context.canBindObjCObjectType(UnqualT1, UnqualT2))
- ObjCConversion = true;
+ Conv |= ReferenceConversions::ObjC;
else if (UnqualT2->isFunctionType() &&
IsFunctionConversion(UnqualT2, UnqualT1, ConvertedT2)) {
- // C++1z [dcl.init.ref]p4:
- // cv1 T1" is reference-compatible with "cv2 T2" if [...] T2 is "noexcept
- // function" and T1 is "function"
- //
- // We extend this to also apply to 'noreturn', so allow any function
- // conversion between function types.
- FunctionConversion = true;
+ Conv |= ReferenceConversions::Function;
+ // No need to check qualifiers; function types don't have them.
return Ref_Compatible;
- } else
- return Ref_Incompatible;
+ }
+ bool ConvertedReferent = Conv != 0;
- // At this point, we know that T1 and T2 are reference-related (at
- // least).
+ // We can have a qualification conversion. Compute whether the types are
+ // similar at the same time.
+ bool PreviousToQualsIncludeConst = true;
+ bool TopLevel = true;
+ do {
+ if (T1 == T2)
+ break;
- // If the type is an array type, promote the element qualifiers to the type
- // for comparison.
- if (isa<ArrayType>(T1) && T1Quals)
- T1 = Context.getQualifiedType(UnqualT1, T1Quals);
- if (isa<ArrayType>(T2) && T2Quals)
- T2 = Context.getQualifiedType(UnqualT2, T2Quals);
+ // We will need a qualification conversion.
+ Conv |= ReferenceConversions::Qualification;
- // C++ [dcl.init.ref]p4:
- // "cv1 T1" is reference-compatible with "cv2 T2" if T1 is
- // reference-related to T2 and cv1 is the same cv-qualification
- // as, or greater cv-qualification than, cv2. For purposes of
- // overload resolution, cases for which cv1 is greater
- // cv-qualification than cv2 are identified as
- // reference-compatible with added qualification (see 13.3.3.2).
- //
- // Note that we also require equivalence of Objective-C GC and address-space
- // qualifiers when performing these computations, so that e.g., an int in
- // address space 1 is not reference-compatible with an int in address
- // space 2.
- if (T1Quals.getObjCLifetime() != T2Quals.getObjCLifetime() &&
- T1Quals.compatiblyIncludesObjCLifetime(T2Quals)) {
- if (isNonTrivialObjCLifetimeConversion(T2Quals, T1Quals))
- ObjCLifetimeConversion = true;
+ // Track whether we performed a qualification conversion anywhere other
+ // than the top level. This matters for ranking reference bindings in
+ // overload resolution.
+ if (!TopLevel)
+ Conv |= ReferenceConversions::NestedQualification;
- T1Quals.removeObjCLifetime();
- T2Quals.removeObjCLifetime();
- }
+ // MS compiler ignores __unaligned qualifier for references; do the same.
+ T1 = withoutUnaligned(Context, T1);
+ T2 = withoutUnaligned(Context, T2);
- // MS compiler ignores __unaligned qualifier for references; do the same.
- T1Quals.removeUnaligned();
- T2Quals.removeUnaligned();
+ // If we find a qualifier mismatch, the types are not reference-compatible,
+ // but are still be reference-related if they're similar.
+ bool ObjCLifetimeConversion = false;
+ if (!isQualificationConversionStep(T2, T1, /*CStyle=*/false,
+ PreviousToQualsIncludeConst,
+ ObjCLifetimeConversion))
+ return (ConvertedReferent || Context.hasSimilarType(T1, T2))
+ ? Ref_Related
+ : Ref_Incompatible;
- if (T1Quals.compatiblyIncludes(T2Quals))
- return Ref_Compatible;
- else
- return Ref_Related;
+ // FIXME: Should we track this for any level other than the first?
+ if (ObjCLifetimeConversion)
+ Conv |= ReferenceConversions::ObjCLifetime;
+
+ TopLevel = false;
+ } while (Context.UnwrapSimilarTypes(T1, T2));
+
+ // At this point, if the types are reference-related, we must either have the
+ // same inner type (ignoring qualifiers), or must have already worked out how
+ // to convert the referent.
+ return (ConvertedReferent || Context.hasSameUnqualifiedType(T1, T2))
+ ? Ref_Compatible
+ : Ref_Incompatible;
}
/// Look for a user-defined conversion to a value reference-compatible
@@ -4464,8 +4529,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
Expr *Init, QualType T2, bool AllowRvalues,
bool AllowExplicit) {
assert(T2->isRecordType() && "Can only find conversions of record types.");
- CXXRecordDecl *T2RecordDecl
- = dyn_cast<CXXRecordDecl>(T2->castAs<RecordType>()->getDecl());
+ auto *T2RecordDecl = cast<CXXRecordDecl>(T2->castAs<RecordType>()->getDecl());
OverloadCandidateSet CandidateSet(
DeclLoc, OverloadCandidateSet::CSK_InitByUserDefinedConversion);
@@ -4484,17 +4548,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
else
Conv = cast<CXXConversionDecl>(D);
- // If this is an explicit conversion, and we're not allowed to consider
- // explicit conversions, skip it.
- if (!AllowExplicit && Conv->isExplicit())
- continue;
-
if (AllowRvalues) {
- bool DerivedToBase = false;
- bool ObjCConversion = false;
- bool ObjCLifetimeConversion = false;
- bool FunctionConversion = false;
-
// If we are initializing an rvalue reference, don't permit conversion
// functions that return lvalues.
if (!ConvTemplate && DeclType->isRValueReferenceType()) {
@@ -4510,9 +4564,8 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
Conv->getConversionType()
.getNonReferenceType()
.getUnqualifiedType(),
- DeclType.getNonReferenceType().getUnqualifiedType(),
- DerivedToBase, ObjCConversion, ObjCLifetimeConversion,
- FunctionConversion) == Sema::Ref_Incompatible)
+ DeclType.getNonReferenceType().getUnqualifiedType()) ==
+ Sema::Ref_Incompatible)
continue;
} else {
// If the conversion function doesn't return a reference type,
@@ -4571,7 +4624,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
ICS.setAmbiguous();
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin();
Cand != CandidateSet.end(); ++Cand)
- if (Cand->Viable)
+ if (Cand->Best)
ICS.Ambiguous.addConversion(Cand->FoundDecl, Cand->Function);
return true;
@@ -4613,14 +4666,44 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
// Compute some basic properties of the types and the initializer.
bool isRValRef = DeclType->isRValueReferenceType();
- bool DerivedToBase = false;
- bool ObjCConversion = false;
- bool ObjCLifetimeConversion = false;
- bool FunctionConversion = false;
Expr::Classification InitCategory = Init->Classify(S.Context);
- Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship(
- DeclLoc, T1, T2, DerivedToBase, ObjCConversion, ObjCLifetimeConversion,
- FunctionConversion);
+
+ Sema::ReferenceConversions RefConv;
+ Sema::ReferenceCompareResult RefRelationship =
+ S.CompareReferenceRelationship(DeclLoc, T1, T2, &RefConv);
+
+ auto SetAsReferenceBinding = [&](bool BindsDirectly) {
+ ICS.setStandard();
+ ICS.Standard.First = ICK_Identity;
+ // FIXME: A reference binding can be a function conversion too. We should
+ // consider that when ordering reference-to-function bindings.
+ ICS.Standard.Second = (RefConv & Sema::ReferenceConversions::DerivedToBase)
+ ? ICK_Derived_To_Base
+ : (RefConv & Sema::ReferenceConversions::ObjC)
+ ? ICK_Compatible_Conversion
+ : ICK_Identity;
+ // FIXME: As a speculative fix to a defect introduced by CWG2352, we rank
+ // a reference binding that performs a non-top-level qualification
+ // conversion as a qualification conversion, not as an identity conversion.
+ ICS.Standard.Third = (RefConv &
+ Sema::ReferenceConversions::NestedQualification)
+ ? ICK_Qualification
+ : ICK_Identity;
+ ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
+ ICS.Standard.setToType(0, T2);
+ ICS.Standard.setToType(1, T1);
+ ICS.Standard.setToType(2, T1);
+ ICS.Standard.ReferenceBinding = true;
+ ICS.Standard.DirectBinding = BindsDirectly;
+ ICS.Standard.IsLvalueReference = !isRValRef;
+ ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
+ ICS.Standard.BindsToRvalue = InitCategory.isRValue();
+ ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
+ ICS.Standard.ObjCLifetimeConversionBinding =
+ (RefConv & Sema::ReferenceConversions::ObjCLifetime) != 0;
+ ICS.Standard.CopyConstructor = nullptr;
+ ICS.Standard.DeprecatedStringLiteralToCharPtr = false;
+ };
// C++0x [dcl.init.ref]p5:
// A reference to type "cv1 T1" is initialized by an expression
@@ -4640,25 +4723,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
// has a type that is a derived class of the parameter type,
// in which case the implicit conversion sequence is a
// derived-to-base Conversion (13.3.3.1).
- ICS.setStandard();
- ICS.Standard.First = ICK_Identity;
- ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base
- : ObjCConversion? ICK_Compatible_Conversion
- : ICK_Identity;
- ICS.Standard.Third = ICK_Identity;
- ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
- ICS.Standard.setToType(0, T2);
- ICS.Standard.setToType(1, T1);
- ICS.Standard.setToType(2, T1);
- ICS.Standard.ReferenceBinding = true;
- ICS.Standard.DirectBinding = true;
- ICS.Standard.IsLvalueReference = !isRValRef;
- ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
- ICS.Standard.BindsToRvalue = false;
- ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
- ICS.Standard.ObjCLifetimeConversionBinding = ObjCLifetimeConversion;
- ICS.Standard.CopyConstructor = nullptr;
- ICS.Standard.DeprecatedStringLiteralToCharPtr = false;
+ SetAsReferenceBinding(/*BindsDirectly=*/true);
// Nothing more to do: the inaccessibility/ambiguity check for
// derived-to-base conversions is suppressed when we're
@@ -4696,34 +4761,16 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
// lvalue and "cv1 T1" is reference-compatible with "cv2 T2", or
if (RefRelationship == Sema::Ref_Compatible &&
(InitCategory.isXValue() ||
- (InitCategory.isPRValue() && (T2->isRecordType() || T2->isArrayType())) ||
+ (InitCategory.isPRValue() &&
+ (T2->isRecordType() || T2->isArrayType())) ||
(InitCategory.isLValue() && T2->isFunctionType()))) {
- ICS.setStandard();
- ICS.Standard.First = ICK_Identity;
- ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base
- : ObjCConversion? ICK_Compatible_Conversion
- : ICK_Identity;
- ICS.Standard.Third = ICK_Identity;
- ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
- ICS.Standard.setToType(0, T2);
- ICS.Standard.setToType(1, T1);
- ICS.Standard.setToType(2, T1);
- ICS.Standard.ReferenceBinding = true;
- // In C++0x, this is always a direct binding. In C++98/03, it's a direct
+ // In C++11, this is always a direct binding. In C++98/03, it's a direct
// binding unless we're binding to a class prvalue.
// Note: Although xvalues wouldn't normally show up in C++98/03 code, we
// allow the use of rvalue references in C++98/03 for the benefit of
// standard library implementors; therefore, we need the xvalue check here.
- ICS.Standard.DirectBinding =
- S.getLangOpts().CPlusPlus11 ||
- !(InitCategory.isPRValue() || T2->isRecordType());
- ICS.Standard.IsLvalueReference = !isRValRef;
- ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
- ICS.Standard.BindsToRvalue = InitCategory.isRValue();
- ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
- ICS.Standard.ObjCLifetimeConversionBinding = ObjCLifetimeConversion;
- ICS.Standard.CopyConstructor = nullptr;
- ICS.Standard.DeprecatedStringLiteralToCharPtr = false;
+ SetAsReferenceBinding(/*BindsDirectly=*/S.getLangOpts().CPlusPlus11 ||
+ !(InitCategory.isPRValue() || T2->isRecordType()));
return ICS;
}
@@ -5042,13 +5089,8 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
}
// Compute some basic properties of the types and the initializer.
- bool dummy1 = false;
- bool dummy2 = false;
- bool dummy3 = false;
- bool dummy4 = false;
Sema::ReferenceCompareResult RefRelationship =
- S.CompareReferenceRelationship(From->getBeginLoc(), T1, T2, dummy1,
- dummy2, dummy3, dummy4);
+ S.CompareReferenceRelationship(From->getBeginLoc(), T1, T2);
if (RefRelationship >= Sema::Ref_Related) {
return TryReferenceInit(S, Init, ToType, /*FIXME*/ From->getBeginLoc(),
@@ -5218,7 +5260,7 @@ TryObjectArgumentInitialization(Sema &S, SourceLocation Loc, QualType FromType,
return ICS;
}
- if (FromTypeCanon.getQualifiers().hasAddressSpace()) {
+ if (FromTypeCanon.hasAddressSpace()) {
Qualifiers QualsImplicitParamType = ImplicitParamType.getQualifiers();
Qualifiers QualsFromType = FromTypeCanon.getQualifiers();
if (!QualsImplicitParamType.isAddressSpaceSupersetOf(QualsFromType)) {
@@ -5367,7 +5409,10 @@ Sema::PerformObjectArgumentInitialization(Expr *From,
if (!Context.hasSameType(From->getType(), DestType)) {
CastKind CK;
- if (FromRecordType.getAddressSpace() != DestType.getAddressSpace())
+ QualType PteeTy = DestType->getPointeeType();
+ LangAS DestAS =
+ PteeTy.isNull() ? DestType.getAddressSpace() : PteeTy.getAddressSpace();
+ if (FromRecordType.getAddressSpace() != DestAS)
CK = CK_AddressSpaceConversion;
else
CK = CK_NoOp;
@@ -6046,7 +6091,7 @@ static bool IsAcceptableNonMemberOperatorCandidate(ASTContext &Context,
if (T1->isRecordType() || (!T2.isNull() && T2->isRecordType()))
return true;
- const FunctionProtoType *Proto = Fn->getType()->getAs<FunctionProtoType>();
+ const auto *Proto = Fn->getType()->castAs<FunctionProtoType>();
if (Proto->getNumParams() < 1)
return false;
@@ -6146,6 +6191,15 @@ void Sema::AddOverloadCandidate(
Candidate.IgnoreObjectArgument = false;
Candidate.ExplicitCallArguments = Args.size();
+ // Explicit functions are not actually candidates at all if we're not
+ // allowing them in this context, but keep them around so we can point
+ // to them in diagnostics.
+ if (!AllowExplicit && ExplicitSpecifier::getFromDecl(Function).isExplicit()) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_explicit;
+ return;
+ }
+
if (Function->isMultiVersion() && Function->hasAttr<TargetAttr>() &&
!Function->getAttr<TargetAttr>()->isDefaultVersion()) {
Candidate.Viable = false;
@@ -6237,6 +6291,16 @@ void Sema::AddOverloadCandidate(
return;
}
+ if (Expr *RequiresClause = Function->getTrailingRequiresClause()) {
+ ConstraintSatisfaction Satisfaction;
+ if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) ||
+ !Satisfaction.IsSatisfied) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
+ return;
+ }
+ }
+
// Determine the implicit conversion sequences for each of the
// arguments.
for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {
@@ -6269,15 +6333,6 @@ void Sema::AddOverloadCandidate(
}
}
- if (!AllowExplicit) {
- ExplicitSpecifier ES = ExplicitSpecifier::getFromDecl(Function);
- if (ES.getKind() != ExplicitSpecKind::ResolvedFalse) {
- Candidate.Viable = false;
- Candidate.FailureKind = ovl_fail_explicit_resolved;
- return;
- }
- }
-
if (EnableIfAttr *FailedAttr = CheckEnableIf(Function, Args)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_enable_if;
@@ -6753,6 +6808,16 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
return;
}
+ if (Expr *RequiresClause = Method->getTrailingRequiresClause()) {
+ ConstraintSatisfaction Satisfaction;
+ if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) ||
+ !Satisfaction.IsSatisfied) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
+ return;
+ }
+ }
+
// Determine the implicit conversion sequences for each of the
// arguments.
for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {
@@ -6866,6 +6931,12 @@ void Sema::AddMethodTemplateCandidate(
Conversions, PO);
}
+/// Determine whether a given function template has a simple explicit specifier
+/// or a non-value-dependent explicit-specification that evaluates to true.
+static bool isNonDependentlyExplicit(FunctionTemplateDecl *FTD) {
+ return ExplicitSpecifier::getFromDecl(FTD->getTemplatedDecl()).isExplicit();
+}
+
/// Add a C++ function template specialization as a candidate
/// in the candidate set, using template argument deduction to produce
/// an appropriate function template specialization.
@@ -6878,6 +6949,18 @@ void Sema::AddTemplateOverloadCandidate(
if (!CandidateSet.isNewCandidate(FunctionTemplate, PO))
return;
+ // If the function template has a non-dependent explicit specification,
+ // exclude it now if appropriate; we are not permitted to perform deduction
+ // and substitution in this case.
+ if (!AllowExplicit && isNonDependentlyExplicit(FunctionTemplate)) {
+ OverloadCandidate &Candidate = CandidateSet.addCandidate();
+ Candidate.FoundDecl = FoundDecl;
+ Candidate.Function = FunctionTemplate->getTemplatedDecl();
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_explicit;
+ return;
+ }
+
// C++ [over.match.funcs]p7:
// In each case where a candidate is a function template, candidate
// function template specializations are generated using template argument
@@ -7065,6 +7148,9 @@ void Sema::AddConversionCandidate(
// Per C++ [over.match.conv]p1, [over.match.ref]p1, an explicit conversion
// operator is only a candidate if its return type is the target type or
// can be converted to the target type with a qualification conversion.
+ //
+ // FIXME: Include such functions in the candidate list and explain why we
+ // can't select them.
if (Conversion->isExplicit() &&
!isAllowableExplicitConversion(*this, ConvType, ToType,
AllowObjCConversionOnExplicit))
@@ -7086,6 +7172,15 @@ void Sema::AddConversionCandidate(
Candidate.Viable = true;
Candidate.ExplicitCallArguments = 1;
+ // Explicit functions are not actually candidates at all if we're not
+ // allowing them in this context, but keep them around so we can point
+ // to them in diagnostics.
+ if (!AllowExplicit && Conversion->isExplicit()) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_explicit;
+ return;
+ }
+
// C++ [over.match.funcs]p4:
// For conversion functions, the function is considered to be a member of
// the class of the implicit implied object argument for the purpose of
@@ -7109,6 +7204,17 @@ void Sema::AddConversionCandidate(
return;
}
+ Expr *RequiresClause = Conversion->getTrailingRequiresClause();
+ if (RequiresClause) {
+ ConstraintSatisfaction Satisfaction;
+ if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) ||
+ !Satisfaction.IsSatisfied) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
+ return;
+ }
+ }
+
// We won't go through a user-defined type conversion function to convert a
// derived to base as such conversions are given Conversion Rank. They only
// go through a copy constructor. 13.3.3.1.2-p4 [over.ics.user]
@@ -7199,13 +7305,6 @@ void Sema::AddConversionCandidate(
"Can only end up with a standard conversion sequence or failure");
}
- if (!AllowExplicit && Conversion->getExplicitSpecifier().getKind() !=
- ExplicitSpecKind::ResolvedFalse) {
- Candidate.Viable = false;
- Candidate.FailureKind = ovl_fail_explicit_resolved;
- return;
- }
-
if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, None)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_enable_if;
@@ -7236,6 +7335,18 @@ void Sema::AddTemplateConversionCandidate(
if (!CandidateSet.isNewCandidate(FunctionTemplate))
return;
+ // If the function template has a non-dependent explicit specification,
+ // exclude it now if appropriate; we are not permitted to perform deduction
+ // and substitution in this case.
+ if (!AllowExplicit && isNonDependentlyExplicit(FunctionTemplate)) {
+ OverloadCandidate &Candidate = CandidateSet.addCandidate();
+ Candidate.FoundDecl = FoundDecl;
+ Candidate.Function = FunctionTemplate->getTemplatedDecl();
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_explicit;
+ return;
+ }
+
TemplateDeductionInfo Info(CandidateSet.getLocation());
CXXConversionDecl *Specialization = nullptr;
if (TemplateDeductionResult Result
@@ -9440,6 +9551,35 @@ bool clang::isBetterOverloadCandidate(
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 (Cand1.Function && Cand2.Function && !Cand1IsSpecialization &&
+ !Cand2IsSpecialization && Cand1.Function->hasPrototype() &&
+ Cand2.Function->hasPrototype()) {
+ auto *PT1 = cast<FunctionProtoType>(Cand1.Function->getFunctionType());
+ auto *PT2 = cast<FunctionProtoType>(Cand2.Function->getFunctionType());
+ if (PT1->getNumParams() == PT2->getNumParams() &&
+ PT1->isVariadic() == PT2->isVariadic() &&
+ S.FunctionParamTypesAreEqual(PT1, PT2)) {
+ Expr *RC1 = Cand1.Function->getTrailingRequiresClause();
+ Expr *RC2 = Cand2.Function->getTrailingRequiresClause();
+ if (RC1 && RC2) {
+ bool AtLeastAsConstrained1, AtLeastAsConstrained2;
+ if (S.IsAtLeastAsConstrained(Cand1.Function, {RC1}, Cand2.Function,
+ {RC2}, AtLeastAsConstrained1))
+ return false;
+ if (!AtLeastAsConstrained1)
+ return false;
+ if (S.IsAtLeastAsConstrained(Cand2.Function, {RC2}, Cand1.Function,
+ {RC1}, AtLeastAsConstrained2))
+ return false;
+ if (!AtLeastAsConstrained2)
+ return true;
+ } else if (RC1 || RC2)
+ return RC1 != nullptr;
+ }
+ }
+
// -- F1 is a constructor for a class D, F2 is a constructor for a base
// class B of D, and for all arguments the corresponding parameters of
// F1 and F2 have the same type.
@@ -9527,8 +9667,7 @@ bool Sema::isEquivalentInternalLinkageDeclaration(const NamedDecl *A,
// entity in different modules.
if (!VA->getDeclContext()->getRedeclContext()->Equals(
VB->getDeclContext()->getRedeclContext()) ||
- getOwningModule(const_cast<ValueDecl *>(VA)) ==
- getOwningModule(const_cast<ValueDecl *>(VB)) ||
+ getOwningModule(VA) == getOwningModule(VB) ||
VA->isExternallyVisible() || VB->isExternallyVisible())
return false;
@@ -9565,12 +9704,12 @@ void Sema::diagnoseEquivalentInternalLinkageDeclarations(
SourceLocation Loc, const NamedDecl *D, ArrayRef<const NamedDecl *> Equiv) {
Diag(Loc, diag::ext_equivalent_internal_linkage_decl_in_modules) << D;
- Module *M = getOwningModule(const_cast<NamedDecl*>(D));
+ Module *M = getOwningModule(D);
Diag(D->getLocation(), diag::note_equivalent_internal_linkage_decl)
<< !M << (M ? M->getFullModuleName() : "");
for (auto *E : Equiv) {
- Module *M = getOwningModule(const_cast<NamedDecl*>(E));
+ Module *M = getOwningModule(E);
Diag(E->getLocation(), diag::note_equivalent_internal_linkage_decl)
<< !M << (M ? M->getFullModuleName() : "");
}
@@ -9622,11 +9761,13 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
// Find the best viable function.
Best = end();
- for (auto *Cand : Candidates)
+ for (auto *Cand : Candidates) {
+ Cand->Best = false;
if (Cand->Viable)
if (Best == end() ||
isBetterOverloadCandidate(S, *Cand, *Best, Loc, Kind))
Best = Cand;
+ }
// If we didn't find any viable functions, abort.
if (Best == end())
@@ -9634,22 +9775,33 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
llvm::SmallVector<const NamedDecl *, 4> EquivalentCands;
+ llvm::SmallVector<OverloadCandidate*, 4> PendingBest;
+ PendingBest.push_back(&*Best);
+ Best->Best = true;
+
// Make sure that this function is better than every other viable
// function. If not, we have an ambiguity.
- for (auto *Cand : Candidates) {
- if (Cand->Viable && Cand != Best &&
- !isBetterOverloadCandidate(S, *Best, *Cand, Loc, Kind)) {
- if (S.isEquivalentInternalLinkageDeclaration(Best->Function,
- Cand->Function)) {
- EquivalentCands.push_back(Cand->Function);
- continue;
- }
+ while (!PendingBest.empty()) {
+ auto *Curr = PendingBest.pop_back_val();
+ for (auto *Cand : Candidates) {
+ if (Cand->Viable && !Cand->Best &&
+ !isBetterOverloadCandidate(S, *Curr, *Cand, Loc, Kind)) {
+ PendingBest.push_back(Cand);
+ Cand->Best = true;
- Best = end();
- return OR_Ambiguous;
+ if (S.isEquivalentInternalLinkageDeclaration(Cand->Function,
+ Curr->Function))
+ EquivalentCands.push_back(Cand->Function);
+ else
+ Best = end();
+ }
}
}
+ // If we found more than one best candidate, this is ambiguous.
+ if (Best == end())
+ return OR_Ambiguous;
+
// Best is the best viable function.
if (Best->Function && Best->Function->isDeleted())
return OR_Deleted;
@@ -9673,6 +9825,7 @@ enum OverloadCandidateKind {
oc_implicit_move_constructor,
oc_implicit_copy_assignment,
oc_implicit_move_assignment,
+ oc_implicit_equality_comparison,
oc_inherited_constructor
};
@@ -9701,6 +9854,9 @@ ClassifyOverloadCandidate(Sema &S, NamedDecl *Found, FunctionDecl *Fn,
}();
OverloadCandidateKind Kind = [&]() {
+ if (Fn->isImplicit() && Fn->getOverloadedOperator() == OO_EqualEqual)
+ return oc_implicit_equality_comparison;
+
if (CRK & CRK_Reversed)
return oc_reversed_binary_operator;
@@ -9791,6 +9947,24 @@ static bool checkAddressOfFunctionIsAvailable(Sema &S, const FunctionDecl *FD,
return false;
}
+ if (const Expr *RC = FD->getTrailingRequiresClause()) {
+ ConstraintSatisfaction Satisfaction;
+ if (S.CheckConstraintSatisfaction(RC, Satisfaction))
+ return false;
+ if (!Satisfaction.IsSatisfied) {
+ if (Complain) {
+ if (InOverloadResolution)
+ S.Diag(FD->getBeginLoc(),
+ diag::note_ovl_candidate_unsatisfied_constraints);
+ else
+ S.Diag(Loc, diag::err_addrof_function_constraints_not_satisfied)
+ << FD;
+ S.DiagnoseUnsatisfiedConstraint(Satisfaction);
+ }
+ return false;
+ }
+ }
+
auto I = llvm::find_if(FD->parameters(), [](const ParmVarDecl *P) {
return P->hasAttr<PassObjectSizeAttr>();
});
@@ -9848,6 +10022,55 @@ void Sema::NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn,
MaybeEmitInheritedConstructorNote(*this, Found);
}
+static void
+MaybeDiagnoseAmbiguousConstraints(Sema &S, ArrayRef<OverloadCandidate> Cands) {
+ // Perhaps the ambiguity was caused by two atomic constraints that are
+ // 'identical' but not equivalent:
+ //
+ // void foo() requires (sizeof(T) > 4) { } // #1
+ // void foo() requires (sizeof(T) > 4) && T::value { } // #2
+ //
+ // The 'sizeof(T) > 4' constraints are seemingly equivalent and should cause
+ // #2 to subsume #1, but these constraint are not considered equivalent
+ // according to the subsumption rules because they are not the same
+ // source-level construct. This behavior is quite confusing and we should try
+ // to help the user figure out what happened.
+
+ SmallVector<const Expr *, 3> FirstAC, SecondAC;
+ FunctionDecl *FirstCand = nullptr, *SecondCand = nullptr;
+ for (auto I = Cands.begin(), E = Cands.end(); I != E; ++I) {
+ if (!I->Function)
+ continue;
+ SmallVector<const Expr *, 3> AC;
+ if (auto *Template = I->Function->getPrimaryTemplate())
+ Template->getAssociatedConstraints(AC);
+ else
+ I->Function->getAssociatedConstraints(AC);
+ if (AC.empty())
+ continue;
+ if (FirstCand == nullptr) {
+ FirstCand = I->Function;
+ FirstAC = AC;
+ } else if (SecondCand == nullptr) {
+ SecondCand = I->Function;
+ SecondAC = AC;
+ } else {
+ // We have more than one pair of constrained functions - this check is
+ // expensive and we'd rather not try to diagnose it.
+ return;
+ }
+ }
+ if (!SecondCand)
+ return;
+ // The diagnostic can only happen if there are associated constraints on
+ // both sides (there needs to be some identical atomic constraint).
+ if (S.MaybeEmitAmbiguousAtomicConstraintsDiagnostic(FirstCand, FirstAC,
+ SecondCand, SecondAC))
+ // Just show the user one diagnostic, they'll probably figure it out
+ // from here.
+ return;
+}
+
// Notes the location of all overload candidates designated through
// OverloadedExpr
void Sema::NoteAllOverloadCandidates(Expr *OverloadedExpr, QualType DestType,
@@ -9916,7 +10139,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
std::string FnDesc;
std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =
- ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, Cand->RewriteKind,
+ ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, Cand->getRewriteKind(),
FnDesc);
Expr *FromExpr = Conv.Bad.FromExpr;
@@ -9959,10 +10182,17 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
Qualifiers ToQs = CToTy.getQualifiers();
if (FromQs.getAddressSpace() != ToQs.getAddressSpace()) {
- S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_addrspace)
- << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
- << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy
- << ToTy << (unsigned)isObjectArgument << I + 1;
+ if (isObjectArgument)
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_addrspace_this)
+ << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second
+ << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+ << FromQs.getAddressSpace() << ToQs.getAddressSpace();
+ else
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_addrspace)
+ << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second
+ << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+ << FromQs.getAddressSpace() << ToQs.getAddressSpace()
+ << ToTy->isReferenceType() << I + 1;
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
@@ -10167,7 +10397,7 @@ static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D,
FunctionDecl *Fn = cast<FunctionDecl>(D);
// TODO: treat calls to a missing default constructor as a special case
- const FunctionProtoType *FnTy = Fn->getType()->getAs<FunctionProtoType>();
+ const auto *FnTy = Fn->getType()->castAs<FunctionProtoType>();
unsigned MinParams = Fn->getMinRequiredArguments();
// at least / at most / exactly
@@ -10303,6 +10533,16 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
which = 2;
}
+ // Tweak the diagnostic if the problem is that we deduced packs of
+ // different arities. We'll print the actual packs anyway in case that
+ // includes additional useful information.
+ if (DeductionFailure.getFirstArg()->getKind() == TemplateArgument::Pack &&
+ DeductionFailure.getSecondArg()->getKind() == TemplateArgument::Pack &&
+ DeductionFailure.getFirstArg()->pack_size() !=
+ DeductionFailure.getSecondArg()->pack_size()) {
+ which = 3;
+ }
+
S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_inconsistent_deduction)
<< which << ParamD->getDeclName() << *DeductionFailure.getFirstArg()
@@ -10333,6 +10573,23 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
MaybeEmitInheritedConstructorNote(S, Found);
return;
+ case Sema::TDK_ConstraintsNotSatisfied: {
+ // Format the template argument list into the argument string.
+ SmallString<128> TemplateArgString;
+ TemplateArgumentList *Args = DeductionFailure.getTemplateArgumentList();
+ TemplateArgString = " ";
+ TemplateArgString += S.getTemplateArgumentBindingsText(
+ getDescribedTemplate(Templated)->getTemplateParameters(), *Args);
+ if (TemplateArgString.size() == 1)
+ TemplateArgString.clear();
+ S.Diag(Templated->getLocation(),
+ diag::note_ovl_candidate_unsatisfied_constraints)
+ << TemplateArgString;
+
+ S.DiagnoseUnsatisfiedConstraint(
+ static_cast<CNSInfo*>(DeductionFailure.Data)->Satisfaction);
+ return;
+ }
case Sema::TDK_TooManyArguments:
case Sema::TDK_TooFewArguments:
DiagnoseArityMismatch(S, Found, Templated, NumArgs);
@@ -10352,6 +10609,8 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
TemplateArgString = " ";
TemplateArgString += S.getTemplateArgumentBindingsText(
getDescribedTemplate(Templated)->getTemplateParameters(), *Args);
+ if (TemplateArgString.size() == 1)
+ TemplateArgString.clear();
}
// If this candidate was disabled by enable_if, say so.
@@ -10401,6 +10660,8 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
TemplateArgString = " ";
TemplateArgString += S.getTemplateArgumentBindingsText(
getDescribedTemplate(Templated)->getTemplateParameters(), *Args);
+ if (TemplateArgString.size() == 1)
+ TemplateArgString.clear();
}
S.Diag(Templated->getLocation(), diag::note_ovl_candidate_deduced_mismatch)
@@ -10486,8 +10747,8 @@ static void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) {
std::string FnDesc;
std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =
- ClassifyOverloadCandidate(S, Cand->FoundDecl, Callee, Cand->RewriteKind,
- FnDesc);
+ ClassifyOverloadCandidate(S, Cand->FoundDecl, Callee,
+ Cand->getRewriteKind(), FnDesc);
S.Diag(Callee->getLocation(), diag::note_ovl_candidate_bad_target)
<< (unsigned)FnKindPair.first << (unsigned)ocs_non_template
@@ -10545,30 +10806,36 @@ static void DiagnoseFailedEnableIfAttr(Sema &S, OverloadCandidate *Cand) {
}
static void DiagnoseFailedExplicitSpec(Sema &S, OverloadCandidate *Cand) {
- ExplicitSpecifier ES;
- const char *DeclName;
+ ExplicitSpecifier ES = ExplicitSpecifier::getFromDecl(Cand->Function);
+ assert(ES.isExplicit() && "not an explicit candidate");
+
+ unsigned Kind;
switch (Cand->Function->getDeclKind()) {
case Decl::Kind::CXXConstructor:
- ES = cast<CXXConstructorDecl>(Cand->Function)->getExplicitSpecifier();
- DeclName = "constructor";
+ Kind = 0;
break;
case Decl::Kind::CXXConversion:
- ES = cast<CXXConversionDecl>(Cand->Function)->getExplicitSpecifier();
- DeclName = "conversion operator";
+ Kind = 1;
break;
case Decl::Kind::CXXDeductionGuide:
- ES = cast<CXXDeductionGuideDecl>(Cand->Function)->getExplicitSpecifier();
- DeclName = "deductiong guide";
+ Kind = Cand->Function->isImplicit() ? 0 : 2;
break;
default:
llvm_unreachable("invalid Decl");
}
- assert(ES.getExpr() && "null expression should be handled before");
- S.Diag(Cand->Function->getLocation(),
- diag::note_ovl_candidate_explicit_forbidden)
- << DeclName;
- S.Diag(ES.getExpr()->getBeginLoc(),
- diag::note_explicit_bool_resolved_to_true);
+
+ // Note the location of the first (in-class) declaration; a redeclaration
+ // (particularly an out-of-class definition) will typically lack the
+ // 'explicit' specifier.
+ // FIXME: This is probably a good thing to do for all 'candidate' notes.
+ FunctionDecl *First = Cand->Function->getFirstDecl();
+ if (FunctionDecl *Pattern = First->getTemplateInstantiationPattern())
+ First = Pattern->getFirstDecl();
+
+ S.Diag(First->getLocation(),
+ diag::note_ovl_candidate_explicit)
+ << Kind << (ES.getExpr() ? 1 : 0)
+ << (ES.getExpr() ? ES.getExpr()->getSourceRange() : SourceRange());
}
static void DiagnoseOpenCLExtensionDisabled(Sema &S, OverloadCandidate *Cand) {
@@ -10605,8 +10872,8 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
if (Fn->isDeleted()) {
std::string FnDesc;
std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =
- ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, Cand->RewriteKind,
- FnDesc);
+ ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn,
+ Cand->getRewriteKind(), FnDesc);
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted)
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
@@ -10616,7 +10883,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
}
// We don't really have anything else to say about viable candidates.
- S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->RewriteKind);
+ S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->getRewriteKind());
return;
}
@@ -10649,7 +10916,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
case ovl_fail_trivial_conversion:
case ovl_fail_bad_final_conversion:
case ovl_fail_final_conversion_not_exact:
- return S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->RewriteKind);
+ return S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->getRewriteKind());
case ovl_fail_bad_conversion: {
unsigned I = (Cand->IgnoreObjectArgument ? 1 : 0);
@@ -10660,7 +10927,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
// FIXME: this currently happens when we're called from SemaInit
// when user-conversion overload fails. Figure out how to handle
// those conditions and diagnose them well.
- return S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->RewriteKind);
+ return S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->getRewriteKind());
}
case ovl_fail_bad_target:
@@ -10669,7 +10936,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
case ovl_fail_enable_if:
return DiagnoseFailedEnableIfAttr(S, Cand);
- case ovl_fail_explicit_resolved:
+ case ovl_fail_explicit:
return DiagnoseFailedExplicitSpec(S, Cand);
case ovl_fail_ext_disabled:
@@ -10695,6 +10962,23 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
case ovl_non_default_multiversion_function:
// Do nothing, these should simply be ignored.
break;
+
+ case ovl_fail_constraints_not_satisfied: {
+ std::string FnDesc;
+ std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =
+ ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn,
+ Cand->getRewriteKind(), FnDesc);
+
+ S.Diag(Fn->getLocation(),
+ diag::note_ovl_candidate_constraints_not_satisfied)
+ << (unsigned)FnKindPair.first << (unsigned)ocs_non_template
+ << FnDesc /* Ignored */;
+ ConstraintSatisfaction Satisfaction;
+ if (S.CheckConstraintSatisfaction(Fn->getTrailingRequiresClause(),
+ Satisfaction))
+ break;
+ S.DiagnoseUnsatisfiedConstraint(Satisfaction);
+ }
}
}
@@ -10785,6 +11069,7 @@ static unsigned RankDeductionFailure(const DeductionFailureInfo &DFI) {
case Sema::TDK_SubstitutionFailure:
case Sema::TDK_DeducedMismatch:
+ case Sema::TDK_ConstraintsNotSatisfied:
case Sema::TDK_DeducedMismatchNested:
case Sema::TDK_NonDeducedMismatch:
case Sema::TDK_MiscellaneousDeductionFailure:
@@ -10816,6 +11101,23 @@ struct CompareOverloadCandidatesForDisplay {
OverloadCandidateSet::CandidateSetKind CSK)
: S(S), NumArgs(NArgs), CSK(CSK) {}
+ OverloadFailureKind EffectiveFailureKind(const OverloadCandidate *C) const {
+ // If there are too many or too few arguments, that's the high-order bit we
+ // want to sort by, even if the immediate failure kind was something else.
+ if (C->FailureKind == ovl_fail_too_many_arguments ||
+ C->FailureKind == ovl_fail_too_few_arguments)
+ return static_cast<OverloadFailureKind>(C->FailureKind);
+
+ if (C->Function) {
+ if (NumArgs > C->Function->getNumParams() && !C->Function->isVariadic())
+ return ovl_fail_too_many_arguments;
+ if (NumArgs < C->Function->getMinRequiredArguments())
+ return ovl_fail_too_few_arguments;
+ }
+
+ return static_cast<OverloadFailureKind>(C->FailureKind);
+ }
+
bool operator()(const OverloadCandidate *L,
const OverloadCandidate *R) {
// Fast-path this check.
@@ -10839,34 +11141,37 @@ struct CompareOverloadCandidatesForDisplay {
// Criteria by which we can sort non-viable candidates:
if (!L->Viable) {
+ OverloadFailureKind LFailureKind = EffectiveFailureKind(L);
+ OverloadFailureKind RFailureKind = EffectiveFailureKind(R);
+
// 1. Arity mismatches come after other candidates.
- if (L->FailureKind == ovl_fail_too_many_arguments ||
- L->FailureKind == ovl_fail_too_few_arguments) {
- if (R->FailureKind == ovl_fail_too_many_arguments ||
- R->FailureKind == ovl_fail_too_few_arguments) {
+ if (LFailureKind == ovl_fail_too_many_arguments ||
+ LFailureKind == ovl_fail_too_few_arguments) {
+ if (RFailureKind == ovl_fail_too_many_arguments ||
+ RFailureKind == ovl_fail_too_few_arguments) {
int LDist = std::abs((int)L->getNumParams() - (int)NumArgs);
int RDist = std::abs((int)R->getNumParams() - (int)NumArgs);
if (LDist == RDist) {
- if (L->FailureKind == R->FailureKind)
+ if (LFailureKind == RFailureKind)
// Sort non-surrogates before surrogates.
return !L->IsSurrogate && R->IsSurrogate;
// Sort candidates requiring fewer parameters than there were
// arguments given after candidates requiring more parameters
// than there were arguments given.
- return L->FailureKind == ovl_fail_too_many_arguments;
+ return LFailureKind == ovl_fail_too_many_arguments;
}
return LDist < RDist;
}
return false;
}
- if (R->FailureKind == ovl_fail_too_many_arguments ||
- R->FailureKind == ovl_fail_too_few_arguments)
+ if (RFailureKind == ovl_fail_too_many_arguments ||
+ RFailureKind == ovl_fail_too_few_arguments)
return true;
// 2. Bad conversions come first and are ordered by the number
// of bad conversions and quality of good conversions.
- if (L->FailureKind == ovl_fail_bad_conversion) {
- if (R->FailureKind != ovl_fail_bad_conversion)
+ if (LFailureKind == ovl_fail_bad_conversion) {
+ if (RFailureKind != ovl_fail_bad_conversion)
return true;
// The conversion that can be fixed with a smaller number of changes,
@@ -10904,17 +11209,17 @@ struct CompareOverloadCandidatesForDisplay {
if (leftBetter > 0) return true;
if (leftBetter < 0) return false;
- } else if (R->FailureKind == ovl_fail_bad_conversion)
+ } else if (RFailureKind == ovl_fail_bad_conversion)
return false;
- if (L->FailureKind == ovl_fail_bad_deduction) {
- if (R->FailureKind != ovl_fail_bad_deduction)
+ if (LFailureKind == ovl_fail_bad_deduction) {
+ if (RFailureKind != ovl_fail_bad_deduction)
return true;
if (L->DeductionFailure.Result != R->DeductionFailure.Result)
return RankDeductionFailure(L->DeductionFailure)
< RankDeductionFailure(R->DeductionFailure);
- } else if (R->FailureKind == ovl_fail_bad_deduction)
+ } else if (RFailureKind == ovl_fail_bad_deduction)
return false;
// TODO: others?
@@ -10943,7 +11248,8 @@ CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
assert(!Cand->Viable);
// Don't do anything on failures other than bad conversion.
- if (Cand->FailureKind != ovl_fail_bad_conversion) return;
+ if (Cand->FailureKind != ovl_fail_bad_conversion)
+ return;
// We only want the FixIts if all the arguments can be corrected.
bool Unfixable = false;
@@ -10969,6 +11275,7 @@ CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
unsigned ConvIdx = 0;
unsigned ArgIdx = 0;
ArrayRef<QualType> ParamTypes;
+ bool Reversed = Cand->RewriteKind & CRK_Reversed;
if (Cand->IsSurrogate) {
QualType ConvType
@@ -10982,10 +11289,11 @@ CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
ParamTypes =
Cand->Function->getType()->castAs<FunctionProtoType>()->getParamTypes();
if (isa<CXXMethodDecl>(Cand->Function) &&
- !isa<CXXConstructorDecl>(Cand->Function)) {
+ !isa<CXXConstructorDecl>(Cand->Function) && !Reversed) {
// Conversion 0 is 'this', which doesn't have a corresponding parameter.
ConvIdx = 1;
- if (CSK == OverloadCandidateSet::CSK_Operator)
+ if (CSK == OverloadCandidateSet::CSK_Operator &&
+ Cand->Function->getDeclName().getCXXOverloadedOperator() != OO_Call)
// Argument 0 is 'this', which doesn't have a corresponding parameter.
ArgIdx = 1;
}
@@ -10996,13 +11304,13 @@ CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
}
// Fill in the rest of the conversions.
- bool Reversed = Cand->RewriteKind & CRK_Reversed;
for (unsigned ParamIdx = Reversed ? ParamTypes.size() - 1 : 0;
ConvIdx != ConvCount;
++ConvIdx, ++ArgIdx, ParamIdx += (Reversed ? -1 : 1)) {
+ assert(ArgIdx < Args.size() && "no argument for this arg conversion");
if (Cand->Conversions[ConvIdx].isInitialized()) {
// We've already checked this conversion.
- } else if (ArgIdx < ParamTypes.size()) {
+ } else if (ParamIdx < ParamTypes.size()) {
if (ParamTypes[ParamIdx]->isDependentType())
Cand->Conversions[ConvIdx].setAsIdentityConversion(
Args[ArgIdx]->getType());
@@ -11033,15 +11341,30 @@ SmallVector<OverloadCandidate *, 32> OverloadCandidateSet::CompleteCandidates(
for (iterator Cand = begin(), LastCand = end(); Cand != LastCand; ++Cand) {
if (!Filter(*Cand))
continue;
- if (Cand->Viable)
- Cands.push_back(Cand);
- else if (OCD == OCD_AllCandidates) {
- CompleteNonViableCandidate(S, Cand, Args, Kind);
- if (Cand->Function || Cand->IsSurrogate)
- Cands.push_back(Cand);
- // Otherwise, this a non-viable builtin candidate. We do not, in general,
- // want to list every possible builtin candidate.
+ switch (OCD) {
+ case OCD_AllCandidates:
+ if (!Cand->Viable) {
+ if (!Cand->Function && !Cand->IsSurrogate) {
+ // This a non-viable builtin candidate. We do not, in general,
+ // want to list every possible builtin candidate.
+ continue;
+ }
+ CompleteNonViableCandidate(S, Cand, Args, Kind);
+ }
+ break;
+
+ case OCD_ViableCandidates:
+ if (!Cand->Viable)
+ continue;
+ break;
+
+ case OCD_AmbiguousCandidates:
+ if (!Cand->Best)
+ continue;
+ break;
}
+
+ Cands.push_back(Cand);
}
llvm::stable_sort(
@@ -11062,6 +11385,9 @@ void OverloadCandidateSet::NoteCandidates(PartialDiagnosticAt PD,
S.Diag(PD.first, PD.second);
NoteCandidates(S, Args, Cands, Opc, OpLoc);
+
+ if (OCD == OCD_AmbiguousCandidates)
+ MaybeDiagnoseAmbiguousConstraints(S, {begin(), end()});
}
void OverloadCandidateSet::NoteCandidates(Sema &S, ArrayRef<Expr *> Args,
@@ -11710,15 +12036,33 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr,
/// resolve that function to a single function that can have its address taken.
/// This will modify `Pair` iff it returns non-null.
///
-/// This routine can only realistically succeed if all but one candidates in the
-/// overload set for SrcExpr cannot have their addresses taken.
+/// This routine can only succeed if from all of the candidates in the overload
+/// set for SrcExpr that can have their addresses taken, there is one candidate
+/// that is more constrained than the rest.
FunctionDecl *
-Sema::resolveAddressOfOnlyViableOverloadCandidate(Expr *E,
- DeclAccessPair &Pair) {
+Sema::resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &Pair) {
OverloadExpr::FindResult R = OverloadExpr::find(E);
OverloadExpr *Ovl = R.Expression;
+ bool IsResultAmbiguous = false;
FunctionDecl *Result = nullptr;
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;
+ };
+
// Don't use the AddressOfResolver because we're specifically looking for
// cases where we have one overload candidate that lacks
// enable_if/pass_object_size/...
@@ -11730,32 +12074,54 @@ Sema::resolveAddressOfOnlyViableOverloadCandidate(Expr *E,
if (!checkAddressOfFunctionIsAvailable(FD))
continue;
- // We have more than one result; quit.
- if (Result)
- return nullptr;
+ // We have more than one result - see if it is more constrained than the
+ // previous one.
+ if (Result) {
+ Optional<bool> MoreConstrainedThanPrevious = CheckMoreConstrained(FD,
+ Result);
+ if (!MoreConstrainedThanPrevious) {
+ IsResultAmbiguous = true;
+ AmbiguousDecls.push_back(FD);
+ continue;
+ }
+ if (!*MoreConstrainedThanPrevious)
+ continue;
+ // FD is more constrained - replace Result with it.
+ }
+ IsResultAmbiguous = false;
DAP = I.getPair();
Result = FD;
}
- if (Result)
+ if (IsResultAmbiguous)
+ return nullptr;
+
+ if (Result) {
+ SmallVector<const Expr *, 1> ResultAC;
+ // We skipped over some ambiguous declarations which might be ambiguous with
+ // the selected result.
+ for (FunctionDecl *Skipped : AmbiguousDecls)
+ if (!CheckMoreConstrained(Skipped, Result).hasValue())
+ return nullptr;
Pair = DAP;
+ }
return Result;
}
/// Given an overloaded function, tries to turn it into a non-overloaded
-/// function reference using resolveAddressOfOnlyViableOverloadCandidate. This
+/// function reference using resolveAddressOfSingleOverloadCandidate. This
/// will perform access checks, diagnose the use of the resultant decl, and, if
/// requested, potentially perform a function-to-pointer decay.
///
-/// Returns false if resolveAddressOfOnlyViableOverloadCandidate fails.
+/// Returns false if resolveAddressOfSingleOverloadCandidate fails.
/// Otherwise, returns true. This may emit diagnostics and return true.
-bool Sema::resolveAndFixAddressOfOnlyViableOverloadCandidate(
+bool Sema::resolveAndFixAddressOfSingleOverloadCandidate(
ExprResult &SrcExpr, bool DoFunctionPointerConverion) {
Expr *E = SrcExpr.get();
assert(E->getType() == Context.OverloadTy && "SrcExpr must be an overload");
DeclAccessPair DAP;
- FunctionDecl *Found = resolveAddressOfOnlyViableOverloadCandidate(E, DAP);
+ FunctionDecl *Found = resolveAddressOfSingleOverloadCandidate(E, DAP);
if (!Found || Found->isCPUDispatchMultiVersion() ||
Found->isCPUSpecificMultiVersion())
return false;
@@ -12406,7 +12772,7 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
PartialDiagnosticAt(Fn->getBeginLoc(),
SemaRef.PDiag(diag::err_ovl_ambiguous_call)
<< ULE->getName() << Fn->getSourceRange()),
- SemaRef, OCD_ViableCandidates, Args);
+ SemaRef, OCD_AmbiguousCandidates, Args);
break;
case OR_Deleted: {
@@ -12652,7 +13018,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
PDiag(diag::err_ovl_ambiguous_oper_unary)
<< UnaryOperator::getOpcodeStr(Opc)
<< Input->getType() << Input->getSourceRange()),
- *this, OCD_ViableCandidates, ArgsArray,
+ *this, OCD_AmbiguousCandidates, ArgsArray,
UnaryOperator::getOpcodeStr(Opc), OpLoc);
return ExprError();
@@ -12672,6 +13038,70 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
return CreateBuiltinUnaryOp(OpLoc, Opc, Input);
}
+/// Perform lookup for an overloaded binary operator.
+void Sema::LookupOverloadedBinOp(OverloadCandidateSet &CandidateSet,
+ OverloadedOperatorKind Op,
+ const UnresolvedSetImpl &Fns,
+ ArrayRef<Expr *> Args, bool PerformADL) {
+ SourceLocation OpLoc = CandidateSet.getLocation();
+
+ OverloadedOperatorKind ExtraOp =
+ CandidateSet.getRewriteInfo().AllowRewrittenCandidates
+ ? getRewrittenOverloadedOperator(Op)
+ : OO_None;
+
+ // Add the candidates from the given function set. This also adds the
+ // rewritten candidates using these functions if necessary.
+ AddNonMemberOperatorCandidates(Fns, Args, CandidateSet);
+
+ // Add operator candidates that are member functions.
+ AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet);
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(Op))
+ AddMemberOperatorCandidates(Op, OpLoc, {Args[1], Args[0]}, CandidateSet,
+ OverloadCandidateParamOrder::Reversed);
+
+ // In C++20, also add any rewritten member candidates.
+ if (ExtraOp) {
+ AddMemberOperatorCandidates(ExtraOp, OpLoc, Args, CandidateSet);
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(ExtraOp))
+ AddMemberOperatorCandidates(ExtraOp, OpLoc, {Args[1], Args[0]},
+ CandidateSet,
+ OverloadCandidateParamOrder::Reversed);
+ }
+
+ // Add candidates from ADL. Per [over.match.oper]p2, this lookup is not
+ // performed for an assignment operator (nor for operator[] nor operator->,
+ // which don't get here).
+ if (Op != OO_Equal && PerformADL) {
+ DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
+ AddArgumentDependentLookupCandidates(OpName, OpLoc, Args,
+ /*ExplicitTemplateArgs*/ nullptr,
+ CandidateSet);
+ if (ExtraOp) {
+ DeclarationName ExtraOpName =
+ Context.DeclarationNames.getCXXOperatorName(ExtraOp);
+ AddArgumentDependentLookupCandidates(ExtraOpName, OpLoc, Args,
+ /*ExplicitTemplateArgs*/ nullptr,
+ CandidateSet);
+ }
+ }
+
+ // Add builtin operator candidates.
+ //
+ // FIXME: We don't add any rewritten candidates here. This is strictly
+ // incorrect; a builtin candidate could be hidden by a non-viable candidate,
+ // resulting in our selecting a rewritten builtin candidate. For example:
+ //
+ // enum class E { e };
+ // bool operator!=(E, E) requires false;
+ // bool k = E::e != E::e;
+ //
+ // ... should select the rewritten builtin candidate 'operator==(E, E)'. But
+ // it seems unreasonable to consider rewritten builtin candidates. A core
+ // issue has been filed proposing to removed this requirement.
+ AddBuiltinOperatorCandidates(Op, OpLoc, Args, CandidateSet);
+}
+
/// Create a binary operation that may resolve to an overloaded
/// operator.
///
@@ -12688,11 +13118,19 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
///
/// \param LHS Left-hand argument.
/// \param RHS Right-hand argument.
+/// \param PerformADL Whether to consider operator candidates found by ADL.
+/// \param AllowRewrittenCandidates Whether to consider candidates found by
+/// C++20 operator rewrites.
+/// \param DefaultedFn If we are synthesizing a defaulted operator function,
+/// the function in question. Such a function is never a candidate in
+/// our overload resolution. This also enables synthesizing a three-way
+/// comparison from < and == as described in C++20 [class.spaceship]p1.
ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
BinaryOperatorKind Opc,
const UnresolvedSetImpl &Fns, Expr *LHS,
Expr *RHS, bool PerformADL,
- bool AllowRewrittenCandidates) {
+ bool AllowRewrittenCandidates,
+ FunctionDecl *DefaultedFn) {
Expr *Args[2] = { LHS, RHS };
LHS=RHS=nullptr; // Please use only Args instead of LHS/RHS couple
@@ -12700,7 +13138,6 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
AllowRewrittenCandidates = false;
OverloadedOperatorKind Op = BinaryOperator::getOverloadedOperator(Opc);
- DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
// If either side is type-dependent, create an appropriate dependent
// expression.
@@ -12722,6 +13159,7 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// FIXME: save results of ADL from here?
CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators
// TODO: provide better source location info in DNLoc component.
+ DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
DeclarationNameInfo OpNameInfo(OpName, OpLoc);
UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create(
Context, NamingClass, NestedNameSpecifierLoc(), OpNameInfo,
@@ -12755,63 +13193,13 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
if (Opc == BO_PtrMemD)
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
- // Build an empty overload set.
+ // Build the overload set.
OverloadCandidateSet CandidateSet(
OpLoc, OverloadCandidateSet::CSK_Operator,
OverloadCandidateSet::OperatorRewriteInfo(Op, AllowRewrittenCandidates));
-
- OverloadedOperatorKind ExtraOp =
- AllowRewrittenCandidates ? getRewrittenOverloadedOperator(Op) : OO_None;
-
- // Add the candidates from the given function set. This also adds the
- // rewritten candidates using these functions if necessary.
- AddNonMemberOperatorCandidates(Fns, Args, CandidateSet);
-
- // Add operator candidates that are member functions.
- AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet);
- if (CandidateSet.getRewriteInfo().shouldAddReversed(Op))
- AddMemberOperatorCandidates(Op, OpLoc, {Args[1], Args[0]}, CandidateSet,
- OverloadCandidateParamOrder::Reversed);
-
- // In C++20, also add any rewritten member candidates.
- if (ExtraOp) {
- AddMemberOperatorCandidates(ExtraOp, OpLoc, Args, CandidateSet);
- if (CandidateSet.getRewriteInfo().shouldAddReversed(ExtraOp))
- AddMemberOperatorCandidates(ExtraOp, OpLoc, {Args[1], Args[0]},
- CandidateSet,
- OverloadCandidateParamOrder::Reversed);
- }
-
- // Add candidates from ADL. Per [over.match.oper]p2, this lookup is not
- // performed for an assignment operator (nor for operator[] nor operator->,
- // which don't get here).
- if (Opc != BO_Assign && PerformADL) {
- AddArgumentDependentLookupCandidates(OpName, OpLoc, Args,
- /*ExplicitTemplateArgs*/ nullptr,
- CandidateSet);
- if (ExtraOp) {
- DeclarationName ExtraOpName =
- Context.DeclarationNames.getCXXOperatorName(ExtraOp);
- AddArgumentDependentLookupCandidates(ExtraOpName, OpLoc, Args,
- /*ExplicitTemplateArgs*/ nullptr,
- CandidateSet);
- }
- }
-
- // Add builtin operator candidates.
- //
- // FIXME: We don't add any rewritten candidates here. This is strictly
- // incorrect; a builtin candidate could be hidden by a non-viable candidate,
- // resulting in our selecting a rewritten builtin candidate. For example:
- //
- // enum class E { e };
- // bool operator!=(E, E) requires false;
- // bool k = E::e != E::e;
- //
- // ... should select the rewritten builtin candidate 'operator==(E, E)'. But
- // it seems unreasonable to consider rewritten builtin candidates. A core
- // issue has been filed proposing to removed this requirement.
- AddBuiltinOperatorCandidates(Op, OpLoc, Args, CandidateSet);
+ if (DefaultedFn)
+ CandidateSet.exclude(DefaultedFn);
+ LookupOverloadedBinOp(CandidateSet, Op, Fns, Args, PerformADL);
bool HadMultipleCandidates = (CandidateSet.size() > 1);
@@ -13018,6 +13406,15 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
if (Opc == BO_Comma)
break;
+ // When defaulting an 'operator<=>', we can try to synthesize a three-way
+ // compare result using '==' and '<'.
+ if (DefaultedFn && Opc == BO_Cmp) {
+ ExprResult E = BuildSynthesizedThreeWayComparison(OpLoc, Fns, Args[0],
+ Args[1], DefaultedFn);
+ if (E.isInvalid() || E.isUsable())
+ return E;
+ }
+
// For class as left operand for assignment or compound assignment
// operator do not fall through to handling in built-in, but report that
// no overloaded assignment operator found
@@ -13061,20 +13458,26 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
<< Args[1]->getType()
<< Args[0]->getSourceRange()
<< Args[1]->getSourceRange()),
- *this, OCD_ViableCandidates, Args, BinaryOperator::getOpcodeStr(Opc),
+ *this, OCD_AmbiguousCandidates, Args, BinaryOperator::getOpcodeStr(Opc),
OpLoc);
return ExprError();
case OR_Deleted:
if (isImplicitlyDeleted(Best->Function)) {
- CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
- Diag(OpLoc, diag::err_ovl_deleted_special_oper)
- << Context.getRecordType(Method->getParent())
- << getSpecialMember(Method);
+ FunctionDecl *DeletedFD = Best->Function;
+ DefaultedFunctionKind DFK = getDefaultedFunctionKind(DeletedFD);
+ if (DFK.isSpecialMember()) {
+ Diag(OpLoc, diag::err_ovl_deleted_special_oper)
+ << Args[0]->getType() << DFK.asSpecialMember();
+ } else {
+ assert(DFK.isComparison());
+ Diag(OpLoc, diag::err_ovl_deleted_comparison)
+ << Args[0]->getType() << DeletedFD;
+ }
// The user probably meant to call this special member. Just
// explain why it's deleted.
- NoteDeletedFunction(Method);
+ NoteDeletedFunction(DeletedFD);
return ExprError();
}
CandidateSet.NoteCandidates(
@@ -13093,6 +13496,98 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
}
+ExprResult Sema::BuildSynthesizedThreeWayComparison(
+ SourceLocation OpLoc, const UnresolvedSetImpl &Fns, Expr *LHS, Expr *RHS,
+ FunctionDecl *DefaultedFn) {
+ const ComparisonCategoryInfo *Info =
+ Context.CompCategories.lookupInfoForType(DefaultedFn->getReturnType());
+ // If we're not producing a known comparison category type, we can't
+ // synthesize a three-way comparison. Let the caller diagnose this.
+ if (!Info)
+ return ExprResult((Expr*)nullptr);
+
+ // If we ever want to perform this synthesis more generally, we will need to
+ // apply the temporary materialization conversion to the operands.
+ assert(LHS->isGLValue() && RHS->isGLValue() &&
+ "cannot use prvalue expressions more than once");
+ Expr *OrigLHS = LHS;
+ Expr *OrigRHS = RHS;
+
+ // Replace the LHS and RHS with OpaqueValueExprs; we're going to refer to
+ // each of them multiple times below.
+ LHS = new (Context)
+ OpaqueValueExpr(LHS->getExprLoc(), LHS->getType(), LHS->getValueKind(),
+ LHS->getObjectKind(), LHS);
+ RHS = new (Context)
+ OpaqueValueExpr(RHS->getExprLoc(), RHS->getType(), RHS->getValueKind(),
+ RHS->getObjectKind(), RHS);
+
+ ExprResult Eq = CreateOverloadedBinOp(OpLoc, BO_EQ, Fns, LHS, RHS, true, true,
+ DefaultedFn);
+ if (Eq.isInvalid())
+ return ExprError();
+
+ ExprResult Less = CreateOverloadedBinOp(OpLoc, BO_LT, Fns, LHS, RHS, true,
+ true, DefaultedFn);
+ if (Less.isInvalid())
+ return ExprError();
+
+ ExprResult Greater;
+ if (Info->isPartial()) {
+ Greater = CreateOverloadedBinOp(OpLoc, BO_LT, Fns, RHS, LHS, true, true,
+ DefaultedFn);
+ if (Greater.isInvalid())
+ return ExprError();
+ }
+
+ // Form the list of comparisons we're going to perform.
+ struct Comparison {
+ ExprResult Cmp;
+ ComparisonCategoryResult Result;
+ } Comparisons[4] =
+ { {Eq, Info->isStrong() ? ComparisonCategoryResult::Equal
+ : ComparisonCategoryResult::Equivalent},
+ {Less, ComparisonCategoryResult::Less},
+ {Greater, ComparisonCategoryResult::Greater},
+ {ExprResult(), ComparisonCategoryResult::Unordered},
+ };
+
+ int I = Info->isPartial() ? 3 : 2;
+
+ // Combine the comparisons with suitable conditional expressions.
+ ExprResult Result;
+ for (; I >= 0; --I) {
+ // Build a reference to the comparison category constant.
+ auto *VI = Info->lookupValueInfo(Comparisons[I].Result);
+ // FIXME: Missing a constant for a comparison category. Diagnose this?
+ if (!VI)
+ return ExprResult((Expr*)nullptr);
+ ExprResult ThisResult =
+ BuildDeclarationNameExpr(CXXScopeSpec(), DeclarationNameInfo(), VI->VD);
+ if (ThisResult.isInvalid())
+ return ExprError();
+
+ // Build a conditional unless this is the final case.
+ if (Result.get()) {
+ Result = ActOnConditionalOp(OpLoc, OpLoc, Comparisons[I].Cmp.get(),
+ ThisResult.get(), Result.get());
+ if (Result.isInvalid())
+ return ExprError();
+ } else {
+ Result = ThisResult;
+ }
+ }
+
+ // Build a PseudoObjectExpr to model the rewriting of an <=> operator, and to
+ // bind the OpaqueValueExprs before they're (repeatedly) used.
+ Expr *SyntacticForm = new (Context)
+ BinaryOperator(OrigLHS, OrigRHS, BO_Cmp, Result.get()->getType(),
+ Result.get()->getValueKind(),
+ Result.get()->getObjectKind(), OpLoc, FPFeatures);
+ Expr *SemanticForm[] = {LHS, RHS, Result.get()};
+ return PseudoObjectExpr::Create(Context, SyntacticForm, SemanticForm, 2);
+}
+
ExprResult
Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
SourceLocation RLoc,
@@ -13246,7 +13741,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
<< Args[1]->getType()
<< Args[0]->getSourceRange()
<< Args[1]->getSourceRange()),
- *this, OCD_ViableCandidates, Args, "[]", LLoc);
+ *this, OCD_AmbiguousCandidates, Args, "[]", LLoc);
return ExprError();
case OR_Deleted:
@@ -13438,7 +13933,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
PartialDiagnosticAt(UnresExpr->getMemberLoc(),
PDiag(diag::err_ovl_ambiguous_member_call)
<< DeclName << MemExprE->getSourceRange()),
- *this, OCD_AllCandidates, Args);
+ *this, OCD_AmbiguousCandidates, Args);
// FIXME: Leaking incoming expressions!
return ExprError();
@@ -13469,7 +13964,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
ResultType = ResultType.getNonLValueExprType(Context);
assert(Method && "Member call to something that isn't a method?");
- const auto *Proto = Method->getType()->getAs<FunctionProtoType>();
+ const auto *Proto = Method->getType()->castAs<FunctionProtoType>();
CXXMemberCallExpr *TheCall =
CXXMemberCallExpr::Create(Context, MemExprE, Args, ResultType, VK,
RParenLoc, Proto->getNumParams());
@@ -13566,7 +14061,6 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
assert(Object.get()->getType()->isRecordType() &&
"Requires object type argument");
- const RecordType *Record = Object.get()->getType()->getAs<RecordType>();
// C++ [over.call.object]p1:
// If the primary-expression E in the function call syntax
@@ -13583,6 +14077,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
diag::err_incomplete_object_call, Object.get()))
return true;
+ const auto *Record = Object.get()->getType()->castAs<RecordType>();
LookupResult R(*this, OpName, LParenLoc, LookupOrdinaryName);
LookupQualifiedName(R, Record->getDecl());
R.suppressDiagnostics();
@@ -13670,7 +14165,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
PDiag(diag::err_ovl_ambiguous_object_call)
<< Object.get()->getType()
<< Object.get()->getSourceRange()),
- *this, OCD_ViableCandidates, Args);
+ *this, OCD_AmbiguousCandidates, Args);
break;
case OR_Deleted:
@@ -13730,9 +14225,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
if (Method->isInvalidDecl())
return ExprError();
- const FunctionProtoType *Proto =
- Method->getType()->getAs<FunctionProtoType>();
-
+ const auto *Proto = Method->getType()->castAs<FunctionProtoType>();
unsigned NumParams = Proto->getNumParams();
DeclarationNameInfo OpLocInfo(
@@ -13853,14 +14346,13 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
DeclarationName OpName =
Context.DeclarationNames.getCXXOperatorName(OO_Arrow);
OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Operator);
- const RecordType *BaseRecord = Base->getType()->getAs<RecordType>();
if (RequireCompleteType(Loc, Base->getType(),
diag::err_typecheck_incomplete_tag, Base))
return ExprError();
LookupResult R(*this, OpName, OpLoc, LookupOrdinaryName);
- LookupQualifiedName(R, BaseRecord->getDecl());
+ LookupQualifiedName(R, Base->getType()->castAs<RecordType>()->getDecl());
R.suppressDiagnostics();
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
@@ -13905,7 +14397,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_ambiguous_oper_unary)
<< "->" << Base->getType()
<< Base->getSourceRange()),
- *this, OCD_ViableCandidates, Base);
+ *this, OCD_AmbiguousCandidates, Base);
return ExprError();
case OR_Deleted:
@@ -13985,7 +14477,7 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
CandidateSet.NoteCandidates(
PartialDiagnosticAt(R.getNameLoc(), PDiag(diag::err_ovl_ambiguous_call)
<< R.getLookupName()),
- *this, OCD_ViableCandidates, Args);
+ *this, OCD_AmbiguousCandidates, Args);
return ExprError();
}
@@ -14200,13 +14692,6 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
UnOp->getOperatorLoc(), false);
}
- // C++ [except.spec]p17:
- // An exception-specification is considered to be needed when:
- // - in an expression the function is the unique lookup result or the
- // selected member of a set of overloaded functions
- if (auto *FPT = Fn->getType()->getAs<FunctionProtoType>())
- ResolveExceptionSpec(E->getExprLoc(), FPT);
-
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) {
// FIXME: avoid copy.
TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = nullptr;
diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp
index 06bcd8d00ded..5587e0d24c7f 100644
--- a/clang/lib/Sema/SemaPseudoObject.cpp
+++ b/clang/lib/Sema/SemaPseudoObject.cpp
@@ -145,7 +145,7 @@ namespace {
assocExprs.reserve(numAssocs);
assocTypes.reserve(numAssocs);
- for (const GenericSelectionExpr::Association &assoc :
+ for (const GenericSelectionExpr::Association assoc :
gse->associations()) {
Expr *assocExpr = assoc.getAssociationExpr();
if (assoc.isSelected())
@@ -1190,16 +1190,15 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() {
true /*instance*/);
if (!AtIndexGetter && S.getLangOpts().DebuggerObjCLiteral) {
- AtIndexGetter = ObjCMethodDecl::Create(S.Context, SourceLocation(),
- SourceLocation(), AtIndexGetterSelector,
- S.Context.getObjCIdType() /*ReturnType*/,
- nullptr /*TypeSourceInfo */,
- S.Context.getTranslationUnitDecl(),
- true /*Instance*/, false/*isVariadic*/,
- /*isPropertyAccessor=*/false,
- /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
- ObjCMethodDecl::Required,
- false);
+ AtIndexGetter = ObjCMethodDecl::Create(
+ S.Context, SourceLocation(), SourceLocation(), AtIndexGetterSelector,
+ S.Context.getObjCIdType() /*ReturnType*/, nullptr /*TypeSourceInfo */,
+ S.Context.getTranslationUnitDecl(), true /*Instance*/,
+ false /*isVariadic*/,
+ /*isPropertyAccessor=*/false,
+ /*isSynthesizedAccessorStub=*/false,
+ /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
+ ObjCMethodDecl::Required, false);
ParmVarDecl *Argument = ParmVarDecl::Create(S.Context, AtIndexGetter,
SourceLocation(), SourceLocation(),
arrayRef ? &S.Context.Idents.get("index")
@@ -1303,6 +1302,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() {
ReturnType, ReturnTInfo, S.Context.getTranslationUnitDecl(),
true /*Instance*/, false /*isVariadic*/,
/*isPropertyAccessor=*/false,
+ /*isSynthesizedAccessorStub=*/false,
/*isImplicitlyDeclared=*/true, /*isDefined=*/false,
ObjCMethodDecl::Required, false);
SmallVector<ParmVarDecl *, 2> Params;
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 6c680f29da4f..d6c3af9e84c8 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -2724,7 +2724,7 @@ static void DiagnoseForRangeReferenceVariableCopies(Sema &SemaRef,
if (!MTE)
return;
- const Expr *E = MTE->GetTemporaryExpr()->IgnoreImpCasts();
+ const Expr *E = MTE->getSubExpr()->IgnoreImpCasts();
// Searching for either UnaryOperator for dereference of a pointer or
// CXXOperatorCallExpr for handling iterators.
@@ -2736,7 +2736,7 @@ static void DiagnoseForRangeReferenceVariableCopies(Sema &SemaRef,
E = ME->getBase();
} else {
const MaterializeTemporaryExpr *MTE = cast<MaterializeTemporaryExpr>(E);
- E = MTE->GetTemporaryExpr();
+ E = MTE->getSubExpr();
}
E = E->IgnoreImpCasts();
}
@@ -2762,19 +2762,32 @@ static void DiagnoseForRangeReferenceVariableCopies(Sema &SemaRef,
QualType NewReferenceType =
SemaRef.Context.getLValueReferenceType(E->getType().withConst());
SemaRef.Diag(VD->getBeginLoc(), diag::note_use_type_or_non_reference)
- << NonReferenceType << NewReferenceType << VD->getSourceRange();
- } else {
+ << NonReferenceType << NewReferenceType << VD->getSourceRange()
+ << FixItHint::CreateRemoval(VD->getTypeSpecEndLoc());
+ } else if (!VariableType->isRValueReferenceType()) {
// The range always returns a copy, so a temporary is always created.
// Suggest removing the reference from the loop variable.
+ // If the type is a rvalue reference do not warn since that changes the
+ // semantic of the code.
SemaRef.Diag(VD->getLocation(), diag::warn_for_range_variable_always_copy)
<< VD << RangeInitType;
QualType NonReferenceType = VariableType.getNonReferenceType();
NonReferenceType.removeLocalConst();
SemaRef.Diag(VD->getBeginLoc(), diag::note_use_non_reference_type)
- << NonReferenceType << VD->getSourceRange();
+ << NonReferenceType << VD->getSourceRange()
+ << FixItHint::CreateRemoval(VD->getTypeSpecEndLoc());
}
}
+/// Determines whether the @p VariableType's declaration is a record with the
+/// clang::trivial_abi attribute.
+static bool hasTrivialABIAttr(QualType VariableType) {
+ if (CXXRecordDecl *RD = VariableType->getAsCXXRecordDecl())
+ return RD->hasAttr<TrivialABIAttr>();
+
+ return false;
+}
+
// Warns when the loop variable can be changed to a reference type to
// prevent a copy. For instance, if given "for (const Foo x : Range)" suggest
// "for (const Foo &x : Range)" if this form does not make a copy.
@@ -2796,10 +2809,13 @@ static void DiagnoseForRangeConstVariableCopies(Sema &SemaRef,
return;
}
- // TODO: Determine a maximum size that a POD type can be before a diagnostic
- // should be emitted. Also, only ignore POD types with trivial copy
- // constructors.
- if (VariableType.isPODType(SemaRef.Context))
+ // Small trivially copyable types are cheap to copy. Do not emit the
+ // diagnostic for these instances. 64 bytes is a common size of a cache line.
+ // (The function `getTypeSize` returns the size in bits.)
+ ASTContext &Ctx = SemaRef.Context;
+ if (Ctx.getTypeSize(VariableType) <= 64 * 8 &&
+ (VariableType.isTriviallyCopyableType(Ctx) ||
+ hasTrivialABIAttr(VariableType)))
return;
// Suggest changing from a const variable to a const reference variable
@@ -2808,7 +2824,8 @@ static void DiagnoseForRangeConstVariableCopies(Sema &SemaRef,
<< VD << VariableType << InitExpr->getType();
SemaRef.Diag(VD->getBeginLoc(), diag::note_use_reference_type)
<< SemaRef.Context.getLValueReferenceType(VariableType)
- << VD->getSourceRange();
+ << VD->getSourceRange()
+ << FixItHint::CreateInsertion(VD->getLocation(), "&");
}
/// DiagnoseForRangeVariableCopies - Diagnose three cases and fixes for them.
@@ -4184,19 +4201,16 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc,
return SEHTryStmt::Create(Context, IsCXXTry, TryLoc, TryBlock, Handler);
}
-StmtResult
-Sema::ActOnSEHExceptBlock(SourceLocation Loc,
- Expr *FilterExpr,
- Stmt *Block) {
+StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, Expr *FilterExpr,
+ Stmt *Block) {
assert(FilterExpr && Block);
-
- if(!FilterExpr->getType()->isIntegerType()) {
- return StmtError(Diag(FilterExpr->getExprLoc(),
- diag::err_filter_expression_integral)
- << FilterExpr->getType());
+ QualType FTy = FilterExpr->getType();
+ if (!FTy->isIntegerType() && !FTy->isDependentType()) {
+ return StmtError(
+ Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral)
+ << FTy);
}
-
- return SEHExceptStmt::Create(Context,Loc,FilterExpr,Block);
+ return SEHExceptStmt::Create(Context, Loc, FilterExpr, Block);
}
void Sema::ActOnStartSEHFinallyBlock() {
diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp
index 9b051e02d127..93faf2d151f9 100644
--- a/clang/lib/Sema/SemaStmtAsm.cpp
+++ b/clang/lib/Sema/SemaStmtAsm.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/GlobalDecl.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/TargetInfo.h"
@@ -255,6 +256,10 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
// The parser verifies that there is a string literal here.
assert(AsmString->isAscii());
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(getCurLexicalContext());
+ llvm::StringMap<bool> FeatureMap;
+ Context.getFunctionFeatureMap(FeatureMap, FD);
+
for (unsigned i = 0; i != NumOutputs; i++) {
StringLiteral *Literal = Constraints[i];
assert(Literal->isAscii());
@@ -325,8 +330,8 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
}
unsigned Size = Context.getTypeSize(OutputExpr->getType());
- if (!Context.getTargetInfo().validateOutputSize(Literal->getString(),
- Size)) {
+ if (!Context.getTargetInfo().validateOutputSize(
+ FeatureMap, Literal->getString(), Size)) {
targetDiag(OutputExpr->getBeginLoc(), diag::err_asm_invalid_output_size)
<< Info.getConstraintStr();
return new (Context)
@@ -427,8 +432,8 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
return StmtError();
unsigned Size = Context.getTypeSize(Ty);
- if (!Context.getTargetInfo().validateInputSize(Literal->getString(),
- Size))
+ if (!Context.getTargetInfo().validateInputSize(FeatureMap,
+ Literal->getString(), Size))
return StmtResult(
targetDiag(InputExpr->getBeginLoc(), diag::err_asm_invalid_input_size)
<< Info.getConstraintStr());
@@ -702,8 +707,13 @@ void Sema::FillInlineAsmIdentifierInfo(Expr *Res,
if (T->isFunctionType() || T->isDependentType())
return Info.setLabel(Res);
if (Res->isRValue()) {
- if (isa<clang::EnumType>(T) && Res->EvaluateAsRValue(Eval, Context))
+ bool IsEnum = isa<clang::EnumType>(T);
+ if (DeclRefExpr *DRE = dyn_cast<clang::DeclRefExpr>(Res))
+ if (DRE->getDecl()->getKind() == Decl::EnumConstant)
+ IsEnum = true;
+ if (IsEnum && Res->EvaluateAsRValue(Eval, Context))
return Info.setEnum(Eval.Val.getInt().getSExtValue());
+
return Info.setLabel(Res);
}
unsigned Size = Context.getTypeSizeInChars(T).getQuantity();
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 3f2d38630c36..1184446796eb 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -976,20 +976,23 @@ ParsedTemplateArgument Sema::ActOnTemplateTypeArgument(TypeResult ParsedType) {
/// If the type parameter has a default argument, it will be added
/// later via ActOnTypeParameterDefault.
NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename,
- SourceLocation EllipsisLoc,
- SourceLocation KeyLoc,
- IdentifierInfo *ParamName,
- SourceLocation ParamNameLoc,
- unsigned Depth, unsigned Position,
- SourceLocation EqualLoc,
- ParsedType DefaultArg) {
+ SourceLocation EllipsisLoc,
+ SourceLocation KeyLoc,
+ IdentifierInfo *ParamName,
+ SourceLocation ParamNameLoc,
+ unsigned Depth, unsigned Position,
+ SourceLocation EqualLoc,
+ ParsedType DefaultArg,
+ bool HasTypeConstraint) {
assert(S->isTemplateParamScope() &&
"Template type parameter not in template parameter scope!");
bool IsParameterPack = EllipsisLoc.isValid();
- TemplateTypeParmDecl *Param = TemplateTypeParmDecl::Create(
- Context, Context.getTranslationUnitDecl(), KeyLoc, ParamNameLoc, Depth,
- Position, ParamName, Typename, IsParameterPack);
+ TemplateTypeParmDecl *Param
+ = TemplateTypeParmDecl::Create(Context, Context.getTranslationUnitDecl(),
+ KeyLoc, ParamNameLoc, Depth, Position,
+ ParamName, Typename, IsParameterPack,
+ HasTypeConstraint);
Param->setAccess(AS_public);
if (Param->isParameterPack())
@@ -1036,6 +1039,125 @@ NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename,
return Param;
}
+/// Convert the parser's template argument list representation into our form.
+static TemplateArgumentListInfo
+makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) {
+ TemplateArgumentListInfo TemplateArgs(TemplateId.LAngleLoc,
+ TemplateId.RAngleLoc);
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId.getTemplateArgs(),
+ TemplateId.NumArgs);
+ S.translateTemplateArguments(TemplateArgsPtr, TemplateArgs);
+ return TemplateArgs;
+}
+
+bool Sema::ActOnTypeConstraint(TemplateIdAnnotation *TypeConstr,
+ TemplateTypeParmDecl *ConstrainedParameter,
+ SourceLocation EllipsisLoc) {
+ ConceptDecl *CD =
+ cast<ConceptDecl>(TypeConstr->Template.get().getAsTemplateDecl());
+
+ // C++2a [temp.param]p4:
+ // [...] The concept designated by a type-constraint shall be a type
+ // concept ([temp.concept]).
+ if (!CD->isTypeConcept()) {
+ Diag(TypeConstr->TemplateNameLoc,
+ diag::err_type_constraint_non_type_concept);
+ return true;
+ }
+
+ bool WereArgsSpecified = TypeConstr->LAngleLoc.isValid();
+
+ if (!WereArgsSpecified &&
+ CD->getTemplateParameters()->getMinRequiredArguments() > 1) {
+ Diag(TypeConstr->TemplateNameLoc,
+ diag::err_type_constraint_missing_arguments) << CD;
+ return true;
+ }
+
+ TemplateArgumentListInfo TemplateArgs;
+ if (TypeConstr->LAngleLoc.isValid()) {
+ TemplateArgs =
+ makeTemplateArgumentListInfo(*this, *TypeConstr);
+ }
+ return AttachTypeConstraint(
+ TypeConstr->SS.isSet() ? TypeConstr->SS.getWithLocInContext(Context) :
+ NestedNameSpecifierLoc(),
+ DeclarationNameInfo(DeclarationName(TypeConstr->Name),
+ TypeConstr->TemplateNameLoc), CD,
+ TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr,
+ ConstrainedParameter, EllipsisLoc);
+}
+
+/// Attach a type-constraint to a template parameter.
+/// \returns true if an error occured. This can happen if the
+/// immediately-declared constraint could not be formed (e.g. incorrect number
+/// of arguments for the named concept).
+bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS,
+ DeclarationNameInfo NameInfo,
+ ConceptDecl *NamedConcept,
+ const TemplateArgumentListInfo *TemplateArgs,
+ TemplateTypeParmDecl *ConstrainedParameter,
+ SourceLocation EllipsisLoc) {
+ // C++2a [temp.param]p4:
+ // [...] If Q is of the form C<A1, ..., An>, then let E' be
+ // C<T, A1, ..., An>. Otherwise, let E' be C<T>. [...]
+ const ASTTemplateArgumentListInfo *ArgsAsWritten =
+ TemplateArgs ? ASTTemplateArgumentListInfo::Create(Context,
+ *TemplateArgs) : nullptr;
+
+ QualType ParamAsArgument(ConstrainedParameter->getTypeForDecl(), 0);
+ TemplateArgumentListInfo ConstraintArgs;
+ ConstraintArgs.addArgument(
+ TemplateArgumentLoc(
+ TemplateArgument(ParamAsArgument),
+ TemplateArgumentLocInfo(
+ Context.getTrivialTypeSourceInfo(ParamAsArgument,
+ ConstrainedParameter->getLocation()))));
+ if (TemplateArgs) {
+ ConstraintArgs.setRAngleLoc(TemplateArgs->getRAngleLoc());
+ ConstraintArgs.setLAngleLoc(TemplateArgs->getLAngleLoc());
+ for (const TemplateArgumentLoc &ArgLoc : TemplateArgs->arguments())
+ ConstraintArgs.addArgument(ArgLoc);
+ }
+
+ // C++2a [temp.param]p4:
+ // [...] This constraint-expression E is called the immediately-declared
+ // constraint of T. [...]
+ CXXScopeSpec SS;
+ SS.Adopt(NS);
+ ExprResult ImmediatelyDeclaredConstraint = CheckConceptTemplateId(SS,
+ /*TemplateKWLoc=*/SourceLocation(), NameInfo, /*FoundDecl=*/NamedConcept,
+ NamedConcept, &ConstraintArgs);
+ if (ImmediatelyDeclaredConstraint.isInvalid())
+ return true;
+
+ if (ConstrainedParameter->isParameterPack()) {
+ // C++2a [temp.param]p4:
+ // [...] If T is not a pack, then E is E', otherwise E is (E' && ...).
+ //
+ // We have the following case:
+ //
+ // template<typename T> concept C1 = true;
+ // template<C1... T> struct s1;
+ //
+ // The constraint: (C1<T> && ...)
+ ImmediatelyDeclaredConstraint =
+ BuildCXXFoldExpr(/*LParenLoc=*/SourceLocation(),
+ ImmediatelyDeclaredConstraint.get(), BO_LAnd,
+ EllipsisLoc, /*RHS=*/nullptr,
+ /*RParenLoc=*/SourceLocation(),
+ /*NumExpansions=*/None).get();
+ if (ImmediatelyDeclaredConstraint.isInvalid())
+ return true;
+ }
+
+ ConstrainedParameter->setTypeConstraint(NS, NameInfo,
+ /*FoundDecl=*/NamedConcept,
+ NamedConcept, ArgsAsWritten,
+ ImmediatelyDeclaredConstraint.get());
+ return false;
+}
+
/// Check that the type of a non-type template parameter is
/// well-formed.
///
@@ -1120,11 +1242,11 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
// Check that we have valid decl-specifiers specified.
auto CheckValidDeclSpecifiers = [this, &D] {
// C++ [temp.param]
- // p1
+ // p1
// template-parameter:
// ...
// parameter-declaration
- // p2
+ // p2
// ... A storage class shall not be specified in a template-parameter
// declaration.
// [dcl.typedef]p1:
@@ -1868,7 +1990,23 @@ private:
SemaRef.Context, DC, TTP->getBeginLoc(), TTP->getLocation(),
/*Depth*/ 0, Depth1IndexAdjustment + TTP->getIndex(),
TTP->getIdentifier(), TTP->wasDeclaredWithTypename(),
- TTP->isParameterPack());
+ TTP->isParameterPack(), TTP->hasTypeConstraint(),
+ TTP->isExpandedParameterPack() ?
+ llvm::Optional<unsigned>(TTP->getNumExpansionParameters()) : None);
+ if (const auto *TC = TTP->getTypeConstraint()) {
+ TemplateArgumentListInfo TransformedArgs;
+ const auto *ArgsAsWritten = TC->getTemplateArgsAsWritten();
+ if (SemaRef.Subst(ArgsAsWritten->getTemplateArgs(),
+ ArgsAsWritten->NumTemplateArgs, TransformedArgs,
+ Args))
+ SemaRef.AttachTypeConstraint(
+ TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(),
+ TC->getNamedConcept(), &TransformedArgs, NewTTP,
+ NewTTP->isParameterPack()
+ ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
+ ->getEllipsisLoc()
+ : SourceLocation());
+ }
if (TTP->hasDefaultArgument()) {
TypeSourceInfo *InstantiatedDefaultArg =
SemaRef.SubstType(TTP->getDefaultArgumentInfo(), Args,
@@ -1894,7 +2032,7 @@ private:
// Ask the template instantiator to do the heavy lifting for us, then adjust
// the index of the parameter once it's done.
auto *NewParam =
- cast_or_null<TemplateParmDecl>(SemaRef.SubstDecl(OldParam, DC, Args));
+ cast<TemplateParmDecl>(SemaRef.SubstDecl(OldParam, DC, Args));
assert(NewParam->getDepth() == 0 && "unexpected template param depth");
NewParam->setPosition(NewParam->getPosition() + Depth1IndexAdjustment);
return NewParam;
@@ -2177,6 +2315,17 @@ static bool DiagnoseUnexpandedParameterPacks(Sema &S,
TemplateParameterList *Params = TTP->getTemplateParameters();
for (unsigned I = 0, N = Params->size(); I != N; ++I) {
NamedDecl *P = Params->getParam(I);
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(P)) {
+ if (!TTP->isParameterPack())
+ if (const TypeConstraint *TC = TTP->getTypeConstraint())
+ if (TC->hasExplicitTemplateArgs())
+ for (auto &ArgLoc : TC->getTemplateArgsAsWritten()->arguments())
+ if (S.DiagnoseUnexpandedParameterPack(ArgLoc,
+ Sema::UPPC_TypeConstraint))
+ return true;
+ continue;
+ }
+
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) {
if (!NTTP->isParameterPack() &&
S.DiagnoseUnexpandedParameterPack(NTTP->getLocation(),
@@ -2549,6 +2698,9 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> {
/// list.
static bool
DependsOnTemplateParameters(QualType T, TemplateParameterList *Params) {
+ if (!Params->size())
+ return false;
+
DependencyChecker Checker(Params, /*IgnoreNonTypeDependent*/false);
Checker.TraverseType(T);
return Checker.Match;
@@ -3210,8 +3362,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
TemplateDecl *Template = Name.getAsTemplateDecl();
if (!Template || isa<FunctionTemplateDecl>(Template) ||
- isa<VarTemplateDecl>(Template) ||
- isa<ConceptDecl>(Template)) {
+ isa<VarTemplateDecl>(Template) || isa<ConceptDecl>(Template)) {
// We might have a substituted template template parameter pack. If so,
// build a template specialization type for it.
if (Name.getAsSubstTemplateTemplateParmPack())
@@ -3227,7 +3378,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// template.
SmallVector<TemplateArgument, 4> Converted;
if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs,
- false, Converted))
+ false, Converted,
+ /*UpdateArgsWithConversion=*/true))
return QualType();
QualType CanonType;
@@ -3235,6 +3387,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
bool InstantiationDependent = false;
if (TypeAliasTemplateDecl *AliasTemplate =
dyn_cast<TypeAliasTemplateDecl>(Template)) {
+
// Find the canonical type for this type alias template specialization.
TypeAliasDecl *Pattern = AliasTemplate->getTemplatedDecl();
if (Pattern->isInvalidDecl())
@@ -3707,17 +3860,6 @@ static bool isSameAsPrimaryTemplate(TemplateParameterList *Params,
return true;
}
-/// Convert the parser's template argument list representation into our form.
-static TemplateArgumentListInfo
-makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) {
- TemplateArgumentListInfo TemplateArgs(TemplateId.LAngleLoc,
- TemplateId.RAngleLoc);
- ASTTemplateArgsPtr TemplateArgsPtr(TemplateId.getTemplateArgs(),
- TemplateId.NumArgs);
- S.translateTemplateArguments(TemplateArgsPtr, TemplateArgs);
- return TemplateArgs;
-}
-
template<typename PartialSpecDecl>
static void checkMoreSpecializedThanPrimary(Sema &S, PartialSpecDecl *Partial) {
if (Partial->getDeclContext()->isDependentContext())
@@ -3746,6 +3888,11 @@ static void checkMoreSpecializedThanPrimary(Sema &S, PartialSpecDecl *Partial) {
}
S.Diag(Template->getLocation(), diag::note_template_decl_here);
+ SmallVector<const Expr *, 3> PartialAC, TemplateAC;
+ Template->getAssociatedConstraints(TemplateAC);
+ Partial->getAssociatedConstraints(PartialAC);
+ S.MaybeEmitAmbiguousAtomicConstraintsDiagnostic(Partial, PartialAC, Template,
+ TemplateAC);
}
static void
@@ -3872,7 +4019,8 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
// template.
SmallVector<TemplateArgument, 4> Converted;
if (CheckTemplateArgumentList(VarTemplate, TemplateNameLoc, TemplateArgs,
- false, Converted))
+ false, Converted,
+ /*UpdateArgsWithConversion=*/true))
return true;
// Find the variable template (partial) specialization declaration that
@@ -3895,7 +4043,9 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
}
if (isSameAsPrimaryTemplate(VarTemplate->getTemplateParameters(),
- Converted)) {
+ Converted) &&
+ (!Context.getLangOpts().ConceptsTS ||
+ !TemplateParams->hasAssociatedConstraints())) {
// C++ [temp.class.spec]p9b3:
//
// -- The argument list of the specialization shall not be identical
@@ -3914,8 +4064,8 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
VarTemplateSpecializationDecl *PrevDecl = nullptr;
if (IsPartialSpecialization)
- // FIXME: Template parameter list matters too
- PrevDecl = VarTemplate->findPartialSpecialization(Converted, InsertPos);
+ PrevDecl = VarTemplate->findPartialSpecialization(Converted, TemplateParams,
+ InsertPos);
else
PrevDecl = VarTemplate->findSpecialization(Converted, InsertPos);
@@ -4043,7 +4193,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
if (CheckTemplateArgumentList(
Template, TemplateNameLoc,
const_cast<TemplateArgumentListInfo &>(TemplateArgs), false,
- Converted))
+ Converted, /*UpdateArgsWithConversion=*/true))
return true;
// Find the variable template specialization declaration that
@@ -4221,20 +4371,20 @@ void Sema::diagnoseMissingTemplateArguments(TemplateName Name,
ExprResult
Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
- SourceLocation ConceptNameLoc,
+ const DeclarationNameInfo &ConceptNameInfo,
NamedDecl *FoundDecl,
ConceptDecl *NamedConcept,
const TemplateArgumentListInfo *TemplateArgs) {
assert(NamedConcept && "A concept template id without a template?");
llvm::SmallVector<TemplateArgument, 4> Converted;
- if (CheckTemplateArgumentList(NamedConcept, ConceptNameLoc,
+ if (CheckTemplateArgumentList(NamedConcept, ConceptNameInfo.getLoc(),
const_cast<TemplateArgumentListInfo&>(*TemplateArgs),
/*PartialTemplateArgs=*/false, Converted,
/*UpdateArgsWithConversion=*/false))
return ExprError();
- Optional<bool> IsSatisfied;
+ ConstraintSatisfaction Satisfaction;
bool AreArgsDependent = false;
for (TemplateArgument &Arg : Converted) {
if (Arg.isDependent()) {
@@ -4242,25 +4392,21 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
break;
}
}
- if (!AreArgsDependent) {
- InstantiatingTemplate Inst(*this, ConceptNameLoc,
- InstantiatingTemplate::ConstraintsCheck{}, NamedConcept, Converted,
- SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameLoc,
- TemplateArgs->getRAngleLoc()));
- MultiLevelTemplateArgumentList MLTAL;
- MLTAL.addOuterTemplateArguments(Converted);
- bool Satisfied;
- if (CalculateConstraintSatisfaction(NamedConcept, MLTAL,
- NamedConcept->getConstraintExpr(),
- Satisfied))
+ if (!AreArgsDependent &&
+ CheckConstraintSatisfaction(NamedConcept,
+ {NamedConcept->getConstraintExpr()},
+ Converted,
+ SourceRange(SS.isSet() ? SS.getBeginLoc() :
+ ConceptNameInfo.getLoc(),
+ TemplateArgs->getRAngleLoc()),
+ Satisfaction))
return ExprError();
- IsSatisfied = Satisfied;
- }
+
return ConceptSpecializationExpr::Create(Context,
SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{},
- TemplateKWLoc, ConceptNameLoc, FoundDecl, NamedConcept,
+ TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept,
ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), Converted,
- IsSatisfied);
+ AreArgsDependent ? nullptr : &Satisfaction);
}
ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
@@ -4304,8 +4450,7 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
}
if (R.getAsSingle<ConceptDecl>()) {
- return CheckConceptTemplateId(SS, TemplateKWLoc,
- R.getLookupNameInfo().getBeginLoc(),
+ return CheckConceptTemplateId(SS, TemplateKWLoc, R.getLookupNameInfo(),
R.getFoundDecl(),
R.getAsSingle<ConceptDecl>(), TemplateArgs);
}
@@ -5108,7 +5253,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
- if (CheckTemplateTemplateArgument(Params, Arg))
+ if (CheckTemplateTemplateArgument(TempParm, Params, Arg))
return true;
Converted.push_back(Arg.getArgument());
@@ -5148,6 +5293,12 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
/// In \c A<int,int>::B, \c NTs and \c TTs have expanded pack size 2, and \c Us
/// is not a pack expansion, so returns an empty Optional.
static Optional<unsigned> getExpandedPackSize(NamedDecl *Param) {
+ if (TemplateTypeParmDecl *TTP
+ = dyn_cast<TemplateTypeParmDecl>(Param)) {
+ if (TTP->isExpandedParameterPack())
+ return TTP->getNumExpansionParameters();
+ }
+
if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(Param)) {
if (NTTP->isExpandedParameterPack())
@@ -5206,7 +5357,11 @@ bool Sema::CheckTemplateArgumentList(
TemplateDecl *Template, SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs,
SmallVectorImpl<TemplateArgument> &Converted,
- bool UpdateArgsWithConversions) {
+ bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied) {
+
+ if (ConstraintsNotSatisfied)
+ *ConstraintsNotSatisfied = false;
+
// Make a copy of the template arguments for processing. Only make the
// changes at the end when successful in matching the arguments to the
// template.
@@ -5268,12 +5423,16 @@ bool Sema::CheckTemplateArgumentList(
bool PackExpansionIntoNonPack =
NewArgs[ArgIdx].getArgument().isPackExpansion() &&
(!(*Param)->isTemplateParameterPack() || getExpandedPackSize(*Param));
- if (PackExpansionIntoNonPack && isa<TypeAliasTemplateDecl>(Template)) {
+ if (PackExpansionIntoNonPack && (isa<TypeAliasTemplateDecl>(Template) ||
+ isa<ConceptDecl>(Template))) {
// Core issue 1430: we have a pack expansion as an argument to an
// alias template, and it's not part of a parameter pack. This
// can't be canonicalized, so reject it now.
+ // As for concepts - we cannot normalize constraints where this
+ // situation exists.
Diag(NewArgs[ArgIdx].getLocation(),
- diag::err_alias_template_expansion_into_fixed_list)
+ diag::err_template_expansion_into_fixed_list)
+ << (isa<ConceptDecl>(Template) ? 1 : 0)
<< NewArgs[ArgIdx].getSourceRange();
Diag((*Param)->getLocation(), diag::note_template_param_here);
return true;
@@ -5321,7 +5480,6 @@ bool Sema::CheckTemplateArgumentList(
if ((*Param)->isTemplateParameterPack() && !ArgumentPack.empty())
Converted.push_back(
TemplateArgument::CreatePackCopy(Context, ArgumentPack));
-
return false;
}
@@ -5460,6 +5618,15 @@ bool Sema::CheckTemplateArgumentList(
if (UpdateArgsWithConversions)
TemplateArgs = std::move(NewArgs);
+ if (!PartialTemplateArgs &&
+ EnsureTemplateArgumentListConstraints(
+ Template, Converted, SourceRange(TemplateLoc,
+ TemplateArgs.getRAngleLoc()))) {
+ if (ConstraintsNotSatisfied)
+ *ConstraintsNotSatisfied = true;
+ return true;
+ }
+
return false;
}
@@ -6870,7 +7037,8 @@ static void DiagnoseTemplateParameterListArityMismatch(
///
/// This routine implements the semantics of C++ [temp.arg.template].
/// It returns true if an error occurred, and false otherwise.
-bool Sema::CheckTemplateTemplateArgument(TemplateParameterList *Params,
+bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
+ TemplateParameterList *Params,
TemplateArgumentLoc &Arg) {
TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern();
TemplateDecl *Template = Name.getAsTemplateDecl();
@@ -6909,6 +7077,9 @@ bool Sema::CheckTemplateTemplateArgument(TemplateParameterList *Params,
// C++1z [temp.arg.template]p3: (DR 150)
// A template-argument matches a template template-parameter P when P
// is at least as specialized as the template-argument A.
+ // FIXME: We should enable RelaxedTemplateTemplateArgs by default as it is a
+ // defect report resolution from C++17 and shouldn't be introduced by
+ // concepts.
if (getLangOpts().RelaxedTemplateTemplateArgs) {
// Quick check for the common case:
// If P contains a parameter pack, then A [...] matches P if each of A's
@@ -6916,12 +7087,39 @@ bool Sema::CheckTemplateTemplateArgument(TemplateParameterList *Params,
// the template-parameter-list of P.
if (TemplateParameterListsAreEqual(
Template->getTemplateParameters(), Params, false,
- TPL_TemplateTemplateArgumentMatch, Arg.getLocation()))
+ TPL_TemplateTemplateArgumentMatch, Arg.getLocation()) &&
+ // If the argument has no associated constraints, then the parameter is
+ // definitely at least as specialized as the argument.
+ // Otherwise - we need a more thorough check.
+ !Template->hasAssociatedConstraints())
return false;
if (isTemplateTemplateParameterAtLeastAsSpecializedAs(Params, Template,
- Arg.getLocation()))
+ Arg.getLocation())) {
+ // C++2a[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].
+ SmallVector<const Expr *, 3> ParamsAC, TemplateAC;
+ Params->getAssociatedConstraints(ParamsAC);
+ Template->getAssociatedConstraints(TemplateAC);
+ bool IsParamAtLeastAsConstrained;
+ if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC,
+ IsParamAtLeastAsConstrained))
+ return true;
+ if (!IsParamAtLeastAsConstrained) {
+ Diag(Arg.getLocation(),
+ diag::err_template_template_parameter_not_at_least_as_constrained)
+ << Template << Param << Arg.getSourceRange();
+ Diag(Param->getLocation(), diag::note_entity_declared_at) << Param;
+ Diag(Template->getLocation(), diag::note_entity_declared_at)
+ << Template;
+ MaybeEmitAmbiguousAtomicConstraintsDiagnostic(Param, ParamsAC, Template,
+ TemplateAC);
+ return true;
+ }
return false;
+ }
// FIXME: Produce better diagnostics for deduction failures.
}
@@ -6965,94 +7163,73 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
ValueDecl *VD = Arg.getAsDecl();
- if (VD->getDeclContext()->isRecord() &&
- (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD) ||
- isa<IndirectFieldDecl>(VD))) {
- // If the value is a class member, we might have a pointer-to-member.
- // Determine whether the non-type template template parameter is of
- // pointer-to-member type. If so, we need to build an appropriate
- // expression for a pointer-to-member, since a "normal" DeclRefExpr
- // would refer to the member itself.
- if (ParamType->isMemberPointerType()) {
- QualType ClassType
- = Context.getTypeDeclType(cast<RecordDecl>(VD->getDeclContext()));
- NestedNameSpecifier *Qualifier
- = NestedNameSpecifier::Create(Context, nullptr, false,
- ClassType.getTypePtr());
- CXXScopeSpec SS;
- SS.MakeTrivial(Context, Qualifier, Loc);
-
- // The actual value-ness of this is unimportant, but for
- // internal consistency's sake, references to instance methods
- // are r-values.
- ExprValueKind VK = VK_LValue;
- if (isa<CXXMethodDecl>(VD) && cast<CXXMethodDecl>(VD)->isInstance())
- VK = VK_RValue;
-
- ExprResult RefExpr = BuildDeclRefExpr(VD,
- VD->getType().getNonReferenceType(),
- VK,
- Loc,
- &SS);
- if (RefExpr.isInvalid())
- return ExprError();
-
- RefExpr = CreateBuiltinUnaryOp(Loc, UO_AddrOf, RefExpr.get());
-
- // We might need to perform a trailing qualification conversion, since
- // the element type on the parameter could be more qualified than the
- // element type in the expression we constructed.
- bool ObjCLifetimeConversion;
- if (IsQualificationConversion(((Expr*) RefExpr.get())->getType(),
- ParamType.getUnqualifiedType(), false,
- ObjCLifetimeConversion))
- RefExpr = ImpCastExprToType(RefExpr.get(), ParamType.getUnqualifiedType(), CK_NoOp);
-
- assert(!RefExpr.isInvalid() &&
- Context.hasSameType(((Expr*) RefExpr.get())->getType(),
- ParamType.getUnqualifiedType()));
- return RefExpr;
- }
+ CXXScopeSpec SS;
+ if (ParamType->isMemberPointerType()) {
+ // If this is a pointer to member, we need to use a qualified name to
+ // form a suitable pointer-to-member constant.
+ assert(VD->getDeclContext()->isRecord() &&
+ (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD) ||
+ isa<IndirectFieldDecl>(VD)));
+ QualType ClassType
+ = Context.getTypeDeclType(cast<RecordDecl>(VD->getDeclContext()));
+ NestedNameSpecifier *Qualifier
+ = NestedNameSpecifier::Create(Context, nullptr, false,
+ ClassType.getTypePtr());
+ SS.MakeTrivial(Context, Qualifier, Loc);
}
- QualType T = VD->getType().getNonReferenceType();
+ ExprResult RefExpr = BuildDeclarationNameExpr(
+ SS, DeclarationNameInfo(VD->getDeclName(), Loc), VD);
+ if (RefExpr.isInvalid())
+ return ExprError();
- if (ParamType->isPointerType()) {
- // When the non-type template parameter is a pointer, take the
- // address of the declaration.
- ExprResult RefExpr = BuildDeclRefExpr(VD, T, VK_LValue, Loc);
+ // For a pointer, the argument declaration is the pointee. Take its address.
+ QualType ElemT(RefExpr.get()->getType()->getArrayElementTypeNoTypeQual(), 0);
+ if (ParamType->isPointerType() && !ElemT.isNull() &&
+ Context.hasSimilarType(ElemT, ParamType->getPointeeType())) {
+ // Decay an array argument if we want a pointer to its first element.
+ RefExpr = DefaultFunctionArrayConversion(RefExpr.get());
if (RefExpr.isInvalid())
return ExprError();
-
- if (!Context.hasSameUnqualifiedType(ParamType->getPointeeType(), T) &&
- (T->isFunctionType() || T->isArrayType())) {
- // Decay functions and arrays unless we're forming a pointer to array.
- RefExpr = DefaultFunctionArrayConversion(RefExpr.get());
- if (RefExpr.isInvalid())
- return ExprError();
-
- return RefExpr;
- }
-
- // Take the address of everything else
- return CreateBuiltinUnaryOp(Loc, UO_AddrOf, RefExpr.get());
+ } else if (ParamType->isPointerType() || ParamType->isMemberPointerType()) {
+ // For any other pointer, take the address (or form a pointer-to-member).
+ RefExpr = CreateBuiltinUnaryOp(Loc, UO_AddrOf, RefExpr.get());
+ if (RefExpr.isInvalid())
+ return ExprError();
+ } else {
+ assert(ParamType->isReferenceType() &&
+ "unexpected type for decl template argument");
}
- ExprValueKind VK = VK_RValue;
+ // At this point we should have the right value category.
+ assert(ParamType->isReferenceType() == RefExpr.get()->isLValue() &&
+ "value kind mismatch for non-type template argument");
- // If the non-type template parameter has reference type, qualify the
- // resulting declaration reference with the extra qualifiers on the
- // type that the reference refers to.
- if (const ReferenceType *TargetRef = ParamType->getAs<ReferenceType>()) {
- VK = VK_LValue;
- T = Context.getQualifiedType(T,
- TargetRef->getPointeeType().getQualifiers());
- } else if (isa<FunctionDecl>(VD)) {
- // References to functions are always lvalues.
- VK = VK_LValue;
+ // The type of the template parameter can differ from the type of the
+ // argument in various ways; convert it now if necessary.
+ QualType DestExprType = ParamType.getNonLValueExprType(Context);
+ if (!Context.hasSameType(RefExpr.get()->getType(), DestExprType)) {
+ CastKind CK;
+ QualType Ignored;
+ if (Context.hasSimilarType(RefExpr.get()->getType(), DestExprType) ||
+ IsFunctionConversion(RefExpr.get()->getType(), DestExprType, Ignored)) {
+ CK = CK_NoOp;
+ } else if (ParamType->isVoidPointerType() &&
+ RefExpr.get()->getType()->isPointerType()) {
+ CK = CK_BitCast;
+ } else {
+ // FIXME: Pointers to members can need conversion derived-to-base or
+ // base-to-derived conversions. We currently don't retain enough
+ // information to convert properly (we need to track a cast path or
+ // subobject number in the template argument).
+ llvm_unreachable(
+ "unexpected conversion required for non-type template argument");
+ }
+ RefExpr = ImpCastExprToType(RefExpr.get(), DestExprType, CK,
+ RefExpr.get()->getValueKind());
}
- return BuildDeclRefExpr(VD, T, VK, Loc);
+ return RefExpr;
}
/// Construct a new expression that refers to the given
@@ -7173,50 +7350,73 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
// template parameter and one of the non-type template parameter types
// is dependent, then we must wait until template instantiation time
// to actually compare the arguments.
- if (Kind == Sema::TPL_TemplateTemplateArgumentMatch &&
- (OldNTTP->getType()->isDependentType() ||
- NewNTTP->getType()->isDependentType()))
- return true;
-
- if (!S.Context.hasSameType(OldNTTP->getType(), NewNTTP->getType())) {
- if (Complain) {
- unsigned NextDiag = diag::err_template_nontype_parm_different_type;
- if (TemplateArgLoc.isValid()) {
- S.Diag(TemplateArgLoc,
- diag::err_template_arg_template_params_mismatch);
- NextDiag = diag::note_template_nontype_parm_different_type;
+ if (Kind != Sema::TPL_TemplateTemplateArgumentMatch ||
+ (!OldNTTP->getType()->isDependentType() &&
+ !NewNTTP->getType()->isDependentType()))
+ if (!S.Context.hasSameType(OldNTTP->getType(), NewNTTP->getType())) {
+ if (Complain) {
+ unsigned NextDiag = diag::err_template_nontype_parm_different_type;
+ if (TemplateArgLoc.isValid()) {
+ S.Diag(TemplateArgLoc,
+ diag::err_template_arg_template_params_mismatch);
+ NextDiag = diag::note_template_nontype_parm_different_type;
+ }
+ S.Diag(NewNTTP->getLocation(), NextDiag)
+ << NewNTTP->getType()
+ << (Kind != Sema::TPL_TemplateMatch);
+ S.Diag(OldNTTP->getLocation(),
+ diag::note_template_nontype_parm_prev_declaration)
+ << OldNTTP->getType();
}
- S.Diag(NewNTTP->getLocation(), NextDiag)
- << NewNTTP->getType()
- << (Kind != Sema::TPL_TemplateMatch);
- S.Diag(OldNTTP->getLocation(),
- diag::note_template_nontype_parm_prev_declaration)
- << OldNTTP->getType();
- }
- return false;
- }
-
- return true;
+ return false;
+ }
}
-
// For template template parameters, check the template parameter types.
// The template parameter lists of template template
// parameters must agree.
- if (TemplateTemplateParmDecl *OldTTP
+ else if (TemplateTemplateParmDecl *OldTTP
= dyn_cast<TemplateTemplateParmDecl>(Old)) {
TemplateTemplateParmDecl *NewTTP = cast<TemplateTemplateParmDecl>(New);
- return S.TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(),
- OldTTP->getTemplateParameters(),
- Complain,
+ if (!S.TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(),
+ OldTTP->getTemplateParameters(),
+ Complain,
(Kind == Sema::TPL_TemplateMatch
? Sema::TPL_TemplateTemplateParmMatch
: Kind),
- TemplateArgLoc);
- }
+ TemplateArgLoc))
+ return false;
+ } else if (Kind != Sema::TPL_TemplateTemplateArgumentMatch) {
+ 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();
+
+ auto Diagnose = [&] {
+ S.Diag(NewC ? NewC->getBeginLoc() : New->getBeginLoc(),
+ diag::err_template_different_type_constraint);
+ S.Diag(OldC ? OldC->getBeginLoc() : Old->getBeginLoc(),
+ diag::note_template_prev_declaration) << /*declaration*/0;
+ };
- // TODO: Concepts: Match immediately-introduced-constraint for type
- // constraints
+ if (!NewC != !OldC) {
+ if (Complain)
+ Diagnose();
+ return false;
+ }
+
+ if (NewC) {
+ llvm::FoldingSetNodeID OldCID, NewCID;
+ OldC->Profile(OldCID, S.Context, /*Canonical=*/true);
+ NewC->Profile(NewCID, S.Context, /*Canonical=*/true);
+ if (OldCID != NewCID) {
+ if (Complain)
+ Diagnose();
+ return false;
+ }
+ }
+ }
return true;
}
@@ -7243,15 +7443,6 @@ void DiagnoseTemplateParameterListArityMismatch(Sema &S,
<< SourceRange(Old->getTemplateLoc(), Old->getRAngleLoc());
}
-static void
-DiagnoseTemplateParameterListRequiresClauseMismatch(Sema &S,
- TemplateParameterList *New,
- TemplateParameterList *Old){
- S.Diag(New->getTemplateLoc(), diag::err_template_different_requires_clause);
- S.Diag(Old->getTemplateLoc(), diag::note_template_prev_declaration)
- << /*declaration*/0;
-}
-
/// Determine whether the given template parameter lists are
/// equivalent.
///
@@ -7344,9 +7535,17 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
if (Kind != TPL_TemplateTemplateArgumentMatch) {
const Expr *NewRC = New->getRequiresClause();
const Expr *OldRC = Old->getRequiresClause();
+
+ auto Diagnose = [&] {
+ Diag(NewRC ? NewRC->getBeginLoc() : New->getTemplateLoc(),
+ diag::err_template_different_requires_clause);
+ Diag(OldRC ? OldRC->getBeginLoc() : Old->getTemplateLoc(),
+ diag::note_template_prev_declaration) << /*declaration*/0;
+ };
+
if (!NewRC != !OldRC) {
if (Complain)
- DiagnoseTemplateParameterListRequiresClauseMismatch(*this, New, Old);
+ Diagnose();
return false;
}
@@ -7356,7 +7555,7 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
NewRC->Profile(NewRCID, Context, /*Canonical=*/true);
if (OldRCID != NewRCID) {
if (Complain)
- DiagnoseTemplateParameterListRequiresClauseMismatch(*this, New, Old);
+ Diagnose();
return false;
}
}
@@ -7382,7 +7581,8 @@ Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) {
// C++ [temp]p4:
// A template [...] shall not have C linkage.
DeclContext *Ctx = S->getEntity();
- if (Ctx && Ctx->isExternCContext()) {
+ assert(Ctx && "Unknown context");
+ if (Ctx->isExternCContext()) {
Diag(TemplateParams->getTemplateLoc(), diag::err_template_linkage)
<< TemplateParams->getSourceRange();
if (const LinkageSpecDecl *LSD = Ctx->getExternCContext())
@@ -7794,7 +7994,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
// template.
SmallVector<TemplateArgument, 4> Converted;
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc,
- TemplateArgs, false, Converted))
+ TemplateArgs, false, Converted,
+ /*UpdateArgsWithConversion=*/true))
return true;
// Find the class template (partial) specialization declaration that
@@ -7820,8 +8021,9 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
ClassTemplateSpecializationDecl *PrevDecl = nullptr;
if (isPartialSpecialization)
- // FIXME: Template parameter list matters, too
- PrevDecl = ClassTemplate->findPartialSpecialization(Converted, InsertPos);
+ PrevDecl = ClassTemplate->findPartialSpecialization(Converted,
+ TemplateParams,
+ InsertPos);
else
PrevDecl = ClassTemplate->findSpecialization(Converted, InsertPos);
@@ -7845,7 +8047,9 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
Converted);
if (Context.hasSameType(CanonType,
- ClassTemplate->getInjectedClassNameSpecialization())) {
+ ClassTemplate->getInjectedClassNameSpecialization()) &&
+ (!Context.getLangOpts().ConceptsTS ||
+ !TemplateParams->hasAssociatedConstraints())) {
// C++ [temp.class.spec]p9b3:
//
// -- The argument list of the specialization shall not be identical
@@ -9040,7 +9244,8 @@ DeclResult Sema::ActOnExplicitInstantiation(
// template.
SmallVector<TemplateArgument, 4> Converted;
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc,
- TemplateArgs, false, Converted))
+ TemplateArgs, false, Converted,
+ /*UpdateArgsWithConversion=*/true))
return true;
// Find the class template specialization declaration that
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 64ef819e30d4..1b9f1b2144d1 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -24,6 +24,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
@@ -642,6 +643,10 @@ static TemplateParameter makeTemplateParameter(Decl *D) {
/// If \p Param is an expanded parameter pack, get the number of expansions.
static Optional<unsigned> getExpandedPackSize(NamedDecl *Param) {
+ if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
+ if (TTP->isExpandedParameterPack())
+ return TTP->getNumExpansionParameters();
+
if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param))
if (NTTP->isExpandedParameterPack())
return NTTP->getNumExpansionTypes();
@@ -859,34 +864,31 @@ public:
/// Finish template argument deduction for a set of argument packs,
/// producing the argument packs and checking for consistency with prior
/// deductions.
- Sema::TemplateDeductionResult
- finish(bool TreatNoDeductionsAsNonDeduced = true) {
+ Sema::TemplateDeductionResult finish() {
// Build argument packs for each of the parameter packs expanded by this
// pack expansion.
for (auto &Pack : Packs) {
// Put back the old value for this pack.
Deduced[Pack.Index] = Pack.Saved;
- // If we are deducing the size of this pack even if we didn't deduce any
- // values for it, then make sure we build a pack of the right size.
- // FIXME: Should we always deduce the size, even if the pack appears in
- // a non-deduced context?
- if (!TreatNoDeductionsAsNonDeduced)
- Pack.New.resize(PackElements);
+ // Always make sure the size of this pack is correct, even if we didn't
+ // deduce any values for it.
+ //
+ // FIXME: This isn't required by the normative wording, but substitution
+ // and post-substitution checking will always fail if the arity of any
+ // pack is not equal to the number of elements we processed. (Either that
+ // or something else has gone *very* wrong.) We're permitted to skip any
+ // hard errors from those follow-on steps by the intent (but not the
+ // wording) of C++ [temp.inst]p8:
+ //
+ // If the function selected by overload resolution can be determined
+ // without instantiating a class template definition, it is unspecified
+ // whether that instantiation actually takes place
+ Pack.New.resize(PackElements);
// Build or find a new value for this pack.
DeducedTemplateArgument NewPack;
- if (PackElements && Pack.New.empty()) {
- if (Pack.DeferredDeduction.isNull()) {
- // We were not able to deduce anything for this parameter pack
- // (because it only appeared in non-deduced contexts), so just
- // restore the saved argument pack.
- continue;
- }
-
- NewPack = Pack.DeferredDeduction;
- Pack.DeferredDeduction = TemplateArgument();
- } else if (Pack.New.empty()) {
+ if (Pack.New.empty()) {
// If we deduced an empty argument pack, create it now.
NewPack = DeducedTemplateArgument(TemplateArgument::getEmptyPack());
} else {
@@ -2501,6 +2503,30 @@ Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg,
llvm_unreachable("Invalid TemplateArgument Kind!");
}
+TemplateArgumentLoc
+Sema::getIdentityTemplateArgumentLoc(Decl *TemplateParm,
+ SourceLocation Location) {
+ if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParm))
+ return getTrivialTemplateArgumentLoc(
+ TemplateArgument(
+ Context.getTemplateTypeParmType(TTP->getDepth(), TTP->getIndex(),
+ TTP->isParameterPack(), TTP)),
+ QualType(), Location.isValid() ? Location : TTP->getLocation());
+ else if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParm))
+ return getTrivialTemplateArgumentLoc(TemplateArgument(TemplateName(TTP)),
+ QualType(),
+ Location.isValid() ? Location :
+ TTP->getLocation());
+ auto *NTTP = cast<NonTypeTemplateParmDecl>(TemplateParm);
+ CXXScopeSpec SS;
+ DeclarationNameInfo Info(NTTP->getDeclName(),
+ Location.isValid() ? Location : NTTP->getLocation());
+ Expr *E = BuildDeclarationNameExpr(SS, Info, NTTP).get();
+ return getTrivialTemplateArgumentLoc(TemplateArgument(E), NTTP->getType(),
+ Location.isValid() ? Location :
+ NTTP->getLocation());
+}
+
/// Convert the given deduced template argument and add it to the set of
/// fully-converted template arguments.
static bool
@@ -2611,8 +2637,8 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments(
// be deduced to an empty sequence of template arguments.
// FIXME: Where did the word "trailing" come from?
if (Deduced[I].isNull() && Param->isTemplateParameterPack()) {
- if (auto Result = PackDeductionScope(S, TemplateParams, Deduced, Info, I)
- .finish(/*TreatNoDeductionsAsNonDeduced*/false))
+ if (auto Result =
+ PackDeductionScope(S, TemplateParams, Deduced, Info, I).finish())
return Result;
}
@@ -2709,6 +2735,23 @@ struct IsPartialSpecialization<VarTemplatePartialSpecializationDecl> {
static constexpr bool value = true;
};
+template<typename TemplateDeclT>
+static Sema::TemplateDeductionResult
+CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template,
+ ArrayRef<TemplateArgument> DeducedArgs,
+ TemplateDeductionInfo& Info) {
+ llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
+ Template->getAssociatedConstraints(AssociatedConstraints);
+ if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints,
+ DeducedArgs, Info.getLocation(),
+ Info.AssociatedConstraintsSatisfaction) ||
+ !Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
+ Info.reset(TemplateArgumentList::CreateCopy(S.Context, DeducedArgs));
+ return Sema::TDK_ConstraintsNotSatisfied;
+ }
+ return Sema::TDK_Success;
+}
+
/// Complete template argument deduction for a partial specialization.
template <typename T>
static typename std::enable_if<IsPartialSpecialization<T>::value,
@@ -2767,10 +2810,14 @@ FinishTemplateArgumentDeduction(
return Sema::TDK_SubstitutionFailure;
}
+ bool ConstraintsNotSatisfied;
SmallVector<TemplateArgument, 4> ConvertedInstArgs;
if (S.CheckTemplateArgumentList(Template, Partial->getLocation(), InstArgs,
- false, ConvertedInstArgs))
- return Sema::TDK_SubstitutionFailure;
+ false, ConvertedInstArgs,
+ /*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) {
@@ -2786,6 +2833,9 @@ FinishTemplateArgumentDeduction(
if (Trap.hasErrorOccurred())
return Sema::TDK_SubstitutionFailure;
+ if (auto Result = CheckDeducedArgumentConstraints(S, Partial, Builder, Info))
+ return Result;
+
return Sema::TDK_Success;
}
@@ -2828,10 +2878,13 @@ static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction(
if (Trap.hasErrorOccurred())
return Sema::TDK_SubstitutionFailure;
+ if (auto Result = CheckDeducedArgumentConstraints(S, Template, Builder,
+ Info))
+ return Result;
+
return Sema::TDK_Success;
}
-
/// Perform template argument deduction to determine whether
/// the given template arguments match the given class template
/// partial specialization per C++ [temp.class.spec.match].
@@ -3385,6 +3438,23 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
return TDK_SubstitutionFailure;
}
+ // C++2a [temp.deduct]p5
+ // [...] When all template arguments have been deduced [...] all uses of
+ // template parameters [...] are replaced with the corresponding deduced
+ // or default argument values.
+ // [...] If the function template has associated constraints
+ // ([temp.constr.decl]), those constraints are checked for satisfaction
+ // ([temp.constr.constr]). If the constraints are not satisfied, type
+ // deduction fails.
+ if (CheckInstantiatedFunctionTemplateConstraints(Info.getLocation(),
+ Specialization, Builder, Info.AssociatedConstraintsSatisfaction))
+ return TDK_MiscellaneousDeductionFailure;
+
+ if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
+ Info.reset(TemplateArgumentList::CreateCopy(Context, Builder));
+ return TDK_ConstraintsNotSatisfied;
+ }
+
if (OriginalCallArgs) {
// C++ [temp.deduct.call]p4:
// In general, the deduction process attempts to find template argument
@@ -3505,7 +3575,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
DeclAccessPair DAP;
if (FunctionDecl *Viable =
- S.resolveAddressOfOnlyViableOverloadCandidate(Arg, DAP))
+ S.resolveAddressOfSingleOverloadCandidate(Arg, DAP))
return GetTypeOfFunction(S, R, Viable);
return {};
@@ -4429,7 +4499,8 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
/*.IsPack = */ (bool)Type.getAs<PackExpansionTypeLoc>()};
if (!DependentDeductionDepth &&
- (Type.getType()->isDependentType() || Init->isTypeDependent())) {
+ (Type.getType()->isDependentType() || Init->isTypeDependent() ||
+ Init->containsUnexpandedParameterPack())) {
Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type);
assert(!Result.isNull() && "substituting DependentTy can't fail");
return DAR_Succeeded;
@@ -4475,11 +4546,12 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
// Build template<class TemplParam> void Func(FuncParam);
TemplateTypeParmDecl *TemplParam = TemplateTypeParmDecl::Create(
- Context, nullptr, SourceLocation(), Loc, Depth, 0, nullptr, false, false);
+ Context, nullptr, SourceLocation(), Loc, Depth, 0, nullptr, false, false,
+ false);
QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0);
NamedDecl *TemplParamPtr = TemplParam;
FixedSizeTemplateParameterListStorage<1, false> TemplateParamsSt(
- Loc, Loc, TemplParamPtr, Loc, nullptr);
+ Context, Loc, Loc, TemplParamPtr, Loc, nullptr);
QualType FuncParam =
SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/false)
@@ -4905,6 +4977,21 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
TemplatePartialOrderingContext TPOC,
unsigned NumCallArguments1,
unsigned NumCallArguments2) {
+
+ auto JudgeByConstraints = [&] () -> FunctionTemplateDecl * {
+ 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;
+ };
+
bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC,
NumCallArguments1);
bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC,
@@ -4914,7 +5001,7 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
return Better1 ? FT1 : FT2;
if (!Better1 && !Better2) // Neither is better than the other
- return nullptr;
+ return JudgeByConstraints();
// 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,
@@ -4924,7 +5011,7 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
if (Variadic1 != Variadic2)
return Variadic1? FT2 : FT1;
- return nullptr;
+ return JudgeByConstraints();
}
/// Determine if the two templates are equivalent.
@@ -5119,8 +5206,21 @@ Sema::getMoreSpecializedPartialSpecialization(
bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info);
bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info);
- if (Better1 == Better2)
- return nullptr;
+ 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;
}
@@ -5132,11 +5232,22 @@ bool Sema::isMoreSpecializedThanPrimary(
QualType PartialT = Spec->getInjectedSpecializationType();
if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info))
return false;
- if (isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) {
- Info.clearSFINAEDiagnostic();
+ 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;
- }
- return true;
+ if (!AtLeastAsConstrainedSpec)
+ return false;
+ if (IsAtLeastAsConstrained(Primary, PrimaryAC, Spec, SpecAC,
+ AtLeastAsConstrainedPrimary))
+ return false;
+ return !AtLeastAsConstrainedPrimary;
}
VarTemplatePartialSpecializationDecl *
@@ -5159,8 +5270,21 @@ Sema::getMoreSpecializedPartialSpecialization(
bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info);
bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info);
- if (Better1 == Better2)
+ 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;
}
@@ -5180,13 +5304,25 @@ bool Sema::isMoreSpecializedThanPrimary(
CanonTemplate, PrimaryArgs);
QualType PartialT = Context.getTemplateSpecializationType(
CanonTemplate, Spec->getTemplateArgs().asArray());
+
if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info))
return false;
- if (isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) {
- Info.clearSFINAEDiagnostic();
+ 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;
- }
- return true;
+ if (IsAtLeastAsConstrained(Primary, PrimaryAC, Spec, SpecAC,
+ AtLeastAsConstrainedPrimary))
+ return false;
+ return !AtLeastAsConstrainedPrimary;
}
bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
@@ -5220,7 +5356,8 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
SFINAETrap Trap(*this);
Context.getInjectedTemplateArgs(P, PArgs);
- TemplateArgumentListInfo PArgList(P->getLAngleLoc(), P->getRAngleLoc());
+ TemplateArgumentListInfo PArgList(P->getLAngleLoc(),
+ P->getRAngleLoc());
for (unsigned I = 0, N = P->size(); I != N; ++I) {
// Unwrap packs that getInjectedTemplateArgs wrapped around pack
// expansions, to form an "as written" argument list.
@@ -5252,6 +5389,41 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
return isAtLeastAsSpecializedAs(*this, PType, AType, AArg, Info);
}
+namespace {
+struct MarkUsedTemplateParameterVisitor :
+ RecursiveASTVisitor<MarkUsedTemplateParameterVisitor> {
+ llvm::SmallBitVector &Used;
+ unsigned Depth;
+
+ MarkUsedTemplateParameterVisitor(llvm::SmallBitVector &Used,
+ unsigned Depth)
+ : Used(Used), Depth(Depth) { }
+
+ bool VisitTemplateTypeParmType(TemplateTypeParmType *T) {
+ if (T->getDepth() == Depth)
+ Used[T->getIndex()] = true;
+ return true;
+ }
+
+ bool TraverseTemplateName(TemplateName Template) {
+ if (auto *TTP =
+ dyn_cast<TemplateTemplateParmDecl>(Template.getAsTemplateDecl()))
+ if (TTP->getDepth() == Depth)
+ Used[TTP->getIndex()] = true;
+ RecursiveASTVisitor<MarkUsedTemplateParameterVisitor>::
+ TraverseTemplateName(Template);
+ return true;
+ }
+
+ bool VisitDeclRefExpr(DeclRefExpr *E) {
+ if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(E->getDecl()))
+ if (NTTP->getDepth() == Depth)
+ Used[NTTP->getIndex()] = true;
+ return true;
+ }
+};
+}
+
/// Mark the template parameters that are used by the given
/// expression.
static void
@@ -5260,6 +5432,12 @@ MarkUsedTemplateParameters(ASTContext &Ctx,
bool OnlyDeduced,
unsigned Depth,
llvm::SmallBitVector &Used) {
+ if (!OnlyDeduced) {
+ MarkUsedTemplateParameterVisitor(Used, Depth)
+ .TraverseStmt(const_cast<Expr *>(E));
+ return;
+ }
+
// We can deduce from a pack expansion.
if (const PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(E))
E = Expansion->getPattern();
@@ -5278,8 +5456,6 @@ MarkUsedTemplateParameters(ASTContext &Ctx,
break;
}
- // FIXME: if !OnlyDeduced, we have to walk the whole subexpression to
- // find other occurrences of template parameters.
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E);
if (!DRE)
return;
@@ -5659,6 +5835,20 @@ MarkUsedTemplateParameters(ASTContext &Ctx,
}
}
+/// Mark which template parameters are used in a given expression.
+///
+/// \param E the expression from which template parameters will be deduced.
+///
+/// \param Used a bit vector whose elements will be set to \c true
+/// to indicate when the corresponding template parameter will be
+/// deduced.
+void
+Sema::MarkUsedTemplateParameters(const Expr *E, bool OnlyDeduced,
+ unsigned Depth,
+ llvm::SmallBitVector &Used) {
+ ::MarkUsedTemplateParameters(Context, E, OnlyDeduced, Depth, Used);
+}
+
/// Mark which template parameters can be deduced from a given
/// template argument list.
///
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 0daa33cfbef5..af41e231134d 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -150,7 +150,7 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
break;
// If this function is a generic lambda specialization, we are done.
- if (isGenericLambdaCallOperatorSpecialization(Function))
+ if (isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function))
break;
} else if (FunctionTemplateDecl *FunTmpl
@@ -203,9 +203,12 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
case DefaultTemplateArgumentChecking:
case DeclaringSpecialMember:
+ case DeclaringImplicitEqualityComparison:
case DefiningSynthesizedFunction:
case ExceptionSpecEvaluation:
case ConstraintSubstitution:
+ case ParameterMappingSubstitution:
+ case ConstraintNormalization:
case RewritingOperatorAsSpaceship:
return false;
@@ -363,7 +366,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema &SemaRef, SourceLocation PointOfInstantiation,
- ConstraintsCheck, TemplateDecl *Template,
+ ConstraintsCheck, NamedDecl *Template,
ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange)
: InstantiatingTemplate(
SemaRef, CodeSynthesisContext::ConstraintsCheck,
@@ -372,13 +375,29 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema &SemaRef, SourceLocation PointOfInstantiation,
- ConstraintSubstitution, TemplateDecl *Template,
+ ConstraintSubstitution, NamedDecl *Template,
sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange)
: InstantiatingTemplate(
SemaRef, CodeSynthesisContext::ConstraintSubstitution,
PointOfInstantiation, InstantiationRange, Template, nullptr,
{}, &DeductionInfo) {}
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation,
+ ConstraintNormalization, NamedDecl *Template,
+ SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef, CodeSynthesisContext::ConstraintNormalization,
+ PointOfInstantiation, InstantiationRange, Template) {}
+
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation,
+ ParameterMappingSubstitution, NamedDecl *Template,
+ SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef, CodeSynthesisContext::ParameterMappingSubstitution,
+ PointOfInstantiation, InstantiationRange, Template) {}
+
void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) {
Ctx.SavedInNonInstantiationSFINAEContext = InNonInstantiationSFINAEContext;
InNonInstantiationSFINAEContext = false;
@@ -671,14 +690,29 @@ void Sema::PrintInstantiationStack() {
<< cast<CXXRecordDecl>(Active->Entity) << Active->SpecialMember;
break;
+ case CodeSynthesisContext::DeclaringImplicitEqualityComparison:
+ Diags.Report(Active->Entity->getLocation(),
+ diag::note_in_declaration_of_implicit_equality_comparison);
+ break;
+
case CodeSynthesisContext::DefiningSynthesizedFunction: {
- // FIXME: For synthesized members other than special members, produce a note.
- auto *MD = dyn_cast<CXXMethodDecl>(Active->Entity);
- auto CSM = MD ? getSpecialMember(MD) : CXXInvalid;
- if (CSM != CXXInvalid) {
+ // FIXME: For synthesized functions that are not defaulted,
+ // produce a note.
+ auto *FD = dyn_cast<FunctionDecl>(Active->Entity);
+ DefaultedFunctionKind DFK =
+ FD ? getDefaultedFunctionKind(FD) : DefaultedFunctionKind();
+ if (DFK.isSpecialMember()) {
+ auto *MD = cast<CXXMethodDecl>(FD);
Diags.Report(Active->PointOfInstantiation,
diag::note_member_synthesized_at)
- << CSM << Context.getTagDeclType(MD->getParent());
+ << MD->isExplicitlyDefaulted() << DFK.asSpecialMember()
+ << Context.getTagDeclType(MD->getParent());
+ } else if (DFK.isComparison()) {
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_comparison_synthesized_at)
+ << (int)DFK.asComparison()
+ << Context.getTagDeclType(
+ cast<CXXRecordDecl>(FD->getLexicalDeclContext()));
}
break;
}
@@ -691,29 +725,43 @@ void Sema::PrintInstantiationStack() {
case CodeSynthesisContext::Memoization:
break;
- case CodeSynthesisContext::ConstraintsCheck:
- if (auto *CD = dyn_cast<ConceptDecl>(Active->Entity)) {
- SmallVector<char, 128> TemplateArgsStr;
- llvm::raw_svector_ostream OS(TemplateArgsStr);
- CD->printName(OS);
- printTemplateArgumentList(OS, Active->template_arguments(),
- getPrintingPolicy());
- Diags.Report(Active->PointOfInstantiation,
- diag::note_concept_specialization_here)
- << OS.str()
- << Active->InstantiationRange;
- break;
+ case CodeSynthesisContext::ConstraintsCheck: {
+ unsigned DiagID = 0;
+ if (isa<ConceptDecl>(Active->Entity))
+ DiagID = diag::note_concept_specialization_here;
+ else if (isa<TemplateDecl>(Active->Entity))
+ DiagID = diag::note_checking_constraints_for_template_id_here;
+ else if (isa<VarTemplatePartialSpecializationDecl>(Active->Entity))
+ DiagID = diag::note_checking_constraints_for_var_spec_id_here;
+ else {
+ assert(isa<ClassTemplatePartialSpecializationDecl>(Active->Entity));
+ DiagID = diag::note_checking_constraints_for_class_spec_id_here;
}
- // TODO: Concepts - implement this for constrained templates and partial
- // specializations.
- llvm_unreachable("only concept constraints are supported right now");
+ SmallVector<char, 128> TemplateArgsStr;
+ llvm::raw_svector_ostream OS(TemplateArgsStr);
+ cast<NamedDecl>(Active->Entity)->printName(OS);
+ printTemplateArgumentList(OS, Active->template_arguments(),
+ getPrintingPolicy());
+ Diags.Report(Active->PointOfInstantiation, DiagID) << OS.str()
+ << Active->InstantiationRange;
break;
-
+ }
case CodeSynthesisContext::ConstraintSubstitution:
Diags.Report(Active->PointOfInstantiation,
diag::note_constraint_substitution_here)
<< Active->InstantiationRange;
break;
+ case CodeSynthesisContext::ConstraintNormalization:
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_constraint_normalization_here)
+ << cast<NamedDecl>(Active->Entity)->getName()
+ << Active->InstantiationRange;
+ break;
+ case CodeSynthesisContext::ParameterMappingSubstitution:
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_parameter_mapping_substitution_here)
+ << Active->InstantiationRange;
+ break;
}
}
}
@@ -738,6 +786,8 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
case CodeSynthesisContext::DefaultFunctionArgumentInstantiation:
case CodeSynthesisContext::ExceptionSpecInstantiation:
case CodeSynthesisContext::ConstraintsCheck:
+ case CodeSynthesisContext::ParameterMappingSubstitution:
+ case CodeSynthesisContext::ConstraintNormalization:
// This is a template instantiation, so there is no SFINAE.
return None;
@@ -759,6 +809,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
return Active->DeductionInfo;
case CodeSynthesisContext::DeclaringSpecialMember:
+ case CodeSynthesisContext::DeclaringImplicitEqualityComparison:
case CodeSynthesisContext::DefiningSynthesizedFunction:
case CodeSynthesisContext::RewritingOperatorAsSpaceship:
// This happens in a context unrelated to template instantiation, so
@@ -1514,8 +1565,12 @@ TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm,
int indexAdjustment,
Optional<unsigned> NumExpansions,
bool ExpectParameterPack) {
- return SemaRef.SubstParmVarDecl(OldParm, TemplateArgs, indexAdjustment,
- NumExpansions, ExpectParameterPack);
+ auto NewParm =
+ SemaRef.SubstParmVarDecl(OldParm, TemplateArgs, indexAdjustment,
+ NumExpansions, ExpectParameterPack);
+ if (NewParm && SemaRef.getLangOpts().OpenCL)
+ SemaRef.deduceOpenCLAddressSpace(NewParm);
+ return NewParm;
}
QualType
@@ -2219,11 +2274,13 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// Finish checking fields.
ActOnFields(nullptr, Instantiation->getLocation(), Instantiation, Fields,
SourceLocation(), SourceLocation(), ParsedAttributesView());
- CheckCompletedCXXClass(Instantiation);
+ CheckCompletedCXXClass(nullptr, Instantiation);
// Default arguments are parsed, if not instantiated. We can go instantiate
- // default arg exprs for default constructors if necessary now.
- ActOnFinishCXXNonNestedClass(Instantiation);
+ // default arg exprs for default constructors if necessary now. Unless we're
+ // parsing a class, in which case wait until that's finished.
+ if (ParsingClassDepth == 0)
+ ActOnFinishCXXNonNestedClass();
// Instantiate late parsed attributes, and attach them to their decls.
// See Sema::InstantiateAttrs
@@ -2900,6 +2957,17 @@ Sema::SubstStmt(Stmt *S, const MultiLevelTemplateArgumentList &TemplateArgs) {
return Instantiator.TransformStmt(S);
}
+bool Sema::SubstTemplateArguments(
+ ArrayRef<TemplateArgumentLoc> Args,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ TemplateArgumentListInfo &Out) {
+ TemplateInstantiator Instantiator(*this, TemplateArgs,
+ SourceLocation(),
+ DeclarationName());
+ return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(),
+ Out);
+}
+
ExprResult
Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) {
if (!E)
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index d1ad304e62e4..64500d0a26d5 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -385,12 +385,13 @@ static void instantiateOMPDeclareVariantAttr(
};
ExprResult VariantFuncRef;
- if (Expr *E = Attr.getVariantFuncRef())
+ if (Expr *E = Attr.getVariantFuncRef()) {
+ // Do not mark function as is used to prevent its emission if this is the
+ // only place where it is used.
+ EnterExpressionEvaluationContext Unevaluated(
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
VariantFuncRef = Subst(E);
-
- ExprResult Score;
- if (Expr *E = Attr.getScore())
- Score = Subst(E);
+ }
// Check function/variant ref.
Optional<std::pair<FunctionDecl *, Expr *>> DeclVarData =
@@ -398,12 +399,41 @@ static void instantiateOMPDeclareVariantAttr(
S.ConvertDeclToDeclGroup(New), VariantFuncRef.get(), Attr.getRange());
if (!DeclVarData)
return;
- // Instantiate the attribute.
- Sema::OpenMPDeclareVariantCtsSelectorData Data(
- Attr.getCtxSelectorSet(), Attr.getCtxSelector(),
- llvm::makeMutableArrayRef(Attr.implVendors_begin(),
- Attr.implVendors_size()),
- Score);
+ SmallVector<Sema::OMPCtxSelectorData, 4> Data;
+ for (unsigned I = 0, E = Attr.scores_size(); I < E; ++I) {
+ ExprResult Score;
+ if (Expr *E = *std::next(Attr.scores_begin(), I))
+ Score = Subst(E);
+ // Instantiate the attribute.
+ auto CtxSet = static_cast<OpenMPContextSelectorSetKind>(
+ *std::next(Attr.ctxSelectorSets_begin(), I));
+ auto Ctx = static_cast<OpenMPContextSelectorKind>(
+ *std::next(Attr.ctxSelectors_begin(), I));
+ switch (CtxSet) {
+ case OMP_CTX_SET_implementation:
+ switch (Ctx) {
+ case OMP_CTX_vendor:
+ Data.emplace_back(CtxSet, Ctx, Score, Attr.implVendors());
+ break;
+ case OMP_CTX_kind:
+ case OMP_CTX_unknown:
+ llvm_unreachable("Unexpected context selector kind.");
+ }
+ break;
+ case OMP_CTX_SET_device:
+ switch (Ctx) {
+ case OMP_CTX_kind:
+ Data.emplace_back(CtxSet, Ctx, Score, Attr.deviceKinds());
+ break;
+ case OMP_CTX_vendor:
+ case OMP_CTX_unknown:
+ llvm_unreachable("Unexpected context selector kind.");
+ }
+ break;
+ case OMP_CTX_SET_unknown:
+ llvm_unreachable("Unexpected context selector set kind.");
+ }
+ }
S.ActOnOpenMPDeclareVariantDirective(DeclVarData.getValue().first,
DeclVarData.getValue().second,
Attr.getRange(), Data);
@@ -625,11 +655,10 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
LateAttrs->push_back(LateInstantiatedAttribute(TmplAttr, Saved, New));
} else {
// Allow 'this' within late-parsed attributes.
- NamedDecl *ND = dyn_cast<NamedDecl>(New);
- CXXRecordDecl *ThisContext =
- dyn_cast_or_null<CXXRecordDecl>(ND->getDeclContext());
+ auto *ND = cast<NamedDecl>(New);
+ auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(ND->getDeclContext());
CXXThisScopeRAII ThisScope(*this, ThisContext, Qualifiers(),
- ND && ND->isCXXInstanceMember());
+ ND->isCXXInstanceMember());
Attr *NewAttr = sema::instantiateTemplateAttribute(TmplAttr, Context,
*this, TemplateArgs);
@@ -905,6 +934,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,
SemaRef.inferObjCARCLifetime(Var))
Var->setInvalidDecl();
+ if (SemaRef.getLangOpts().OpenCL)
+ SemaRef.deduceOpenCLAddressSpace(Var);
+
// Substitute the nested name specifier, if any.
if (SubstQualifier(D, Var))
return nullptr;
@@ -1761,8 +1793,9 @@ static QualType adjustFunctionTypeForInstantiation(ASTContext &Context,
/// 1) instantiating function templates
/// 2) substituting friend declarations
/// 3) substituting deduction guide declarations for nested class templates
-Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
- TemplateParameterList *TemplateParams) {
+Decl *TemplateDeclInstantiator::VisitFunctionDecl(
+ FunctionDecl *D, TemplateParameterList *TemplateParams,
+ RewriteKind FunctionRewriteKind) {
// Check whether there is already a function template specialization for
// this declaration.
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
@@ -1812,6 +1845,18 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
return nullptr;
}
+ // FIXME: Concepts: Do not substitute into constraint expressions
+ Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
+ if (TrailingRequiresClause) {
+ 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
// context.
@@ -1832,6 +1877,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
DeclarationNameInfo NameInfo
= SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
+ if (FunctionRewriteKind != RewriteKind::None)
+ adjustForRewrite(FunctionRewriteKind, D, T, TInfo, NameInfo);
+
FunctionDecl *Function;
if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D)) {
Function = CXXDeductionGuideDecl::Create(
@@ -1845,7 +1893,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
Function = FunctionDecl::Create(
SemaRef.Context, DC, D->getInnerLocStart(), NameInfo, T, TInfo,
D->getCanonicalDecl()->getStorageClass(), D->isInlineSpecified(),
- D->hasWrittenPrototype(), D->getConstexprKind());
+ D->hasWrittenPrototype(), D->getConstexprKind(),
+ TrailingRequiresClause);
Function->setRangeEnd(D->getSourceRange().getEnd());
}
@@ -1872,6 +1921,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
Params[P]->setOwningFunction(Function);
Function->setParams(Params);
+ if (TrailingRequiresClause)
+ Function->setTrailingRequiresClause(TrailingRequiresClause);
+
if (TemplateParams) {
// Our resulting instantiation is actually a function template, since we
// are substituting only the outer template parameters. For example, given
@@ -2049,6 +2101,13 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
}
}
+ if (D->isExplicitlyDefaulted()) {
+ if (SubstDefaultedFunction(Function, D))
+ return nullptr;
+ }
+ if (D->isDeleted())
+ SemaRef.SetDeclDeleted(Function, D->getLocation());
+
if (Function->isLocalExternDecl() && !Function->getPreviousDecl())
DC->makeDeclVisibleInContext(PrincipalDecl);
@@ -2056,14 +2115,13 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary))
PrincipalDecl->setNonMemberOperator();
- assert(!D->isDefaulted() && "only methods should be defaulted");
return Function;
}
Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
CXXMethodDecl *D, TemplateParameterList *TemplateParams,
- Optional<const ASTTemplateArgumentListInfo *>
- ClassScopeSpecializationArgs) {
+ Optional<const ASTTemplateArgumentListInfo *> ClassScopeSpecializationArgs,
+ RewriteKind FunctionRewriteKind) {
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
if (FunctionTemplate && !TemplateParams) {
// We are creating a function template specialization from a function
@@ -2125,6 +2183,18 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
return nullptr;
}
+ // FIXME: Concepts: Do not substitute into constraint expressions
+ Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
+ if (TrailingRequiresClause) {
+ 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) {
@@ -2142,34 +2212,42 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
if (!DC) return nullptr;
}
+ DeclarationNameInfo NameInfo
+ = SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
+
+ if (FunctionRewriteKind != RewriteKind::None)
+ adjustForRewrite(FunctionRewriteKind, D, T, TInfo, NameInfo);
+
// Build the instantiated method declaration.
CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
CXXMethodDecl *Method = nullptr;
SourceLocation StartLoc = D->getInnerLocStart();
- DeclarationNameInfo NameInfo
- = SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
Method = CXXConstructorDecl::Create(
SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
InstantiatedExplicitSpecifier, Constructor->isInlineSpecified(), false,
- Constructor->getConstexprKind());
+ Constructor->getConstexprKind(), InheritedConstructor(),
+ TrailingRequiresClause);
Method->setRangeEnd(Constructor->getEndLoc());
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
Method = CXXDestructorDecl::Create(
SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
- Destructor->isInlineSpecified(), false, Destructor->getConstexprKind());
+ Destructor->isInlineSpecified(), false, Destructor->getConstexprKind(),
+ TrailingRequiresClause);
Method->setRangeEnd(Destructor->getEndLoc());
} else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
Method = CXXConversionDecl::Create(
SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
Conversion->isInlineSpecified(), InstantiatedExplicitSpecifier,
- Conversion->getConstexprKind(), Conversion->getEndLoc());
+ Conversion->getConstexprKind(), Conversion->getEndLoc(),
+ TrailingRequiresClause);
} else {
StorageClass SC = D->isStatic() ? SC_Static : SC_None;
Method = CXXMethodDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo,
T, TInfo, SC, D->isInlineSpecified(),
- D->getConstexprKind(), D->getEndLoc());
+ D->getConstexprKind(), D->getEndLoc(),
+ TrailingRequiresClause);
}
if (D->isInlined())
@@ -2325,8 +2403,10 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
SemaRef.CheckOverrideControl(Method);
// If a function is defined as defaulted or deleted, mark it as such now.
- if (D->isExplicitlyDefaulted())
- SemaRef.SetDeclDefaulted(Method, Method->getLocation());
+ if (D->isExplicitlyDefaulted()) {
+ if (SubstDefaultedFunction(Method, D))
+ return nullptr;
+ }
if (D->isDeletedAsWritten())
SemaRef.SetDeclDeleted(Method, Method->getLocation());
@@ -2399,13 +2479,68 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
// TODO: don't always clone when decls are refcounted.
assert(D->getTypeForDecl()->isTemplateTypeParmType());
+ Optional<unsigned> NumExpanded;
+
+ if (const TypeConstraint *TC = D->getTypeConstraint()) {
+ if (D->isPackExpansion() && !D->isExpandedParameterPack()) {
+ assert(TC->getTemplateArgsAsWritten() &&
+ "type parameter can only be an expansion when explicit arguments "
+ "are specified");
+ // The template type parameter pack's type is a pack expansion of types.
+ // Determine whether we need to expand this parameter pack into separate
+ // types.
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ for (auto &ArgLoc : TC->getTemplateArgsAsWritten()->arguments())
+ SemaRef.collectUnexpandedParameterPacks(ArgLoc, Unexpanded);
+
+ // Determine whether the set of unexpanded parameter packs can and should
+ // be expanded.
+ bool Expand = true;
+ bool RetainExpansion = false;
+ if (SemaRef.CheckParameterPacksForExpansion(
+ cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
+ ->getEllipsisLoc(),
+ SourceRange(TC->getConceptNameLoc(),
+ TC->hasExplicitTemplateArgs() ?
+ TC->getTemplateArgsAsWritten()->getRAngleLoc() :
+ TC->getConceptNameInfo().getEndLoc()),
+ Unexpanded, TemplateArgs, Expand, RetainExpansion, NumExpanded))
+ return nullptr;
+ }
+ }
+
TemplateTypeParmDecl *Inst = TemplateTypeParmDecl::Create(
SemaRef.Context, Owner, D->getBeginLoc(), D->getLocation(),
D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), D->getIndex(),
- D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack());
+ D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack(),
+ D->hasTypeConstraint(), NumExpanded);
+
Inst->setAccess(AS_public);
Inst->setImplicit(D->isImplicit());
+ if (auto *TC = D->getTypeConstraint()) {
+ // TODO: Concepts: do not instantiate the constraint (delayed constraint
+ // substitution)
+ const ASTTemplateArgumentListInfo *TemplArgInfo
+ = TC->getTemplateArgsAsWritten();
+ TemplateArgumentListInfo InstArgs;
+ if (TemplArgInfo) {
+ InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc);
+ InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc);
+ if (SemaRef.Subst(TemplArgInfo->getTemplateArgs(),
+ TemplArgInfo->NumTemplateArgs,
+ InstArgs, TemplateArgs))
+ return nullptr;
+ }
+ if (SemaRef.AttachTypeConstraint(
+ TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(),
+ TC->getNamedConcept(), &InstArgs, Inst,
+ D->isParameterPack()
+ ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
+ ->getEllipsisLoc()
+ : SourceLocation()))
+ return nullptr;
+ }
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
TypeSourceInfo *InstantiatedDefaultArg =
SemaRef.SubstType(D->getDefaultArgumentInfo(), TemplateArgs,
@@ -3040,7 +3175,9 @@ Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl(
}
if (SubstReductionType.isNull())
return nullptr;
- bool IsCorrect = !SubstReductionType.isNull();
+ Expr *Combiner = D->getCombiner();
+ Expr *Init = D->getInitializer();
+ bool IsCorrect = true;
// Create instantiated copy.
std::pair<QualType, SourceLocation> ReductionTypes[] = {
std::make_pair(SubstReductionType, D->getLocation())};
@@ -3055,23 +3192,10 @@ Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl(
PrevDeclInScope);
auto *NewDRD = cast<OMPDeclareReductionDecl>(DRD.get().getSingleDecl());
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewDRD);
- if (!RequiresInstantiation) {
- if (Expr *Combiner = D->getCombiner()) {
- NewDRD->setCombinerData(D->getCombinerIn(), D->getCombinerOut());
- NewDRD->setCombiner(Combiner);
- if (Expr *Init = D->getInitializer()) {
- NewDRD->setInitializerData(D->getInitOrig(), D->getInitPriv());
- NewDRD->setInitializer(Init, D->getInitializerKind());
- }
- }
- (void)SemaRef.ActOnOpenMPDeclareReductionDirectiveEnd(
- /*S=*/nullptr, DRD, IsCorrect && !D->isInvalidDecl());
- return NewDRD;
- }
Expr *SubstCombiner = nullptr;
Expr *SubstInitializer = nullptr;
// Combiners instantiation sequence.
- if (D->getCombiner()) {
+ if (Combiner) {
SemaRef.ActOnOpenMPDeclareReductionCombinerStart(
/*S=*/nullptr, NewDRD);
SemaRef.CurrentInstantiationScope->InstantiatedLocal(
@@ -3083,41 +3207,41 @@ Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl(
auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(Owner);
Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, Qualifiers(),
ThisContext);
- SubstCombiner = SemaRef.SubstExpr(D->getCombiner(), TemplateArgs).get();
+ SubstCombiner = SemaRef.SubstExpr(Combiner, TemplateArgs).get();
SemaRef.ActOnOpenMPDeclareReductionCombinerEnd(NewDRD, SubstCombiner);
- // Initializers instantiation sequence.
- if (D->getInitializer()) {
- VarDecl *OmpPrivParm =
- SemaRef.ActOnOpenMPDeclareReductionInitializerStart(
- /*S=*/nullptr, NewDRD);
- SemaRef.CurrentInstantiationScope->InstantiatedLocal(
- cast<DeclRefExpr>(D->getInitOrig())->getDecl(),
- cast<DeclRefExpr>(NewDRD->getInitOrig())->getDecl());
- SemaRef.CurrentInstantiationScope->InstantiatedLocal(
- cast<DeclRefExpr>(D->getInitPriv())->getDecl(),
- cast<DeclRefExpr>(NewDRD->getInitPriv())->getDecl());
- if (D->getInitializerKind() == OMPDeclareReductionDecl::CallInit) {
- SubstInitializer =
- SemaRef.SubstExpr(D->getInitializer(), TemplateArgs).get();
- } else {
- IsCorrect = IsCorrect && OmpPrivParm->hasInit();
- }
- SemaRef.ActOnOpenMPDeclareReductionInitializerEnd(
- NewDRD, SubstInitializer, OmpPrivParm);
+ }
+ // Initializers instantiation sequence.
+ if (Init) {
+ VarDecl *OmpPrivParm = SemaRef.ActOnOpenMPDeclareReductionInitializerStart(
+ /*S=*/nullptr, NewDRD);
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(
+ cast<DeclRefExpr>(D->getInitOrig())->getDecl(),
+ cast<DeclRefExpr>(NewDRD->getInitOrig())->getDecl());
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(
+ cast<DeclRefExpr>(D->getInitPriv())->getDecl(),
+ cast<DeclRefExpr>(NewDRD->getInitPriv())->getDecl());
+ if (D->getInitializerKind() == OMPDeclareReductionDecl::CallInit) {
+ SubstInitializer = SemaRef.SubstExpr(Init, TemplateArgs).get();
+ } else {
+ auto *OldPrivParm =
+ cast<VarDecl>(cast<DeclRefExpr>(D->getInitPriv())->getDecl());
+ IsCorrect = IsCorrect && OldPrivParm->hasInit();
+ if (IsCorrect)
+ SemaRef.InstantiateVariableInitializer(OmpPrivParm, OldPrivParm,
+ TemplateArgs);
}
- IsCorrect =
- IsCorrect && SubstCombiner &&
- (!D->getInitializer() ||
- (D->getInitializerKind() == OMPDeclareReductionDecl::CallInit &&
- SubstInitializer) ||
- (D->getInitializerKind() != OMPDeclareReductionDecl::CallInit &&
- !SubstInitializer && !SubstInitializer));
- } else {
- IsCorrect = false;
+ SemaRef.ActOnOpenMPDeclareReductionInitializerEnd(NewDRD, SubstInitializer,
+ OmpPrivParm);
}
+ IsCorrect = IsCorrect && SubstCombiner &&
+ (!Init ||
+ (D->getInitializerKind() == OMPDeclareReductionDecl::CallInit &&
+ SubstInitializer) ||
+ (D->getInitializerKind() != OMPDeclareReductionDecl::CallInit &&
+ !SubstInitializer));
- (void)SemaRef.ActOnOpenMPDeclareReductionDirectiveEnd(/*S=*/nullptr, DRD,
- IsCorrect);
+ (void)SemaRef.ActOnOpenMPDeclareReductionDirectiveEnd(
+ /*S=*/nullptr, DRD, IsCorrect && !D->isInvalidDecl());
return NewDRD;
}
@@ -3163,7 +3287,8 @@ TemplateDeclInstantiator::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) {
} else {
// Instantiate the mapper variable.
DeclarationNameInfo DirName;
- SemaRef.StartOpenMPDSABlock(OMPD_declare_mapper, DirName, /*S=*/nullptr,
+ SemaRef.StartOpenMPDSABlock(llvm::omp::OMPD_declare_mapper, DirName,
+ /*S=*/nullptr,
(*D->clauselist_begin())->getBeginLoc());
SemaRef.ActOnOpenMPDeclareMapperDirectiveVarDecl(
NewDMD, /*S=*/nullptr, SubstMapperTy, D->getLocation(), VN);
@@ -3275,7 +3400,8 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
D->getLocation(),
InstTemplateArgs,
false,
- Converted))
+ Converted,
+ /*UpdateArgsWithConversion=*/true))
return nullptr;
// Figure out where to insert this class template explicit specialization
@@ -3396,7 +3522,8 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
// Check that the template argument list is well-formed for this template.
SmallVector<TemplateArgument, 4> Converted;
if (SemaRef.CheckTemplateArgumentList(InstVarTemplate, D->getLocation(),
- VarTemplateArgsInfo, false, Converted))
+ VarTemplateArgsInfo, false, Converted,
+ /*UpdateArgsWithConversion=*/true))
return nullptr;
// Check whether we've already seen a declaration of this specialization.
@@ -3490,6 +3617,73 @@ Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner,
return SubstD;
}
+void TemplateDeclInstantiator::adjustForRewrite(RewriteKind RK,
+ FunctionDecl *Orig, QualType &T,
+ TypeSourceInfo *&TInfo,
+ DeclarationNameInfo &NameInfo) {
+ assert(RK == RewriteKind::RewriteSpaceshipAsEqualEqual);
+
+ // C++2a [class.compare.default]p3:
+ // the return type is replaced with bool
+ auto *FPT = T->castAs<FunctionProtoType>();
+ T = SemaRef.Context.getFunctionType(
+ SemaRef.Context.BoolTy, FPT->getParamTypes(), FPT->getExtProtoInfo());
+
+ // Update the return type in the source info too. The most straightforward
+ // way is to create new TypeSourceInfo for the new type. Use the location of
+ // the '= default' as the location of the new type.
+ //
+ // FIXME: Set the correct return type when we initially transform the type,
+ // rather than delaying it to now.
+ TypeSourceInfo *NewTInfo =
+ SemaRef.Context.getTrivialTypeSourceInfo(T, Orig->getEndLoc());
+ auto OldLoc = TInfo->getTypeLoc().getAsAdjusted<FunctionProtoTypeLoc>();
+ assert(OldLoc && "type of function is not a function type?");
+ auto NewLoc = NewTInfo->getTypeLoc().castAs<FunctionProtoTypeLoc>();
+ for (unsigned I = 0, N = OldLoc.getNumParams(); I != N; ++I)
+ NewLoc.setParam(I, OldLoc.getParam(I));
+ TInfo = NewTInfo;
+
+ // and the declarator-id is replaced with operator==
+ NameInfo.setName(
+ SemaRef.Context.DeclarationNames.getCXXOperatorName(OO_EqualEqual));
+}
+
+FunctionDecl *Sema::SubstSpaceshipAsEqualEqual(CXXRecordDecl *RD,
+ FunctionDecl *Spaceship) {
+ if (Spaceship->isInvalidDecl())
+ return nullptr;
+
+ // C++2a [class.compare.default]p3:
+ // an == operator function is declared implicitly [...] with the same
+ // access and function-definition and in the same class scope as the
+ // three-way comparison operator function
+ MultiLevelTemplateArgumentList NoTemplateArgs;
+ TemplateDeclInstantiator Instantiator(*this, RD, NoTemplateArgs);
+ Decl *R;
+ if (auto *MD = dyn_cast<CXXMethodDecl>(Spaceship)) {
+ R = Instantiator.VisitCXXMethodDecl(
+ MD, nullptr, None,
+ TemplateDeclInstantiator::RewriteKind::RewriteSpaceshipAsEqualEqual);
+ } else {
+ assert(Spaceship->getFriendObjectKind() &&
+ "defaulted spaceship is neither a member nor a friend");
+
+ R = Instantiator.VisitFunctionDecl(
+ Spaceship, nullptr,
+ TemplateDeclInstantiator::RewriteKind::RewriteSpaceshipAsEqualEqual);
+ if (!R)
+ return nullptr;
+
+ FriendDecl *FD =
+ FriendDecl::Create(Context, RD, Spaceship->getLocation(),
+ cast<NamedDecl>(R), Spaceship->getBeginLoc());
+ FD->setAccess(AS_public);
+ RD->addDecl(FD);
+ }
+ return cast_or_null<FunctionDecl>(R);
+}
+
/// Instantiates a nested template parameter list in the current
/// instantiation context.
///
@@ -3598,7 +3792,8 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
// in the member template's set of class template partial specializations.
void *InsertPos = nullptr;
ClassTemplateSpecializationDecl *PrevDecl
- = ClassTemplate->findPartialSpecialization(Converted, InsertPos);
+ = ClassTemplate->findPartialSpecialization(Converted, InstParams,
+ InsertPos);
// Build the canonical type that describes the converted template
// arguments of the class template partial specialization.
@@ -3722,7 +3917,7 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
// in the member template's set of variable template partial specializations.
void *InsertPos = nullptr;
VarTemplateSpecializationDecl *PrevDecl =
- VarTemplate->findPartialSpecialization(Converted, InsertPos);
+ VarTemplate->findPartialSpecialization(Converted, InstParams, InsertPos);
// Build the canonical type that describes the converted template
// arguments of the variable template partial specialization.
@@ -4009,6 +4204,48 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
TemplateArgs);
}
+bool Sema::CheckInstantiatedFunctionTemplateConstraints(
+ SourceLocation PointOfInstantiation, FunctionDecl *Decl,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ ConstraintSatisfaction &Satisfaction) {
+ // In most cases we're not going to have constraints, so check for that first.
+ FunctionTemplateDecl *Template = Decl->getPrimaryTemplate();
+ // Note - code synthesis context for the constraints check is created
+ // inside CheckConstraintsSatisfaction.
+ SmallVector<const Expr *, 3> TemplateAC;
+ Template->getAssociatedConstraints(TemplateAC);
+ if (TemplateAC.empty()) {
+ Satisfaction.IsSatisfied = true;
+ return false;
+ }
+
+ // Enter the scope of this instantiation. We don't use
+ // PushDeclContext because we don't have a scope.
+ Sema::ContextRAII savedContext(*this, Decl);
+ LocalInstantiationScope Scope(*this);
+
+ MultiLevelTemplateArgumentList MLTAL =
+ getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true);
+
+ // 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(),
+ MLTAL.getInnermost(), SourceRange());
+ if (Inst.isInvalid())
+ return true;
+ if (addInstantiatedParametersToScope(*this, Decl,
+ Decl->getTemplateInstantiationPattern(),
+ Scope, MLTAL))
+ return true;
+ }
+
+ return CheckConstraintSatisfaction(Template, TemplateAC, TemplateArgs,
+ PointOfInstantiation, Satisfaction);
+}
+
/// Initializes the common fields of an instantiation function
/// declaration (New) from the corresponding fields of its template (Tmpl).
///
@@ -4016,9 +4253,6 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
bool
TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
FunctionDecl *Tmpl) {
- if (Tmpl->isDeleted())
- New->setDeletedAsWritten();
-
New->setImplicit(Tmpl->isImplicit());
// Forward the mangling number from the template to the instantiated decl.
@@ -4119,6 +4353,34 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
return false;
}
+bool TemplateDeclInstantiator::SubstDefaultedFunction(FunctionDecl *New,
+ FunctionDecl *Tmpl) {
+ // Transfer across any unqualified lookups.
+ if (auto *DFI = Tmpl->getDefaultedFunctionInfo()) {
+ SmallVector<DeclAccessPair, 32> Lookups;
+ Lookups.reserve(DFI->getUnqualifiedLookups().size());
+ bool AnyChanged = false;
+ for (DeclAccessPair DA : DFI->getUnqualifiedLookups()) {
+ NamedDecl *D = SemaRef.FindInstantiatedDecl(New->getLocation(),
+ DA.getDecl(), TemplateArgs);
+ if (!D)
+ return true;
+ AnyChanged |= (D != DA.getDecl());
+ Lookups.push_back(DeclAccessPair::make(D, DA.getAccess()));
+ }
+
+ // It's unlikely that substitution will change any declarations. Don't
+ // store an unnecessary copy in that case.
+ New->setDefaultedFunctionInfo(
+ AnyChanged ? FunctionDecl::DefaultedFunctionInfo::Create(
+ SemaRef.Context, Lookups)
+ : DFI);
+ }
+
+ SemaRef.SetDeclDefaulted(New, Tmpl->getLocation());
+ return false;
+}
+
/// Instantiate (or find existing instantiation of) a function template with a
/// given set of template arguments.
///
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index 975d6620c06f..d947d6d282be 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -937,6 +937,10 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
}
}
+ if (Expr *TRC = D.getTrailingRequiresClause())
+ if (TRC->containsUnexpandedParameterPack())
+ return true;
+
return false;
}
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index fccdb2bc2e2c..3884fdae8fe7 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -1976,6 +1976,19 @@ bool Sema::CheckQualifiedFunctionForTypeId(QualType T, SourceLocation Loc) {
return true;
}
+// Helper to deduce addr space of a pointee type in OpenCL mode.
+static QualType deduceOpenCLPointeeAddrSpace(Sema &S, QualType PointeeType) {
+ if (!PointeeType->isUndeducedAutoType() && !PointeeType->isDependentType() &&
+ !PointeeType->isSamplerT() &&
+ !PointeeType.hasAddressSpace())
+ PointeeType = S.getASTContext().getAddrSpaceQualType(
+ PointeeType,
+ S.getLangOpts().OpenCLCPlusPlus || S.getLangOpts().OpenCLVersion == 200
+ ? LangAS::opencl_generic
+ : LangAS::opencl_private);
+ return PointeeType;
+}
+
/// Build a pointer type.
///
/// \param T The type to which we'll be building a pointer.
@@ -2012,6 +2025,9 @@ QualType Sema::BuildPointerType(QualType T,
if (getLangOpts().ObjCAutoRefCount)
T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ false);
+ if (getLangOpts().OpenCL)
+ T = deduceOpenCLPointeeAddrSpace(*this, T);
+
// Build the pointer type.
return Context.getPointerType(T);
}
@@ -2072,6 +2088,9 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
if (getLangOpts().ObjCAutoRefCount)
T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ true);
+ if (getLangOpts().OpenCL)
+ T = deduceOpenCLPointeeAddrSpace(*this, T);
+
// Handle restrict on references.
if (LValueRef)
return Context.getLValueReferenceType(T, SpelledAsLValue);
@@ -2655,6 +2674,9 @@ QualType Sema::BuildBlockPointerType(QualType T,
if (checkQualifiedFunction(*this, T, Loc, QFK_BlockPointer))
return QualType();
+ if (getLangOpts().OpenCL)
+ T = deduceOpenCLPointeeAddrSpace(*this, T);
+
return Context.getBlockPointerType(T);
}
@@ -2994,7 +3016,8 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
SemaRef.Context, SemaRef.Context.getTranslationUnitDecl(),
/*KeyLoc*/ SourceLocation(), /*NameLoc*/ D.getBeginLoc(),
TemplateParameterDepth, AutoParameterPosition,
- /*Identifier*/ nullptr, false, IsParameterPack);
+ /*Identifier*/ nullptr, false, IsParameterPack,
+ /*HasTypeConstraint=*/false);
CorrespondingTemplateParam->setImplicit();
LSI->TemplateParams.push_back(CorrespondingTemplateParam);
// Replace the 'auto' in the function parameter with this invented
@@ -3139,7 +3162,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
T = SemaRef.Context.IntTy;
D.setInvalidType(true);
- } else if (!HaveTrailing &&
+ } else if (Auto && !HaveTrailing &&
D.getContext() != DeclaratorContext::LambdaExprContext) {
// If there was a trailing return type, we already got
// warn_cxx98_compat_trailing_return_type in the parser.
@@ -4788,6 +4811,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExtInfo = EI;
EPI.Variadic = FTI.isVariadic;
+ EPI.EllipsisLoc = FTI.getEllipsisLoc();
EPI.HasTrailingReturn = FTI.hasTrailingReturnType();
EPI.TypeQuals.addCVRUQualifiers(
FTI.MethodQualifiers ? FTI.MethodQualifiers->getTypeQualifiers()
@@ -4927,7 +4951,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
.getScopeRep()
->getKind() == NestedNameSpecifier::TypeSpec) ||
state.getDeclarator().getContext() ==
- DeclaratorContext::MemberContext;
+ DeclaratorContext::MemberContext ||
+ state.getDeclarator().getContext() ==
+ DeclaratorContext::LambdaExprContext;
};
if (state.getSema().getLangOpts().OpenCLCPlusPlus && IsClassMember()) {
@@ -4946,7 +4972,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// If a class member function's address space is not set, set it to
// __generic.
LangAS AS =
- (ASIdx == LangAS::Default ? LangAS::opencl_generic : ASIdx);
+ (ASIdx == LangAS::Default ? S.getDefaultCXXMethodAddrSpace()
+ : ASIdx);
EPI.TypeQuals.addAddressSpace(AS);
}
T = Context.getFunctionType(T, ParamTys, EPI);
@@ -6325,7 +6352,8 @@ namespace {
Pointer,
BlockPointer,
Reference,
- MemberPointer
+ MemberPointer,
+ MacroQualified,
};
QualType Original;
@@ -6356,6 +6384,9 @@ namespace {
} else if (isa<AttributedType>(Ty)) {
T = cast<AttributedType>(Ty)->getEquivalentType();
Stack.push_back(Attributed);
+ } else if (isa<MacroQualifiedType>(Ty)) {
+ T = cast<MacroQualifiedType>(Ty)->getUnderlyingType();
+ Stack.push_back(MacroQualified);
} else {
const Type *DTy = Ty->getUnqualifiedDesugaredType();
if (Ty == DTy) {
@@ -6412,6 +6443,9 @@ namespace {
return C.getParenType(New);
}
+ case MacroQualified:
+ return wrap(C, cast<MacroQualifiedType>(Old)->getUnderlyingType(), I);
+
case Pointer: {
QualType New = wrap(C, cast<PointerType>(Old)->getPointeeType(), I);
return C.getPointerType(New);
@@ -6464,35 +6498,36 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
break;
}
+ llvm::SmallSet<attr::Kind, 2> Attrs;
attr::Kind NewAttrKind = A->getKind();
QualType Desugared = Type;
const AttributedType *AT = dyn_cast<AttributedType>(Type);
while (AT) {
- attr::Kind CurAttrKind = AT->getAttrKind();
-
- // You cannot specify duplicate type attributes, so if the attribute has
- // already been applied, flag it.
- if (NewAttrKind == CurAttrKind) {
- S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact) << PAttr;
- return true;
- }
+ Attrs.insert(AT->getAttrKind());
+ Desugared = AT->getModifiedType();
+ AT = dyn_cast<AttributedType>(Desugared);
+ }
- // You cannot have both __sptr and __uptr on the same type, nor can you
- // have __ptr32 and __ptr64.
- if ((CurAttrKind == attr::Ptr32 && NewAttrKind == attr::Ptr64) ||
- (CurAttrKind == attr::Ptr64 && NewAttrKind == attr::Ptr32)) {
- S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible)
- << "'__ptr32'" << "'__ptr64'";
- return true;
- } else if ((CurAttrKind == attr::SPtr && NewAttrKind == attr::UPtr) ||
- (CurAttrKind == attr::UPtr && NewAttrKind == attr::SPtr)) {
- S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible)
- << "'__sptr'" << "'__uptr'";
- return true;
- }
+ // You cannot specify duplicate type attributes, so if the attribute has
+ // already been applied, flag it.
+ if (Attrs.count(NewAttrKind)) {
+ S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact) << PAttr;
+ return true;
+ }
+ Attrs.insert(NewAttrKind);
- Desugared = AT->getEquivalentType();
- AT = dyn_cast<AttributedType>(Desugared);
+ // You cannot have both __sptr and __uptr on the same type, nor can you
+ // have __ptr32 and __ptr64.
+ if (Attrs.count(attr::Ptr32) && Attrs.count(attr::Ptr64)) {
+ S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible)
+ << "'__ptr32'"
+ << "'__ptr64'";
+ return true;
+ } else if (Attrs.count(attr::SPtr) && Attrs.count(attr::UPtr)) {
+ S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible)
+ << "'__sptr'"
+ << "'__uptr'";
+ return true;
}
// Pointer type qualifiers can only operate on pointer types, but not
@@ -6510,7 +6545,26 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
return true;
}
- Type = State.getAttributedType(A, Type, Type);
+ // Add address space to type based on its attributes.
+ LangAS ASIdx = LangAS::Default;
+ uint64_t PtrWidth = S.Context.getTargetInfo().getPointerWidth(0);
+ if (PtrWidth == 32) {
+ if (Attrs.count(attr::Ptr64))
+ ASIdx = LangAS::ptr64;
+ else if (Attrs.count(attr::UPtr))
+ ASIdx = LangAS::ptr32_uptr;
+ } else if (PtrWidth == 64 && Attrs.count(attr::Ptr32)) {
+ if (Attrs.count(attr::UPtr))
+ ASIdx = LangAS::ptr32_uptr;
+ else
+ ASIdx = LangAS::ptr32_sptr;
+ }
+
+ QualType Pointee = Type->getPointeeType();
+ if (ASIdx != LangAS::Default)
+ Pointee = S.Context.getAddrSpaceQualType(
+ S.Context.removeAddrSpaceQualType(Pointee), ASIdx);
+ Type = State.getAttributedType(A, Type, S.Context.getPointerType(Pointee));
return false;
}
@@ -7215,6 +7269,7 @@ static bool isPermittedNeonBaseType(QualType &Ty,
// Signed poly is mathematically wrong, but has been baked into some ABIs by
// now.
bool IsPolyUnsigned = Triple.getArch() == llvm::Triple::aarch64 ||
+ Triple.getArch() == llvm::Triple::aarch64_32 ||
Triple.getArch() == llvm::Triple::aarch64_be;
if (VecKind == VectorType::NeonPolyVector) {
if (IsPolyUnsigned) {
@@ -7232,10 +7287,8 @@ static bool isPermittedNeonBaseType(QualType &Ty,
// Non-polynomial vector types: the usual suspects are allowed, as well as
// float64_t on AArch64.
- bool Is64Bit = Triple.getArch() == llvm::Triple::aarch64 ||
- Triple.getArch() == llvm::Triple::aarch64_be;
-
- if (Is64Bit && BTy->getKind() == BuiltinType::Double)
+ if ((Triple.isArch64Bit() || Triple.getArch() == llvm::Triple::aarch64_32) &&
+ BTy->getKind() == BuiltinType::Double)
return true;
return BTy->getKind() == BuiltinType::SChar ||
@@ -7261,8 +7314,10 @@ static bool isPermittedNeonBaseType(QualType &Ty,
/// match one of the standard Neon vector types.
static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr,
Sema &S, VectorType::VectorKind VecKind) {
- // Target must have NEON
- if (!S.Context.getTargetInfo().hasFeature("neon")) {
+ // Target must have NEON (or MVE, whose vectors are similar enough
+ // not to need a separate attribute)
+ if (!S.Context.getTargetInfo().hasFeature("neon") &&
+ !S.Context.getTargetInfo().hasFeature("mve")) {
S.Diag(Attr.getLoc(), diag::err_attribute_unsupported) << Attr;
Attr.setInvalid();
return;
@@ -7361,137 +7416,6 @@ static void HandleOpenCLAccessAttr(QualType &CurType, const ParsedAttr &Attr,
}
}
-static void deduceOpenCLImplicitAddrSpace(TypeProcessingState &State,
- QualType &T, TypeAttrLocation TAL) {
- Declarator &D = State.getDeclarator();
-
- // Handle the cases where address space should not be deduced.
- //
- // The pointee type of a pointer type is always deduced since a pointer always
- // points to some memory location which should has an address space.
- //
- // There are situations that at the point of certain declarations, the address
- // space may be unknown and better to be left as default. For example, when
- // defining a typedef or struct type, they are not associated with any
- // specific address space. Later on, they may be used with any address space
- // to declare a variable.
- //
- // The return value of a function is r-value, therefore should not have
- // address space.
- //
- // The void type does not occupy memory, therefore should not have address
- // space, except when it is used as a pointee type.
- //
- // Since LLVM assumes function type is in default address space, it should not
- // have address space.
- auto ChunkIndex = State.getCurrentChunkIndex();
- bool IsPointee =
- ChunkIndex > 0 &&
- (D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Pointer ||
- D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Reference ||
- D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::BlockPointer);
- // For pointers/references to arrays the next chunk is always an array
- // followed by any number of parentheses.
- if (!IsPointee && ChunkIndex > 1) {
- auto AdjustedCI = ChunkIndex - 1;
- if (D.getTypeObject(AdjustedCI).Kind == DeclaratorChunk::Array)
- AdjustedCI--;
- // Skip over all parentheses.
- while (AdjustedCI > 0 &&
- D.getTypeObject(AdjustedCI).Kind == DeclaratorChunk::Paren)
- AdjustedCI--;
- if (D.getTypeObject(AdjustedCI).Kind == DeclaratorChunk::Pointer ||
- D.getTypeObject(AdjustedCI).Kind == DeclaratorChunk::Reference)
- IsPointee = true;
- }
- bool IsFuncReturnType =
- ChunkIndex > 0 &&
- D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Function;
- bool IsFuncType =
- ChunkIndex < D.getNumTypeObjects() &&
- D.getTypeObject(ChunkIndex).Kind == DeclaratorChunk::Function;
- if ( // Do not deduce addr space for function return type and function type,
- // otherwise it will fail some sema check.
- IsFuncReturnType || IsFuncType ||
- // Do not deduce addr space for member types of struct, except the pointee
- // type of a pointer member type or static data members.
- (D.getContext() == DeclaratorContext::MemberContext &&
- (!IsPointee &&
- D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static)) ||
- // Do not deduce addr space of non-pointee in type alias because it
- // doesn't define any object.
- (D.getContext() == DeclaratorContext::AliasDeclContext && !IsPointee) ||
- // Do not deduce addr space for types used to define a typedef and the
- // typedef itself, except the pointee type of a pointer type which is used
- // to define the typedef.
- (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef &&
- !IsPointee) ||
- // Do not deduce addr space of the void type, e.g. in f(void), otherwise
- // it will fail some sema check.
- (T->isVoidType() && !IsPointee) ||
- // Do not deduce addr spaces for dependent types because they might end
- // up instantiating to a type with an explicit address space qualifier.
- // Except for pointer or reference types because the addr space in
- // template argument can only belong to a pointee.
- (T->isDependentType() && !T->isPointerType() && !T->isReferenceType()) ||
- // Do not deduce addr space of decltype because it will be taken from
- // its argument.
- T->isDecltypeType() ||
- // OpenCL spec v2.0 s6.9.b:
- // The sampler type cannot be used with the __local and __global address
- // space qualifiers.
- // OpenCL spec v2.0 s6.13.14:
- // Samplers can also be declared as global constants in the program
- // source using the following syntax.
- // const sampler_t <sampler name> = <value>
- // In codegen, file-scope sampler type variable has special handing and
- // does not rely on address space qualifier. On the other hand, deducing
- // address space of const sampler file-scope variable as global address
- // space causes spurious diagnostic about __global address space
- // qualifier, therefore do not deduce address space of file-scope sampler
- // type variable.
- (D.getContext() == DeclaratorContext::FileContext && T->isSamplerT()))
- return;
-
- LangAS ImpAddr = LangAS::Default;
- // Put OpenCL automatic variable in private address space.
- // OpenCL v1.2 s6.5:
- // The default address space name for arguments to a function in a
- // program, or local variables of a function is __private. All function
- // arguments shall be in the __private address space.
- if (State.getSema().getLangOpts().OpenCLVersion <= 120 &&
- !State.getSema().getLangOpts().OpenCLCPlusPlus) {
- ImpAddr = LangAS::opencl_private;
- } else {
- // If address space is not set, OpenCL 2.0 defines non private default
- // address spaces for some cases:
- // OpenCL 2.0, section 6.5:
- // The address space for a variable at program scope or a static variable
- // inside a function can either be __global or __constant, but defaults to
- // __global if not specified.
- // (...)
- // Pointers that are declared without pointing to a named address space
- // point to the generic address space.
- if (IsPointee) {
- ImpAddr = LangAS::opencl_generic;
- } else {
- if (D.getContext() == DeclaratorContext::TemplateArgContext) {
- // Do not deduce address space for non-pointee type in template arg.
- } else if (D.getContext() == DeclaratorContext::FileContext) {
- ImpAddr = LangAS::opencl_global;
- } else {
- if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static ||
- D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern) {
- ImpAddr = LangAS::opencl_global;
- } else {
- ImpAddr = LangAS::opencl_private;
- }
- }
- }
- }
- T = State.getSema().Context.getAddrSpaceQualType(T, ImpAddr);
-}
-
static void HandleLifetimeBoundAttr(TypeProcessingState &State,
QualType &CurType,
ParsedAttr &Attr) {
@@ -7504,6 +7428,16 @@ static void HandleLifetimeBoundAttr(TypeProcessingState &State,
}
}
+static bool isAddressSpaceKind(const ParsedAttr &attr) {
+ auto attrKind = attr.getKind();
+
+ return attrKind == ParsedAttr::AT_AddressSpace ||
+ attrKind == ParsedAttr::AT_OpenCLPrivateAddressSpace ||
+ attrKind == ParsedAttr::AT_OpenCLGlobalAddressSpace ||
+ attrKind == ParsedAttr::AT_OpenCLLocalAddressSpace ||
+ attrKind == ParsedAttr::AT_OpenCLConstantAddressSpace ||
+ attrKind == ParsedAttr::AT_OpenCLGenericAddressSpace;
+}
static void processTypeAttrs(TypeProcessingState &state, QualType &type,
TypeAttrLocation TAL,
@@ -7542,11 +7476,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
if (!IsTypeAttr)
continue;
}
- } else if (TAL != TAL_DeclChunk &&
- attr.getKind() != ParsedAttr::AT_AddressSpace) {
+ } else if (TAL != TAL_DeclChunk && !isAddressSpaceKind(attr)) {
// Otherwise, only consider type processing for a C++11 attribute if
// it's actually been applied to a type.
- // We also allow C++11 address_space attributes to pass through.
+ // We also allow C++11 address_space and
+ // OpenCL language address space attributes to pass through.
continue;
}
}
@@ -7701,6 +7635,18 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
else if (!handleFunctionTypeAttr(state, attr, type))
distributeFunctionTypeAttr(state, attr, type);
break;
+ case ParsedAttr::AT_AcquireHandle: {
+ if (!type->isFunctionType())
+ return;
+ StringRef HandleType;
+ if (!state.getSema().checkStringLiteralArgumentAttr(attr, 0, HandleType))
+ return;
+ type = state.getAttributedType(
+ AcquireHandleAttr::Create(state.getSema().Context, HandleType, attr),
+ type, type);
+ attr.setUsedAsTypeAttr();
+ break;
+ }
}
// Handle attributes that are defined in a macro. We do not want this to be
@@ -7721,8 +7667,6 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
if (!state.getSema().getLangOpts().OpenCL ||
type.getAddressSpace() != LangAS::Default)
return;
-
- deduceOpenCLImplicitAddrSpace(state, type, TAL);
}
void Sema::completeExprArrayBound(Expr *E) {
@@ -7944,33 +7888,31 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested,
static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) {
RD = RD->getMostRecentNonInjectedDecl();
if (!RD->hasAttr<MSInheritanceAttr>()) {
- MSInheritanceAttr::Spelling IM;
-
+ MSInheritanceModel IM;
+ bool BestCase = false;
switch (S.MSPointerToMemberRepresentationMethod) {
case LangOptions::PPTMK_BestCase:
+ BestCase = true;
IM = RD->calculateInheritanceModel();
break;
case LangOptions::PPTMK_FullGeneralitySingleInheritance:
- IM = MSInheritanceAttr::Keyword_single_inheritance;
+ IM = MSInheritanceModel::Single;
break;
case LangOptions::PPTMK_FullGeneralityMultipleInheritance:
- IM = MSInheritanceAttr::Keyword_multiple_inheritance;
+ IM = MSInheritanceModel::Multiple;
break;
case LangOptions::PPTMK_FullGeneralityVirtualInheritance:
- IM = MSInheritanceAttr::Keyword_unspecified_inheritance;
+ IM = MSInheritanceModel::Unspecified;
break;
}
- SourceRange Loc =
- S.ImplicitMSInheritanceAttrLoc.isValid()
- ? S.ImplicitMSInheritanceAttrLoc
- : RD->getSourceRange();
- RD->addAttr(MSInheritanceAttr::CreateImplicit(
- S.getASTContext(),
- /*BestCase=*/S.MSPointerToMemberRepresentationMethod ==
- LangOptions::PPTMK_BestCase,
- Loc, AttributeCommonInfo::AS_Microsoft, IM));
- S.Consumer.AssignInheritanceModel(RD);
+ SourceRange Loc = S.ImplicitMSInheritanceAttrLoc.isValid()
+ ? S.ImplicitMSInheritanceAttrLoc
+ : RD->getSourceRange();
+ RD->addAttr(MSInheritanceAttr::CreateImplicit(
+ S.getASTContext(), BestCase, Loc, AttributeCommonInfo::AS_Microsoft,
+ MSInheritanceAttr::Spelling(IM)));
+ S.Consumer.AssignInheritanceModel(RD);
}
}
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 4b3a6708717c..3b827fbc950b 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -22,6 +22,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprOpenMP.h"
+#include "clang/AST/OpenMPClause.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
@@ -37,6 +38,8 @@
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
+using namespace llvm::omp;
+
namespace clang {
using namespace sema;
@@ -1613,7 +1616,7 @@ public:
///
/// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
- OMPClause *RebuildOMPProcBindClause(OpenMPProcBindClauseKind Kind,
+ OMPClause *RebuildOMPProcBindClause(ProcBindKind Kind,
SourceLocation KindKwLoc,
SourceLocation StartLoc,
SourceLocation LParenLoc,
@@ -1675,11 +1678,14 @@ public:
/// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
OMPClause *RebuildOMPLastprivateClause(ArrayRef<Expr *> VarList,
+ OpenMPLastprivateModifier LPKind,
+ SourceLocation LPKindLoc,
+ SourceLocation ColonLoc,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
- return getSema().ActOnOpenMPLastprivateClause(VarList, StartLoc, LParenLoc,
- EndLoc);
+ return getSema().ActOnOpenMPLastprivateClause(
+ VarList, LPKind, LPKindLoc, ColonLoc, StartLoc, LParenLoc, EndLoc);
}
/// Build a new OpenMP 'shared' clause.
@@ -1984,6 +1990,33 @@ public:
return getSema().ActOnOpenMPIsDevicePtrClause(VarList, Locs);
}
+ /// Build a new OpenMP 'defaultmap' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPDefaultmapClause(OpenMPDefaultmapClauseModifier M,
+ OpenMPDefaultmapClauseKind Kind,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation MLoc,
+ SourceLocation KindLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPDefaultmapClause(M, Kind, StartLoc, LParenLoc,
+ MLoc, KindLoc, EndLoc);
+ }
+
+ /// Build a new OpenMP 'nontemporal' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPNontemporalClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPNontemporalClause(VarList, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
/// Rebuild the operand to an Objective-C \@synchronized statement.
///
/// By default, performs semantic analysis to build the new statement.
@@ -3031,13 +3064,13 @@ public:
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildConceptSpecializationExpr(NestedNameSpecifierLoc NNS,
- SourceLocation TemplateKWLoc, SourceLocation ConceptNameLoc,
+ SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
TemplateArgumentListInfo *TALI) {
CXXScopeSpec SS;
SS.Adopt(NNS);
ExprResult Result = getSema().CheckConceptTemplateId(SS, TemplateKWLoc,
- ConceptNameLoc,
+ ConceptNameInfo,
FoundDecl,
NamedConcept, TALI);
if (Result.isInvalid())
@@ -3455,7 +3488,7 @@ ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init,
Init = AIL->getCommonExpr();
if (MaterializeTemporaryExpr *MTE = dyn_cast<MaterializeTemporaryExpr>(Init))
- Init = MTE->GetTemporaryExpr();
+ Init = MTE->getSubExpr();
while (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(Init))
Init = Binder->getSubExpr();
@@ -4564,14 +4597,6 @@ QualType TreeTransform<Derived>::TransformDecayedType(TypeLocBuilder &TLB,
return Result;
}
-/// Helper to deduce addr space of a pointee type in OpenCL mode.
-/// If the type is updated it will be overwritten in PointeeType param.
-static void deduceOpenCLPointeeAddrSpace(Sema &SemaRef, QualType &PointeeType) {
- if (PointeeType.getAddressSpace() == LangAS::Default)
- PointeeType = SemaRef.Context.getAddrSpaceQualType(PointeeType,
- LangAS::opencl_generic);
-}
-
template<typename Derived>
QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB,
PointerTypeLoc TL) {
@@ -4580,9 +4605,6 @@ QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB,
if (PointeeType.isNull())
return QualType();
- if (SemaRef.getLangOpts().OpenCL)
- deduceOpenCLPointeeAddrSpace(SemaRef, PointeeType);
-
QualType Result = TL.getType();
if (PointeeType->getAs<ObjCObjectType>()) {
// A dependent pointer type 'T *' has is being transformed such
@@ -4621,9 +4643,6 @@ TreeTransform<Derived>::TransformBlockPointerType(TypeLocBuilder &TLB,
if (PointeeType.isNull())
return QualType();
- if (SemaRef.getLangOpts().OpenCL)
- deduceOpenCLPointeeAddrSpace(SemaRef, PointeeType);
-
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
PointeeType != TL.getPointeeLoc().getType()) {
@@ -4653,9 +4672,6 @@ TreeTransform<Derived>::TransformReferenceType(TypeLocBuilder &TLB,
if (PointeeType.isNull())
return QualType();
- if (SemaRef.getLangOpts().OpenCL)
- deduceOpenCLPointeeAddrSpace(SemaRef, PointeeType);
-
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
PointeeType != T->getPointeeTypeAsWritten()) {
@@ -7190,8 +7206,12 @@ TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) {
// that may fail.
ScopeInfo->setNeedsCoroutineSuspends(false);
- // The new CoroutinePromise object needs to be built and put into the current
- // FunctionScopeInfo before any transformations or rebuilding occurs.
+ // We re-build the coroutine promise object (and the coroutine parameters its
+ // type and constructor depend on) based on the types used in our current
+ // function. We must do so, and set it on the current FunctionScopeInfo,
+ // before attempting to transform the other parts of the coroutine body
+ // statement, such as the implicit suspend statements (because those
+ // statements reference the FunctionScopeInfo::CoroutinePromise).
if (!SemaRef.buildCoroutineParameterMoves(FD->getLocation()))
return StmtError();
auto *Promise = SemaRef.buildCoroutinePromise(FD->getLocation());
@@ -7200,8 +7220,9 @@ TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) {
getDerived().transformedLocalDecl(S->getPromiseDecl(), {Promise});
ScopeInfo->CoroutinePromise = Promise;
- // Transform the implicit coroutine statements we built during the initial
- // parse.
+ // Transform the implicit coroutine statements constructed using dependent
+ // types during the previous parse: initial and final suspensions, the return
+ // object, and others. We also transform the coroutine function's body.
StmtResult InitSuspend = getDerived().TransformStmt(S->getInitSuspendStmt());
if (InitSuspend.isInvalid())
return StmtError();
@@ -7228,17 +7249,13 @@ TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) {
return StmtError();
Builder.ReturnValue = Res.get();
+ // If during the previous parse the coroutine still had a dependent promise
+ // statement, we may need to build some implicit coroutine statements
+ // (such as exception and fallthrough handlers) for the first time.
if (S->hasDependentPromiseType()) {
- // PR41909: We may find a generic coroutine lambda definition within a
- // template function that is being instantiated. In this case, the lambda
- // will have a dependent promise type, until it is used in an expression
- // that creates an instantiation with a non-dependent promise type. We
- // should not assert or build coroutine dependent statements for such a
- // generic lambda.
- auto *MD = dyn_cast_or_null<CXXMethodDecl>(FD);
- if (!MD || !MD->getParent()->isGenericLambda()) {
- assert(!Promise->getType()->isDependentType() &&
- "the promise type must no longer be dependent");
+ // We can only build these statements, however, if the current promise type
+ // is not dependent.
+ if (!Promise->getType()->isDependentType()) {
assert(!S->getFallthroughHandler() && !S->getExceptionHandler() &&
!S->getReturnStmtOnAllocFailure() && !S->getDeallocate() &&
"these nodes should not have been built yet");
@@ -8046,6 +8063,17 @@ StmtResult TreeTransform<Derived>::TransformOMPParallelForSimdDirective(
}
template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPParallelMasterDirective(
+ OMPParallelMasterDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel_master, DirName,
+ nullptr, D->getBeginLoc());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
StmtResult TreeTransform<Derived>::TransformOMPParallelSectionsDirective(
OMPParallelSectionsDirective *D) {
DeclarationNameInfo DirName;
@@ -8310,6 +8338,18 @@ StmtResult TreeTransform<Derived>::TransformOMPParallelMasterTaskLoopDirective(
}
template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPParallelMasterTaskLoopSimdDirective(
+ OMPParallelMasterTaskLoopSimdDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(
+ OMPD_parallel_master_taskloop_simd, DirName, nullptr, D->getBeginLoc());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
StmtResult TreeTransform<Derived>::TransformOMPDistributeDirective(
OMPDistributeDirective *D) {
DeclarationNameInfo DirName;
@@ -8745,7 +8785,8 @@ TreeTransform<Derived>::TransformOMPLastprivateClause(OMPLastprivateClause *C) {
Vars.push_back(EVar.get());
}
return getDerived().RebuildOMPLastprivateClause(
- Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+ Vars, C->getKind(), C->getKindLoc(), C->getColonLoc(), C->getBeginLoc(),
+ C->getLParenLoc(), C->getEndLoc());
}
template <typename Derived>
@@ -9173,7 +9214,15 @@ OMPClause *TreeTransform<Derived>::TransformOMPDistScheduleClause(
template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPDefaultmapClause(OMPDefaultmapClause *C) {
- return C;
+ // Rebuild Defaultmap Clause since we need to invoke the checking of
+ // defaultmap(none:variable-category) after template initialization.
+ return getDerived().RebuildOMPDefaultmapClause(C->getDefaultmapModifier(),
+ C->getDefaultmapKind(),
+ C->getBeginLoc(),
+ C->getLParenLoc(),
+ C->getDefaultmapModifierLoc(),
+ C->getDefaultmapKindLoc(),
+ C->getEndLoc());
}
template <typename Derived>
@@ -9234,6 +9283,21 @@ TreeTransform<Derived>::TransformOMPIsDevicePtrClause(OMPIsDevicePtrClause *C) {
return getDerived().RebuildOMPIsDevicePtrClause(Vars, Locs);
}
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPNontemporalClause(OMPNontemporalClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
+ if (EVar.isInvalid())
+ return nullptr;
+ Vars.push_back(EVar.get());
+ }
+ return getDerived().RebuildOMPNontemporalClause(
+ Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+}
+
//===----------------------------------------------------------------------===//
// Expression transformation
//===----------------------------------------------------------------------===//
@@ -9368,7 +9432,7 @@ TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) {
SmallVector<Expr *, 4> AssocExprs;
SmallVector<TypeSourceInfo *, 4> AssocTypes;
- for (const GenericSelectionExpr::Association &Assoc : E->associations()) {
+ for (const GenericSelectionExpr::Association Assoc : E->associations()) {
TypeSourceInfo *TSI = Assoc.getTypeSourceInfo();
if (TSI) {
TypeSourceInfo *AssocType = getDerived().TransformType(TSI);
@@ -11111,7 +11175,7 @@ TreeTransform<Derived>::TransformConceptSpecializationExpr(
return getDerived().RebuildConceptSpecializationExpr(
E->getNestedNameSpecifierLoc(), E->getTemplateKWLoc(),
- E->getConceptNameLoc(), E->getFoundDecl(), E->getNamedConcept(),
+ E->getConceptNameInfo(), E->getFoundDecl(), E->getNamedConcept(),
&TransArgs);
}
@@ -11488,6 +11552,13 @@ 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.
CXXRecordDecl *OldClass = E->getLambdaClass();
CXXRecordDecl *Class
@@ -11508,7 +11579,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
Class, E->getIntroducerRange(), NewCallOpTSI,
E->getCallOperator()->getEndLoc(),
NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(),
- E->getCallOperator()->getConstexprKind());
+ E->getCallOperator()->getConstexprKind(),
+ NewTrailingRequiresClause.get());
LSI->CallOperator = NewCallOperator;
@@ -12145,7 +12217,7 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformMaterializeTemporaryExpr(
MaterializeTemporaryExpr *E) {
- return getDerived().TransformExpr(E->GetTemporaryExpr());
+ return getDerived().TransformExpr(E->getSubExpr());
}
template<typename Derived>
diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp
index dd06e0582ac5..cdb5b17022c2 100644
--- a/clang/lib/Serialization/ASTCommon.cpp
+++ b/clang/lib/Serialization/ASTCommon.cpp
@@ -401,6 +401,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::Decomposition:
case Decl::Binding:
case Decl::Concept:
+ case Decl::LifetimeExtendedTemporary:
return false;
// These indirectly derive from Redeclarable<T> but are not actually
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 2d3884ebe021..19e7ebe03a1f 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -10,9 +10,11 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Serialization/ASTReader.h"
+#include "clang/Basic/OpenMPKinds.h"
+#include "clang/Serialization/ASTRecordReader.h"
#include "ASTCommon.h"
#include "ASTReaderInternals.h"
+#include "clang/AST/AbstractTypeReader.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
@@ -29,6 +31,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/OpenMPClause.h"
#include "clang/AST/ODRHash.h"
#include "clang/AST/RawCommentList.h"
#include "clang/AST/TemplateBase.h"
@@ -76,7 +79,7 @@
#include "clang/Serialization/ContinuousRangeMap.h"
#include "clang/Serialization/GlobalModuleIndex.h"
#include "clang/Serialization/InMemoryModuleCache.h"
-#include "clang/Serialization/Module.h"
+#include "clang/Serialization/ModuleFile.h"
#include "clang/Serialization/ModuleFileExtension.h"
#include "clang/Serialization/ModuleManager.h"
#include "clang/Serialization/PCHContainerOperations.h"
@@ -1239,12 +1242,12 @@ void ASTReader::Error(StringRef Msg) const {
}
}
-void ASTReader::Error(unsigned DiagID,
- StringRef Arg1, StringRef Arg2) const {
+void ASTReader::Error(unsigned DiagID, StringRef Arg1, StringRef Arg2,
+ StringRef Arg3) const {
if (Diags.isDiagnosticInFlight())
- Diags.SetDelayedDiagnostic(DiagID, Arg1, Arg2);
+ Diags.SetDelayedDiagnostic(DiagID, Arg1, Arg2, Arg3);
else
- Diag(DiagID) << Arg1 << Arg2;
+ Diag(DiagID) << Arg1 << Arg2 << Arg3;
}
void ASTReader::Error(unsigned DiagID, StringRef Arg1, StringRef Arg2,
@@ -2561,7 +2564,6 @@ ASTReader::ReadControlBlock(ModuleFile &F,
const ModuleFile *ImportedBy,
unsigned ClientLoadCapabilities) {
BitstreamCursor &Stream = F.Stream;
- ASTReadResult Result = Success;
if (llvm::Error Err = Stream.EnterSubBlock(CONTROL_BLOCK_ID)) {
Error(std::move(Err));
@@ -2652,7 +2654,7 @@ ASTReader::ReadControlBlock(ModuleFile &F,
}
}
- return Result;
+ return Success;
}
case llvm::BitstreamEntry::SubBlock:
@@ -2682,9 +2684,10 @@ ASTReader::ReadControlBlock(ModuleFile &F,
bool AllowCompatibleConfigurationMismatch =
F.Kind == MK_ExplicitModule || F.Kind == MK_PrebuiltModule;
- Result = ReadOptionsBlock(Stream, ClientLoadCapabilities,
- AllowCompatibleConfigurationMismatch,
- *Listener, SuggestedPredefines);
+ ASTReadResult Result =
+ ReadOptionsBlock(Stream, ClientLoadCapabilities,
+ AllowCompatibleConfigurationMismatch, *Listener,
+ SuggestedPredefines);
if (Result == Failure) {
Error("malformed block record in AST file");
return Result;
@@ -3221,7 +3224,8 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
case MODULAR_CODEGEN_DECLS:
// FIXME: Skip reading this record if our ASTConsumer doesn't care about
// them (ie: if we're not codegenerating this module).
- if (F.Kind == MK_MainFile)
+ if (F.Kind == MK_MainFile ||
+ getContext().getLangOpts().BuildingPCHWithObjectFile)
for (unsigned I = 0, N = Record.size(); I != N; ++I)
EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I]));
break;
@@ -3408,8 +3412,10 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
break;
case SOURCE_MANAGER_LINE_TABLE:
- if (ParseLineTable(F, Record))
+ if (ParseLineTable(F, Record)) {
+ Error("malformed SOURCE_MANAGER_LINE_TABLE in AST file");
return Failure;
+ }
break;
case SOURCE_LOCATION_PRELOADS: {
@@ -4174,6 +4180,20 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
PreviousGeneration = incrementGeneration(*ContextObj);
unsigned NumModules = ModuleMgr.size();
+ auto removeModulesAndReturn = [&](ASTReadResult ReadResult) {
+ assert(ReadResult && "expected to return error");
+ ModuleMgr.removeModules(ModuleMgr.begin() + NumModules,
+ PP.getLangOpts().Modules
+ ? &PP.getHeaderSearchInfo().getModuleMap()
+ : nullptr);
+
+ // If we find that any modules are unusable, the global index is going
+ // to be out-of-date. Just remove it.
+ GlobalIndex.reset();
+ ModuleMgr.setGlobalIndex(nullptr);
+ return ReadResult;
+ };
+
SmallVector<ImportedModule, 4> Loaded;
switch (ASTReadResult ReadResult =
ReadASTCore(FileName, Type, ImportLoc,
@@ -4184,42 +4204,33 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
case OutOfDate:
case VersionMismatch:
case ConfigurationMismatch:
- case HadErrors: {
- llvm::SmallPtrSet<ModuleFile *, 4> LoadedSet;
- for (const ImportedModule &IM : Loaded)
- LoadedSet.insert(IM.Mod);
-
- ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, LoadedSet,
- PP.getLangOpts().Modules
- ? &PP.getHeaderSearchInfo().getModuleMap()
- : nullptr);
-
- // If we find that any modules are unusable, the global index is going
- // to be out-of-date. Just remove it.
- GlobalIndex.reset();
- ModuleMgr.setGlobalIndex(nullptr);
- return ReadResult;
- }
+ case HadErrors:
+ return removeModulesAndReturn(ReadResult);
case Success:
break;
}
// Here comes stuff that we only do once the entire chain is loaded.
- // Load the AST blocks of all of the modules that we loaded.
- for (SmallVectorImpl<ImportedModule>::iterator M = Loaded.begin(),
- MEnd = Loaded.end();
- M != MEnd; ++M) {
- ModuleFile &F = *M->Mod;
+ // Load the AST blocks of all of the modules that we loaded. We can still
+ // hit errors parsing the ASTs at this point.
+ for (ImportedModule &M : Loaded) {
+ ModuleFile &F = *M.Mod;
// Read the AST block.
if (ASTReadResult Result = ReadASTBlock(F, ClientLoadCapabilities))
- return Result;
+ return removeModulesAndReturn(Result);
+
+ // The AST block should always have a definition for the main module.
+ if (F.isModule() && !F.DidReadTopLevelSubmodule) {
+ Error(diag::err_module_file_missing_top_level_submodule, F.FileName);
+ return removeModulesAndReturn(Failure);
+ }
// Read the extension blocks.
while (!SkipCursorToBlock(F.Stream, EXTENSION_BLOCK_ID)) {
if (ASTReadResult Result = ReadExtensionBlock(F))
- return Result;
+ return removeModulesAndReturn(Result);
}
// Once read, set the ModuleFile bit base offset and update the size in
@@ -4227,6 +4238,11 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
F.GlobalBitOffset = TotalModulesSizeInBits;
TotalModulesSizeInBits += F.SizeInBits;
GlobalBitOffsetsMap.insert(std::make_pair(F.GlobalBitOffset, &F));
+ }
+
+ // Preload source locations and interesting indentifiers.
+ for (ImportedModule &M : Loaded) {
+ ModuleFile &F = *M.Mod;
// Preload SLocEntries.
for (unsigned I = 0, N = F.PreloadSLocEntries.size(); I != N; ++I) {
@@ -4269,10 +4285,8 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
// Setup the import locations and notify the module manager that we've
// committed to these module files.
- for (SmallVectorImpl<ImportedModule>::iterator M = Loaded.begin(),
- MEnd = Loaded.end();
- M != MEnd; ++M) {
- ModuleFile &F = *M->Mod;
+ for (ImportedModule &M : Loaded) {
+ ModuleFile &F = *M.Mod;
ModuleMgr.moduleFileAccepted(&F);
@@ -4280,10 +4294,10 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
F.DirectImportLoc = ImportLoc;
// FIXME: We assume that locations from PCH / preamble do not need
// any translation.
- if (!M->ImportedBy)
- F.ImportLoc = M->ImportLoc;
+ if (!M.ImportedBy)
+ F.ImportLoc = M.ImportLoc;
else
- F.ImportLoc = TranslateSourceLocation(*M->ImportedBy, M->ImportLoc);
+ F.ImportLoc = TranslateSourceLocation(*M.ImportedBy, M.ImportLoc);
}
if (!PP.getLangOpts().CPlusPlus ||
@@ -4773,8 +4787,10 @@ ASTReader::ASTReadResult ASTReader::ReadExtensionBlock(ModuleFile &F) {
switch (MaybeRecCode.get()) {
case EXTENSION_METADATA: {
ModuleFileExtensionMetadata Metadata;
- if (parseModuleFileExtensionMetadata(Record, Blob, Metadata))
+ if (parseModuleFileExtensionMetadata(Record, Blob, Metadata)) {
+ Error("malformed EXTENSION_METADATA in AST file");
return Failure;
+ }
// Find a module file extension with this block name.
auto Known = ModuleFileExtensions.find(Metadata.BlockName);
@@ -5476,16 +5492,14 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
// Don't emit module relocation error if we have -fno-validate-pch
if (!PP.getPreprocessorOpts().DisablePCHValidation &&
CurFile != F.File) {
- if (!Diags.isDiagnosticInFlight()) {
- Diag(diag::err_module_file_conflict)
- << CurrentModule->getTopLevelModuleName()
- << CurFile->getName()
- << F.File->getName();
- }
+ Error(diag::err_module_file_conflict,
+ CurrentModule->getTopLevelModuleName(), CurFile->getName(),
+ F.File->getName());
return Failure;
}
}
+ F.DidReadTopLevelSubmodule = true;
CurrentModule->setASTFile(F.File);
CurrentModule->PresumedModuleMapFile = F.ModuleMapPath;
}
@@ -6306,6 +6320,15 @@ ASTReader::RecordLocation ASTReader::TypeCursorForIndex(unsigned Index) {
return RecordLocation(M, M->TypeOffsets[Index - M->BaseTypeIndex]);
}
+static llvm::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;
+ }
+}
+
/// Read and return the type with the given index..
///
/// The index is the type ID, shifted and minus the number of predefs. This
@@ -6327,616 +6350,61 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
// Note that we are loading a type record.
Deserializing AType(this);
- unsigned Idx = 0;
if (llvm::Error Err = DeclsCursor.JumpToBit(Loc.Offset)) {
Error(std::move(Err));
return QualType();
}
- RecordData Record;
- Expected<unsigned> MaybeCode = DeclsCursor.ReadCode();
- if (!MaybeCode) {
- Error(MaybeCode.takeError());
+ Expected<unsigned> RawCode = DeclsCursor.ReadCode();
+ if (!RawCode) {
+ Error(RawCode.takeError());
return QualType();
}
- unsigned Code = MaybeCode.get();
- Expected<unsigned> MaybeTypeCode = DeclsCursor.readRecord(Code, Record);
- if (!MaybeTypeCode) {
- Error(MaybeTypeCode.takeError());
+ ASTRecordReader Record(*this, *Loc.F);
+ Expected<unsigned> Code = Record.readRecord(DeclsCursor, RawCode.get());
+ if (!Code) {
+ Error(Code.takeError());
return QualType();
}
- switch ((TypeCode)MaybeTypeCode.get()) {
- case TYPE_EXT_QUAL: {
- if (Record.size() != 2) {
- Error("Incorrect encoding of extended qualifier type");
- return QualType();
- }
- QualType Base = readType(*Loc.F, Record, Idx);
- Qualifiers Quals = Qualifiers::fromOpaqueValue(Record[Idx++]);
- return Context.getQualifiedType(Base, Quals);
- }
-
- case TYPE_COMPLEX: {
- if (Record.size() != 1) {
- Error("Incorrect encoding of complex type");
- return QualType();
- }
- QualType ElemType = readType(*Loc.F, Record, Idx);
- return Context.getComplexType(ElemType);
- }
-
- case TYPE_POINTER: {
- if (Record.size() != 1) {
- Error("Incorrect encoding of pointer type");
- return QualType();
- }
- QualType PointeeType = readType(*Loc.F, Record, Idx);
- return Context.getPointerType(PointeeType);
- }
-
- case TYPE_DECAYED: {
- if (Record.size() != 1) {
- Error("Incorrect encoding of decayed type");
- return QualType();
- }
- QualType OriginalType = readType(*Loc.F, Record, Idx);
- QualType DT = Context.getAdjustedParameterType(OriginalType);
- if (!isa<DecayedType>(DT))
- Error("Decayed type does not decay");
- return DT;
- }
-
- case TYPE_ADJUSTED: {
- if (Record.size() != 2) {
- Error("Incorrect encoding of adjusted type");
- return QualType();
- }
- QualType OriginalTy = readType(*Loc.F, Record, Idx);
- QualType AdjustedTy = readType(*Loc.F, Record, Idx);
- return Context.getAdjustedType(OriginalTy, AdjustedTy);
- }
-
- case TYPE_BLOCK_POINTER: {
- if (Record.size() != 1) {
- Error("Incorrect encoding of block pointer type");
- return QualType();
- }
- QualType PointeeType = readType(*Loc.F, Record, Idx);
- return Context.getBlockPointerType(PointeeType);
- }
-
- case TYPE_LVALUE_REFERENCE: {
- if (Record.size() != 2) {
- Error("Incorrect encoding of lvalue reference type");
- return QualType();
- }
- QualType PointeeType = readType(*Loc.F, Record, Idx);
- return Context.getLValueReferenceType(PointeeType, Record[1]);
- }
-
- case TYPE_RVALUE_REFERENCE: {
- if (Record.size() != 1) {
- Error("Incorrect encoding of rvalue reference type");
- return QualType();
- }
- QualType PointeeType = readType(*Loc.F, Record, Idx);
- return Context.getRValueReferenceType(PointeeType);
- }
-
- case TYPE_MEMBER_POINTER: {
- if (Record.size() != 2) {
- Error("Incorrect encoding of member pointer type");
- return QualType();
- }
- QualType PointeeType = readType(*Loc.F, Record, Idx);
- QualType ClassType = readType(*Loc.F, Record, Idx);
- if (PointeeType.isNull() || ClassType.isNull())
- return QualType();
-
- return Context.getMemberPointerType(PointeeType, ClassType.getTypePtr());
- }
-
- case TYPE_CONSTANT_ARRAY: {
- QualType ElementType = readType(*Loc.F, Record, Idx);
- ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
- unsigned IndexTypeQuals = Record[2];
- unsigned Idx = 3;
- llvm::APInt Size = ReadAPInt(Record, Idx);
- Expr *SizeExpr = ReadExpr(*Loc.F);
- return Context.getConstantArrayType(ElementType, Size, SizeExpr,
- ASM, IndexTypeQuals);
- }
-
- case TYPE_INCOMPLETE_ARRAY: {
- QualType ElementType = readType(*Loc.F, Record, Idx);
- ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
- unsigned IndexTypeQuals = Record[2];
- return Context.getIncompleteArrayType(ElementType, ASM, IndexTypeQuals);
- }
-
- case TYPE_VARIABLE_ARRAY: {
- QualType ElementType = readType(*Loc.F, Record, Idx);
- ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
- unsigned IndexTypeQuals = Record[2];
- SourceLocation LBLoc = ReadSourceLocation(*Loc.F, Record[3]);
- SourceLocation RBLoc = ReadSourceLocation(*Loc.F, Record[4]);
- return Context.getVariableArrayType(ElementType, ReadExpr(*Loc.F),
- ASM, IndexTypeQuals,
- SourceRange(LBLoc, RBLoc));
- }
-
- case TYPE_VECTOR: {
- if (Record.size() != 3) {
- Error("incorrect encoding of vector type in AST file");
- return QualType();
- }
-
- QualType ElementType = readType(*Loc.F, Record, Idx);
- unsigned NumElements = Record[1];
- unsigned VecKind = Record[2];
- return Context.getVectorType(ElementType, NumElements,
- (VectorType::VectorKind)VecKind);
- }
-
- case TYPE_EXT_VECTOR: {
- if (Record.size() != 3) {
- Error("incorrect encoding of extended vector type in AST file");
- return QualType();
- }
-
- QualType ElementType = readType(*Loc.F, Record, Idx);
- unsigned NumElements = Record[1];
- return Context.getExtVectorType(ElementType, NumElements);
+ if (Code.get() == TYPE_EXT_QUAL) {
+ QualType baseType = Record.readQualType();
+ Qualifiers quals = Record.readQualifiers();
+ return Context.getQualifiedType(baseType, quals);
}
- case TYPE_FUNCTION_NO_PROTO: {
- if (Record.size() != 8) {
- Error("incorrect encoding of no-proto function type");
- return QualType();
- }
- QualType ResultType = readType(*Loc.F, Record, Idx);
- FunctionType::ExtInfo Info(Record[1], Record[2], Record[3],
- (CallingConv)Record[4], Record[5], Record[6],
- Record[7]);
- return Context.getFunctionNoProtoType(ResultType, Info);
- }
-
- case TYPE_FUNCTION_PROTO: {
- QualType ResultType = readType(*Loc.F, Record, Idx);
-
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.ExtInfo = FunctionType::ExtInfo(/*noreturn*/ Record[1],
- /*hasregparm*/ Record[2],
- /*regparm*/ Record[3],
- static_cast<CallingConv>(Record[4]),
- /*produces*/ Record[5],
- /*nocallersavedregs*/ Record[6],
- /*nocfcheck*/ Record[7]);
-
- unsigned Idx = 8;
-
- EPI.Variadic = Record[Idx++];
- EPI.HasTrailingReturn = Record[Idx++];
- EPI.TypeQuals = Qualifiers::fromOpaqueValue(Record[Idx++]);
- EPI.RefQualifier = static_cast<RefQualifierKind>(Record[Idx++]);
- SmallVector<QualType, 8> ExceptionStorage;
- readExceptionSpec(*Loc.F, ExceptionStorage, EPI.ExceptionSpec, Record, Idx);
-
- unsigned NumParams = Record[Idx++];
- SmallVector<QualType, 16> ParamTypes;
- for (unsigned I = 0; I != NumParams; ++I)
- ParamTypes.push_back(readType(*Loc.F, Record, Idx));
-
- SmallVector<FunctionProtoType::ExtParameterInfo, 4> ExtParameterInfos;
- if (Idx != Record.size()) {
- for (unsigned I = 0; I != NumParams; ++I)
- ExtParameterInfos.push_back(
- FunctionProtoType::ExtParameterInfo
- ::getFromOpaqueValue(Record[Idx++]));
- EPI.ExtParameterInfos = ExtParameterInfos.data();
- }
-
- assert(Idx == Record.size());
-
- return Context.getFunctionType(ResultType, ParamTypes, EPI);
- }
-
- case TYPE_UNRESOLVED_USING: {
- unsigned Idx = 0;
- return Context.getTypeDeclType(
- ReadDeclAs<UnresolvedUsingTypenameDecl>(*Loc.F, Record, Idx));
- }
-
- case TYPE_TYPEDEF: {
- if (Record.size() != 2) {
- Error("incorrect encoding of typedef type");
- return QualType();
- }
- unsigned Idx = 0;
- TypedefNameDecl *Decl = ReadDeclAs<TypedefNameDecl>(*Loc.F, Record, Idx);
- QualType Canonical = readType(*Loc.F, Record, Idx);
- if (!Canonical.isNull())
- Canonical = Context.getCanonicalType(Canonical);
- return Context.getTypedefType(Decl, Canonical);
- }
-
- case TYPE_TYPEOF_EXPR:
- return Context.getTypeOfExprType(ReadExpr(*Loc.F));
-
- case TYPE_TYPEOF: {
- if (Record.size() != 1) {
- Error("incorrect encoding of typeof(type) in AST file");
- return QualType();
- }
- QualType UnderlyingType = readType(*Loc.F, Record, Idx);
- return Context.getTypeOfType(UnderlyingType);
- }
-
- case TYPE_DECLTYPE: {
- QualType UnderlyingType = readType(*Loc.F, Record, Idx);
- return Context.getDecltypeType(ReadExpr(*Loc.F), UnderlyingType);
- }
-
- case TYPE_UNARY_TRANSFORM: {
- QualType BaseType = readType(*Loc.F, Record, Idx);
- QualType UnderlyingType = readType(*Loc.F, Record, Idx);
- UnaryTransformType::UTTKind UKind = (UnaryTransformType::UTTKind)Record[2];
- return Context.getUnaryTransformType(BaseType, UnderlyingType, UKind);
- }
-
- case TYPE_AUTO: {
- QualType Deduced = readType(*Loc.F, Record, Idx);
- AutoTypeKeyword Keyword = (AutoTypeKeyword)Record[Idx++];
- bool IsDependent = false, IsPack = false;
- if (Deduced.isNull()) {
- IsDependent = Record[Idx] > 0;
- IsPack = Record[Idx] > 1;
- ++Idx;
- }
- return Context.getAutoType(Deduced, Keyword, IsDependent, IsPack);
- }
-
- case TYPE_DEDUCED_TEMPLATE_SPECIALIZATION: {
- TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx);
- QualType Deduced = readType(*Loc.F, Record, Idx);
- bool IsDependent = Deduced.isNull() ? Record[Idx++] : false;
- return Context.getDeducedTemplateSpecializationType(Name, Deduced,
- IsDependent);
- }
-
- case TYPE_RECORD: {
- if (Record.size() != 2) {
- Error("incorrect encoding of record type");
- return QualType();
- }
- unsigned Idx = 0;
- bool IsDependent = Record[Idx++];
- RecordDecl *RD = ReadDeclAs<RecordDecl>(*Loc.F, Record, Idx);
- RD = cast_or_null<RecordDecl>(RD->getCanonicalDecl());
- QualType T = Context.getRecordType(RD);
- const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent);
- return T;
- }
-
- case TYPE_ENUM: {
- if (Record.size() != 2) {
- Error("incorrect encoding of enum type");
- return QualType();
- }
- unsigned Idx = 0;
- bool IsDependent = Record[Idx++];
- QualType T
- = Context.getEnumType(ReadDeclAs<EnumDecl>(*Loc.F, Record, Idx));
- const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent);
- return T;
- }
-
- case TYPE_ATTRIBUTED: {
- if (Record.size() != 3) {
- Error("incorrect encoding of attributed type");
- return QualType();
- }
- QualType modifiedType = readType(*Loc.F, Record, Idx);
- QualType equivalentType = readType(*Loc.F, Record, Idx);
- AttributedType::Kind kind = static_cast<AttributedType::Kind>(Record[2]);
- return Context.getAttributedType(kind, modifiedType, equivalentType);
- }
-
- case TYPE_PAREN: {
- if (Record.size() != 1) {
- Error("incorrect encoding of paren type");
- return QualType();
- }
- QualType InnerType = readType(*Loc.F, Record, Idx);
- return Context.getParenType(InnerType);
- }
-
- case TYPE_MACRO_QUALIFIED: {
- if (Record.size() != 2) {
- Error("incorrect encoding of macro defined type");
- return QualType();
- }
- QualType UnderlyingTy = readType(*Loc.F, Record, Idx);
- IdentifierInfo *MacroII = GetIdentifierInfo(*Loc.F, Record, Idx);
- return Context.getMacroQualifiedType(UnderlyingTy, MacroII);
- }
-
- case TYPE_PACK_EXPANSION: {
- if (Record.size() != 2) {
- Error("incorrect encoding of pack expansion type");
- return QualType();
- }
- QualType Pattern = readType(*Loc.F, Record, Idx);
- if (Pattern.isNull())
- return QualType();
- Optional<unsigned> NumExpansions;
- if (Record[1])
- NumExpansions = Record[1] - 1;
- return Context.getPackExpansionType(Pattern, NumExpansions);
- }
-
- case TYPE_ELABORATED: {
- unsigned Idx = 0;
- ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++];
- NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx);
- QualType NamedType = readType(*Loc.F, Record, Idx);
- TagDecl *OwnedTagDecl = ReadDeclAs<TagDecl>(*Loc.F, Record, Idx);
- return Context.getElaboratedType(Keyword, NNS, NamedType, OwnedTagDecl);
- }
-
- case TYPE_OBJC_INTERFACE: {
- unsigned Idx = 0;
- ObjCInterfaceDecl *ItfD
- = ReadDeclAs<ObjCInterfaceDecl>(*Loc.F, Record, Idx);
- return Context.getObjCInterfaceType(ItfD->getCanonicalDecl());
- }
-
- case TYPE_OBJC_TYPE_PARAM: {
- unsigned Idx = 0;
- ObjCTypeParamDecl *Decl
- = ReadDeclAs<ObjCTypeParamDecl>(*Loc.F, Record, Idx);
- unsigned NumProtos = Record[Idx++];
- SmallVector<ObjCProtocolDecl*, 4> Protos;
- for (unsigned I = 0; I != NumProtos; ++I)
- Protos.push_back(ReadDeclAs<ObjCProtocolDecl>(*Loc.F, Record, Idx));
- return Context.getObjCTypeParamType(Decl, Protos);
- }
-
- case TYPE_OBJC_OBJECT: {
- unsigned Idx = 0;
- QualType Base = readType(*Loc.F, Record, Idx);
- unsigned NumTypeArgs = Record[Idx++];
- SmallVector<QualType, 4> TypeArgs;
- for (unsigned I = 0; I != NumTypeArgs; ++I)
- TypeArgs.push_back(readType(*Loc.F, Record, Idx));
- unsigned NumProtos = Record[Idx++];
- SmallVector<ObjCProtocolDecl*, 4> Protos;
- for (unsigned I = 0; I != NumProtos; ++I)
- Protos.push_back(ReadDeclAs<ObjCProtocolDecl>(*Loc.F, Record, Idx));
- bool IsKindOf = Record[Idx++];
- return Context.getObjCObjectType(Base, TypeArgs, Protos, IsKindOf);
- }
-
- case TYPE_OBJC_OBJECT_POINTER: {
- unsigned Idx = 0;
- QualType Pointee = readType(*Loc.F, Record, Idx);
- return Context.getObjCObjectPointerType(Pointee);
- }
-
- case TYPE_SUBST_TEMPLATE_TYPE_PARM: {
- unsigned Idx = 0;
- QualType Parm = readType(*Loc.F, Record, Idx);
- QualType Replacement = readType(*Loc.F, Record, Idx);
- return Context.getSubstTemplateTypeParmType(
- cast<TemplateTypeParmType>(Parm),
- Context.getCanonicalType(Replacement));
- }
-
- case TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK: {
- unsigned Idx = 0;
- QualType Parm = readType(*Loc.F, Record, Idx);
- TemplateArgument ArgPack = ReadTemplateArgument(*Loc.F, Record, Idx);
- return Context.getSubstTemplateTypeParmPackType(
- cast<TemplateTypeParmType>(Parm),
- ArgPack);
- }
-
- case TYPE_INJECTED_CLASS_NAME: {
- CXXRecordDecl *D = ReadDeclAs<CXXRecordDecl>(*Loc.F, Record, Idx);
- QualType TST = readType(*Loc.F, Record, Idx); // probably derivable
- // FIXME: ASTContext::getInjectedClassNameType is not currently suitable
- // for AST reading, too much interdependencies.
- const Type *T = nullptr;
- for (auto *DI = D; DI; DI = DI->getPreviousDecl()) {
- if (const Type *Existing = DI->getTypeForDecl()) {
- T = Existing;
- break;
- }
- }
- if (!T) {
- T = new (Context, TypeAlignment) InjectedClassNameType(D, TST);
- for (auto *DI = D; DI; DI = DI->getPreviousDecl())
- DI->setTypeForDecl(T);
- }
- return QualType(T, 0);
- }
-
- case TYPE_TEMPLATE_TYPE_PARM: {
- unsigned Idx = 0;
- unsigned Depth = Record[Idx++];
- unsigned Index = Record[Idx++];
- bool Pack = Record[Idx++];
- TemplateTypeParmDecl *D
- = ReadDeclAs<TemplateTypeParmDecl>(*Loc.F, Record, Idx);
- return Context.getTemplateTypeParmType(Depth, Index, Pack, D);
- }
-
- case TYPE_DEPENDENT_NAME: {
- unsigned Idx = 0;
- ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++];
- NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx);
- const IdentifierInfo *Name = GetIdentifierInfo(*Loc.F, Record, Idx);
- QualType Canon = readType(*Loc.F, Record, Idx);
- if (!Canon.isNull())
- Canon = Context.getCanonicalType(Canon);
- return Context.getDependentNameType(Keyword, NNS, Name, Canon);
- }
-
- case TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION: {
- unsigned Idx = 0;
- ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++];
- NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx);
- const IdentifierInfo *Name = GetIdentifierInfo(*Loc.F, Record, Idx);
- unsigned NumArgs = Record[Idx++];
- SmallVector<TemplateArgument, 8> Args;
- Args.reserve(NumArgs);
- while (NumArgs--)
- Args.push_back(ReadTemplateArgument(*Loc.F, Record, Idx));
- return Context.getDependentTemplateSpecializationType(Keyword, NNS, Name,
- Args);
- }
-
- case TYPE_DEPENDENT_SIZED_ARRAY: {
- unsigned Idx = 0;
-
- // ArrayType
- QualType ElementType = readType(*Loc.F, Record, Idx);
- ArrayType::ArraySizeModifier ASM
- = (ArrayType::ArraySizeModifier)Record[Idx++];
- unsigned IndexTypeQuals = Record[Idx++];
-
- // DependentSizedArrayType
- Expr *NumElts = ReadExpr(*Loc.F);
- SourceRange Brackets = ReadSourceRange(*Loc.F, Record, Idx);
-
- return Context.getDependentSizedArrayType(ElementType, NumElts, ASM,
- IndexTypeQuals, Brackets);
- }
-
- case TYPE_TEMPLATE_SPECIALIZATION: {
- unsigned Idx = 0;
- bool IsDependent = Record[Idx++];
- TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx);
- SmallVector<TemplateArgument, 8> Args;
- ReadTemplateArgumentList(Args, *Loc.F, Record, Idx);
- QualType Underlying = readType(*Loc.F, Record, Idx);
- QualType T;
- if (Underlying.isNull())
- T = Context.getCanonicalTemplateSpecializationType(Name, Args);
- else
- T = Context.getTemplateSpecializationType(Name, Args, Underlying);
- const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent);
- return T;
- }
-
- case TYPE_ATOMIC: {
- if (Record.size() != 1) {
- Error("Incorrect encoding of atomic type");
- return QualType();
- }
- QualType ValueType = readType(*Loc.F, Record, Idx);
- return Context.getAtomicType(ValueType);
- }
-
- case TYPE_PIPE: {
- if (Record.size() != 2) {
- Error("Incorrect encoding of pipe type");
- return QualType();
- }
-
- // Reading the pipe element type.
- QualType ElementType = readType(*Loc.F, Record, Idx);
- unsigned ReadOnly = Record[1];
- return Context.getPipeType(ElementType, ReadOnly);
- }
-
- case TYPE_DEPENDENT_SIZED_VECTOR: {
- unsigned Idx = 0;
- QualType ElementType = readType(*Loc.F, Record, Idx);
- Expr *SizeExpr = ReadExpr(*Loc.F);
- SourceLocation AttrLoc = ReadSourceLocation(*Loc.F, Record, Idx);
- unsigned VecKind = Record[Idx];
-
- return Context.getDependentVectorType(ElementType, SizeExpr, AttrLoc,
- (VectorType::VectorKind)VecKind);
- }
-
- case TYPE_DEPENDENT_SIZED_EXT_VECTOR: {
- unsigned Idx = 0;
-
- // DependentSizedExtVectorType
- QualType ElementType = readType(*Loc.F, Record, Idx);
- Expr *SizeExpr = ReadExpr(*Loc.F);
- SourceLocation AttrLoc = ReadSourceLocation(*Loc.F, Record, Idx);
-
- return Context.getDependentSizedExtVectorType(ElementType, SizeExpr,
- AttrLoc);
- }
-
- case TYPE_DEPENDENT_ADDRESS_SPACE: {
- unsigned Idx = 0;
-
- // DependentAddressSpaceType
- QualType PointeeType = readType(*Loc.F, Record, Idx);
- Expr *AddrSpaceExpr = ReadExpr(*Loc.F);
- SourceLocation AttrLoc = ReadSourceLocation(*Loc.F, Record, Idx);
-
- return Context.getDependentAddressSpaceType(PointeeType, AddrSpaceExpr,
- AttrLoc);
- }
+ auto maybeClass = getTypeClassForCode((TypeCode) Code.get());
+ if (!maybeClass) {
+ Error("Unexpected code for type");
+ return QualType();
}
- llvm_unreachable("Invalid TypeCode!");
-}
-void ASTReader::readExceptionSpec(ModuleFile &ModuleFile,
- SmallVectorImpl<QualType> &Exceptions,
- FunctionProtoType::ExceptionSpecInfo &ESI,
- const RecordData &Record, unsigned &Idx) {
- ExceptionSpecificationType EST =
- static_cast<ExceptionSpecificationType>(Record[Idx++]);
- ESI.Type = EST;
- if (EST == EST_Dynamic) {
- for (unsigned I = 0, N = Record[Idx++]; I != N; ++I)
- Exceptions.push_back(readType(ModuleFile, Record, Idx));
- ESI.Exceptions = Exceptions;
- } else if (isComputedNoexcept(EST)) {
- ESI.NoexceptExpr = ReadExpr(ModuleFile);
- } else if (EST == EST_Uninstantiated) {
- ESI.SourceDecl = ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx);
- ESI.SourceTemplate = ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx);
- } else if (EST == EST_Unevaluated) {
- ESI.SourceDecl = ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx);
- }
+ serialization::AbstractTypeReader<ASTRecordReader> TypeReader(Record);
+ return TypeReader.read(*maybeClass);
}
namespace clang {
class TypeLocReader : public TypeLocVisitor<TypeLocReader> {
- ModuleFile *F;
- ASTReader *Reader;
- const ASTReader::RecordData &Record;
- unsigned &Idx;
+ ASTRecordReader &Reader;
- SourceLocation ReadSourceLocation() {
- return Reader->ReadSourceLocation(*F, Record, Idx);
+ SourceLocation readSourceLocation() {
+ return Reader.readSourceLocation();
}
TypeSourceInfo *GetTypeSourceInfo() {
- return Reader->GetTypeSourceInfo(*F, Record, Idx);
+ return Reader.readTypeSourceInfo();
}
NestedNameSpecifierLoc ReadNestedNameSpecifierLoc() {
- return Reader->ReadNestedNameSpecifierLoc(*F, Record, Idx);
+ return Reader.readNestedNameSpecifierLoc();
}
Attr *ReadAttr() {
- return Reader->ReadAttr(*F, Record, Idx);
+ return Reader.readAttr();
}
public:
- TypeLocReader(ModuleFile &F, ASTReader &Reader,
- const ASTReader::RecordData &Record, unsigned &Idx)
- : F(&F), Reader(&Reader), Record(Record), Idx(Idx) {}
+ TypeLocReader(ASTRecordReader &Reader) : Reader(Reader) {}
// We want compile-time assurance that we've enumerated all of
// these, so unfortunately we have to declare them first, then
@@ -6957,21 +6425,21 @@ void TypeLocReader::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
}
void TypeLocReader::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
- TL.setBuiltinLoc(ReadSourceLocation());
+ TL.setBuiltinLoc(readSourceLocation());
if (TL.needsExtraLocalData()) {
- TL.setWrittenTypeSpec(static_cast<DeclSpec::TST>(Record[Idx++]));
- TL.setWrittenSignSpec(static_cast<DeclSpec::TSS>(Record[Idx++]));
- TL.setWrittenWidthSpec(static_cast<DeclSpec::TSW>(Record[Idx++]));
- TL.setModeAttr(Record[Idx++]);
+ TL.setWrittenTypeSpec(static_cast<DeclSpec::TST>(Reader.readInt()));
+ TL.setWrittenSignSpec(static_cast<DeclSpec::TSS>(Reader.readInt()));
+ TL.setWrittenWidthSpec(static_cast<DeclSpec::TSW>(Reader.readInt()));
+ TL.setModeAttr(Reader.readInt());
}
}
void TypeLocReader::VisitComplexTypeLoc(ComplexTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation());
+ TL.setNameLoc(readSourceLocation());
}
void TypeLocReader::VisitPointerTypeLoc(PointerTypeLoc TL) {
- TL.setStarLoc(ReadSourceLocation());
+ TL.setStarLoc(readSourceLocation());
}
void TypeLocReader::VisitDecayedTypeLoc(DecayedTypeLoc TL) {
@@ -6983,31 +6451,31 @@ void TypeLocReader::VisitAdjustedTypeLoc(AdjustedTypeLoc TL) {
}
void TypeLocReader::VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc TL) {
- TL.setExpansionLoc(ReadSourceLocation());
+ TL.setExpansionLoc(readSourceLocation());
}
void TypeLocReader::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
- TL.setCaretLoc(ReadSourceLocation());
+ TL.setCaretLoc(readSourceLocation());
}
void TypeLocReader::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) {
- TL.setAmpLoc(ReadSourceLocation());
+ TL.setAmpLoc(readSourceLocation());
}
void TypeLocReader::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) {
- TL.setAmpAmpLoc(ReadSourceLocation());
+ TL.setAmpAmpLoc(readSourceLocation());
}
void TypeLocReader::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
- TL.setStarLoc(ReadSourceLocation());
+ TL.setStarLoc(readSourceLocation());
TL.setClassTInfo(GetTypeSourceInfo());
}
void TypeLocReader::VisitArrayTypeLoc(ArrayTypeLoc TL) {
- TL.setLBracketLoc(ReadSourceLocation());
- TL.setRBracketLoc(ReadSourceLocation());
- if (Record[Idx++])
- TL.setSizeExpr(Reader->ReadExpr(*F));
+ TL.setLBracketLoc(readSourceLocation());
+ TL.setRBracketLoc(readSourceLocation());
+ if (Reader.readBool())
+ TL.setSizeExpr(Reader.readExpr());
else
TL.setSizeExpr(nullptr);
}
@@ -7032,41 +6500,37 @@ void TypeLocReader::VisitDependentSizedArrayTypeLoc(
void TypeLocReader::VisitDependentAddressSpaceTypeLoc(
DependentAddressSpaceTypeLoc TL) {
- TL.setAttrNameLoc(ReadSourceLocation());
- SourceRange range;
- range.setBegin(ReadSourceLocation());
- range.setEnd(ReadSourceLocation());
- TL.setAttrOperandParensRange(range);
- TL.setAttrExprOperand(Reader->ReadExpr(*F));
+ TL.setAttrNameLoc(readSourceLocation());
+ TL.setAttrOperandParensRange(Reader.readSourceRange());
+ TL.setAttrExprOperand(Reader.readExpr());
}
void TypeLocReader::VisitDependentSizedExtVectorTypeLoc(
DependentSizedExtVectorTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation());
+ TL.setNameLoc(readSourceLocation());
}
void TypeLocReader::VisitVectorTypeLoc(VectorTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation());
+ TL.setNameLoc(readSourceLocation());
}
void TypeLocReader::VisitDependentVectorTypeLoc(
DependentVectorTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation());
+ TL.setNameLoc(readSourceLocation());
}
void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation());
+ TL.setNameLoc(readSourceLocation());
}
void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
- TL.setLocalRangeBegin(ReadSourceLocation());
- TL.setLParenLoc(ReadSourceLocation());
- TL.setRParenLoc(ReadSourceLocation());
- TL.setExceptionSpecRange(SourceRange(Reader->ReadSourceLocation(*F, Record, Idx),
- Reader->ReadSourceLocation(*F, Record, Idx)));
- TL.setLocalRangeEnd(ReadSourceLocation());
+ TL.setLocalRangeBegin(readSourceLocation());
+ TL.setLParenLoc(readSourceLocation());
+ TL.setRParenLoc(readSourceLocation());
+ TL.setExceptionSpecRange(Reader.readSourceRange());
+ TL.setLocalRangeEnd(readSourceLocation());
for (unsigned i = 0, e = TL.getNumParams(); i != e; ++i) {
- TL.setParam(i, Reader->ReadDeclAs<ParmVarDecl>(*F, Record, Idx));
+ TL.setParam(i, Reader.readDeclAs<ParmVarDecl>());
}
}
@@ -7079,52 +6543,52 @@ void TypeLocReader::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) {
}
void TypeLocReader::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation());
+ TL.setNameLoc(readSourceLocation());
}
void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation());
+ TL.setNameLoc(readSourceLocation());
}
void TypeLocReader::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
- TL.setTypeofLoc(ReadSourceLocation());
- TL.setLParenLoc(ReadSourceLocation());
- TL.setRParenLoc(ReadSourceLocation());
+ TL.setTypeofLoc(readSourceLocation());
+ TL.setLParenLoc(readSourceLocation());
+ TL.setRParenLoc(readSourceLocation());
}
void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
- TL.setTypeofLoc(ReadSourceLocation());
- TL.setLParenLoc(ReadSourceLocation());
- TL.setRParenLoc(ReadSourceLocation());
+ TL.setTypeofLoc(readSourceLocation());
+ TL.setLParenLoc(readSourceLocation());
+ TL.setRParenLoc(readSourceLocation());
TL.setUnderlyingTInfo(GetTypeSourceInfo());
}
void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation());
+ TL.setNameLoc(readSourceLocation());
}
void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
- TL.setKWLoc(ReadSourceLocation());
- TL.setLParenLoc(ReadSourceLocation());
- TL.setRParenLoc(ReadSourceLocation());
+ TL.setKWLoc(readSourceLocation());
+ TL.setLParenLoc(readSourceLocation());
+ TL.setRParenLoc(readSourceLocation());
TL.setUnderlyingTInfo(GetTypeSourceInfo());
}
void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation());
+ TL.setNameLoc(readSourceLocation());
}
void TypeLocReader::VisitDeducedTemplateSpecializationTypeLoc(
DeducedTemplateSpecializationTypeLoc TL) {
- TL.setTemplateNameLoc(ReadSourceLocation());
+ TL.setTemplateNameLoc(readSourceLocation());
}
void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation());
+ TL.setNameLoc(readSourceLocation());
}
void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation());
+ TL.setNameLoc(readSourceLocation());
}
void TypeLocReader::VisitAttributedTypeLoc(AttributedTypeLoc TL) {
@@ -7132,126 +6596,123 @@ void TypeLocReader::VisitAttributedTypeLoc(AttributedTypeLoc TL) {
}
void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation());
+ TL.setNameLoc(readSourceLocation());
}
void TypeLocReader::VisitSubstTemplateTypeParmTypeLoc(
SubstTemplateTypeParmTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation());
+ TL.setNameLoc(readSourceLocation());
}
void TypeLocReader::VisitSubstTemplateTypeParmPackTypeLoc(
SubstTemplateTypeParmPackTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation());
+ TL.setNameLoc(readSourceLocation());
}
void TypeLocReader::VisitTemplateSpecializationTypeLoc(
TemplateSpecializationTypeLoc TL) {
- TL.setTemplateKeywordLoc(ReadSourceLocation());
- TL.setTemplateNameLoc(ReadSourceLocation());
- TL.setLAngleLoc(ReadSourceLocation());
- TL.setRAngleLoc(ReadSourceLocation());
+ TL.setTemplateKeywordLoc(readSourceLocation());
+ TL.setTemplateNameLoc(readSourceLocation());
+ TL.setLAngleLoc(readSourceLocation());
+ TL.setRAngleLoc(readSourceLocation());
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
TL.setArgLocInfo(
i,
- Reader->GetTemplateArgumentLocInfo(
- *F, TL.getTypePtr()->getArg(i).getKind(), Record, Idx));
+ Reader.readTemplateArgumentLocInfo(
+ TL.getTypePtr()->getArg(i).getKind()));
}
void TypeLocReader::VisitParenTypeLoc(ParenTypeLoc TL) {
- TL.setLParenLoc(ReadSourceLocation());
- TL.setRParenLoc(ReadSourceLocation());
+ TL.setLParenLoc(readSourceLocation());
+ TL.setRParenLoc(readSourceLocation());
}
void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
- TL.setElaboratedKeywordLoc(ReadSourceLocation());
+ TL.setElaboratedKeywordLoc(readSourceLocation());
TL.setQualifierLoc(ReadNestedNameSpecifierLoc());
}
void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation());
+ TL.setNameLoc(readSourceLocation());
}
void TypeLocReader::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
- TL.setElaboratedKeywordLoc(ReadSourceLocation());
+ TL.setElaboratedKeywordLoc(readSourceLocation());
TL.setQualifierLoc(ReadNestedNameSpecifierLoc());
- TL.setNameLoc(ReadSourceLocation());
+ TL.setNameLoc(readSourceLocation());
}
void TypeLocReader::VisitDependentTemplateSpecializationTypeLoc(
DependentTemplateSpecializationTypeLoc TL) {
- TL.setElaboratedKeywordLoc(ReadSourceLocation());
+ TL.setElaboratedKeywordLoc(readSourceLocation());
TL.setQualifierLoc(ReadNestedNameSpecifierLoc());
- TL.setTemplateKeywordLoc(ReadSourceLocation());
- TL.setTemplateNameLoc(ReadSourceLocation());
- TL.setLAngleLoc(ReadSourceLocation());
- TL.setRAngleLoc(ReadSourceLocation());
+ TL.setTemplateKeywordLoc(readSourceLocation());
+ TL.setTemplateNameLoc(readSourceLocation());
+ TL.setLAngleLoc(readSourceLocation());
+ TL.setRAngleLoc(readSourceLocation());
for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I)
TL.setArgLocInfo(
I,
- Reader->GetTemplateArgumentLocInfo(
- *F, TL.getTypePtr()->getArg(I).getKind(), Record, Idx));
+ Reader.readTemplateArgumentLocInfo(
+ TL.getTypePtr()->getArg(I).getKind()));
}
void TypeLocReader::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) {
- TL.setEllipsisLoc(ReadSourceLocation());
+ TL.setEllipsisLoc(readSourceLocation());
}
void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation());
+ TL.setNameLoc(readSourceLocation());
}
void TypeLocReader::VisitObjCTypeParamTypeLoc(ObjCTypeParamTypeLoc TL) {
if (TL.getNumProtocols()) {
- TL.setProtocolLAngleLoc(ReadSourceLocation());
- TL.setProtocolRAngleLoc(ReadSourceLocation());
+ TL.setProtocolLAngleLoc(readSourceLocation());
+ TL.setProtocolRAngleLoc(readSourceLocation());
}
for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i)
- TL.setProtocolLoc(i, ReadSourceLocation());
+ TL.setProtocolLoc(i, readSourceLocation());
}
void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
- TL.setHasBaseTypeAsWritten(Record[Idx++]);
- TL.setTypeArgsLAngleLoc(ReadSourceLocation());
- TL.setTypeArgsRAngleLoc(ReadSourceLocation());
+ TL.setHasBaseTypeAsWritten(Reader.readBool());
+ TL.setTypeArgsLAngleLoc(readSourceLocation());
+ TL.setTypeArgsRAngleLoc(readSourceLocation());
for (unsigned i = 0, e = TL.getNumTypeArgs(); i != e; ++i)
TL.setTypeArgTInfo(i, GetTypeSourceInfo());
- TL.setProtocolLAngleLoc(ReadSourceLocation());
- TL.setProtocolRAngleLoc(ReadSourceLocation());
+ TL.setProtocolLAngleLoc(readSourceLocation());
+ TL.setProtocolRAngleLoc(readSourceLocation());
for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i)
- TL.setProtocolLoc(i, ReadSourceLocation());
+ TL.setProtocolLoc(i, readSourceLocation());
}
void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
- TL.setStarLoc(ReadSourceLocation());
+ TL.setStarLoc(readSourceLocation());
}
void TypeLocReader::VisitAtomicTypeLoc(AtomicTypeLoc TL) {
- TL.setKWLoc(ReadSourceLocation());
- TL.setLParenLoc(ReadSourceLocation());
- TL.setRParenLoc(ReadSourceLocation());
+ TL.setKWLoc(readSourceLocation());
+ TL.setLParenLoc(readSourceLocation());
+ TL.setRParenLoc(readSourceLocation());
}
void TypeLocReader::VisitPipeTypeLoc(PipeTypeLoc TL) {
- TL.setKWLoc(ReadSourceLocation());
+ TL.setKWLoc(readSourceLocation());
}
-void ASTReader::ReadTypeLoc(ModuleFile &F, const ASTReader::RecordData &Record,
- unsigned &Idx, TypeLoc TL) {
- TypeLocReader TLR(F, *this, Record, Idx);
+void ASTRecordReader::readTypeLoc(TypeLoc TL) {
+ TypeLocReader TLR(*this);
for (; !TL.isNull(); TL = TL.getNextTypeLoc())
TLR.Visit(TL);
}
-TypeSourceInfo *
-ASTReader::GetTypeSourceInfo(ModuleFile &F, const ASTReader::RecordData &Record,
- unsigned &Idx) {
- QualType InfoTy = readType(F, Record, Idx);
+TypeSourceInfo *ASTRecordReader::readTypeSourceInfo() {
+ QualType InfoTy = readType();
if (InfoTy.isNull())
return nullptr;
TypeSourceInfo *TInfo = getContext().CreateTypeSourceInfo(InfoTy);
- ReadTypeLoc(F, Record, Idx, TInfo->getTypeLoc());
+ readTypeLoc(TInfo->getTypeLoc());
return TInfo;
}
@@ -7534,27 +6995,23 @@ ASTReader::getGlobalTypeID(ModuleFile &F, unsigned LocalID) const {
}
TemplateArgumentLocInfo
-ASTReader::GetTemplateArgumentLocInfo(ModuleFile &F,
- TemplateArgument::ArgKind Kind,
- const RecordData &Record,
- unsigned &Index) {
+ASTRecordReader::readTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind) {
switch (Kind) {
case TemplateArgument::Expression:
- return ReadExpr(F);
+ return readExpr();
case TemplateArgument::Type:
- return GetTypeSourceInfo(F, Record, Index);
+ return readTypeSourceInfo();
case TemplateArgument::Template: {
- NestedNameSpecifierLoc QualifierLoc = ReadNestedNameSpecifierLoc(F, Record,
- Index);
- SourceLocation TemplateNameLoc = ReadSourceLocation(F, Record, Index);
+ NestedNameSpecifierLoc QualifierLoc =
+ readNestedNameSpecifierLoc();
+ SourceLocation TemplateNameLoc = readSourceLocation();
return TemplateArgumentLocInfo(QualifierLoc, TemplateNameLoc,
SourceLocation());
}
case TemplateArgument::TemplateExpansion: {
- NestedNameSpecifierLoc QualifierLoc = ReadNestedNameSpecifierLoc(F, Record,
- Index);
- SourceLocation TemplateNameLoc = ReadSourceLocation(F, Record, Index);
- SourceLocation EllipsisLoc = ReadSourceLocation(F, Record, Index);
+ NestedNameSpecifierLoc QualifierLoc = readNestedNameSpecifierLoc();
+ SourceLocation TemplateNameLoc = readSourceLocation();
+ SourceLocation EllipsisLoc = readSourceLocation();
return TemplateArgumentLocInfo(QualifierLoc, TemplateNameLoc,
EllipsisLoc);
}
@@ -7569,29 +7026,24 @@ ASTReader::GetTemplateArgumentLocInfo(ModuleFile &F,
llvm_unreachable("unexpected template argument loc");
}
-TemplateArgumentLoc
-ASTReader::ReadTemplateArgumentLoc(ModuleFile &F,
- const RecordData &Record, unsigned &Index) {
- TemplateArgument Arg = ReadTemplateArgument(F, Record, Index);
+TemplateArgumentLoc ASTRecordReader::readTemplateArgumentLoc() {
+ TemplateArgument Arg = readTemplateArgument();
if (Arg.getKind() == TemplateArgument::Expression) {
- if (Record[Index++]) // bool InfoHasSameExpr.
+ if (readBool()) // bool InfoHasSameExpr.
return TemplateArgumentLoc(Arg, TemplateArgumentLocInfo(Arg.getAsExpr()));
}
- return TemplateArgumentLoc(Arg, GetTemplateArgumentLocInfo(F, Arg.getKind(),
- Record, Index));
+ return TemplateArgumentLoc(Arg, readTemplateArgumentLocInfo(Arg.getKind()));
}
-const ASTTemplateArgumentListInfo*
-ASTReader::ReadASTTemplateArgumentListInfo(ModuleFile &F,
- const RecordData &Record,
- unsigned &Index) {
- SourceLocation LAngleLoc = ReadSourceLocation(F, Record, Index);
- SourceLocation RAngleLoc = ReadSourceLocation(F, Record, Index);
- unsigned NumArgsAsWritten = Record[Index++];
+const ASTTemplateArgumentListInfo *
+ASTRecordReader::readASTTemplateArgumentListInfo() {
+ SourceLocation LAngleLoc = readSourceLocation();
+ SourceLocation RAngleLoc = readSourceLocation();
+ unsigned NumArgsAsWritten = readInt();
TemplateArgumentListInfo TemplArgsInfo(LAngleLoc, RAngleLoc);
for (unsigned i = 0; i != NumArgsAsWritten; ++i)
- TemplArgsInfo.addArgument(ReadTemplateArgumentLoc(F, Record, Index));
+ TemplArgsInfo.addArgument(readTemplateArgumentLoc());
return ASTTemplateArgumentListInfo::Create(getContext(), TemplArgsInfo);
}
@@ -7662,7 +7114,6 @@ ASTReader::GetExternalCXXCtorInitializers(uint64_t Offset) {
}
ReadingKindTracker ReadingKind(Read_Decl, *this);
- RecordData Record;
Expected<unsigned> MaybeCode = Cursor.ReadCode();
if (!MaybeCode) {
Error(MaybeCode.takeError());
@@ -7670,7 +7121,8 @@ ASTReader::GetExternalCXXCtorInitializers(uint64_t Offset) {
}
unsigned Code = MaybeCode.get();
- Expected<unsigned> MaybeRecCode = Cursor.readRecord(Code, Record);
+ ASTRecordReader Record(*this, *Loc.F);
+ Expected<unsigned> MaybeRecCode = Record.readRecord(Cursor, Code);
if (!MaybeRecCode) {
Error(MaybeRecCode.takeError());
return nullptr;
@@ -7680,8 +7132,7 @@ ASTReader::GetExternalCXXCtorInitializers(uint64_t Offset) {
return nullptr;
}
- unsigned Idx = 0;
- return ReadCXXCtorInitializers(*Loc.F, Record, Idx);
+ return Record.readCXXCtorInitializers();
}
CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
@@ -7696,7 +7147,6 @@ CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
return nullptr;
}
ReadingKindTracker ReadingKind(Read_Decl, *this);
- RecordData Record;
Expected<unsigned> MaybeCode = Cursor.ReadCode();
if (!MaybeCode) {
@@ -7705,7 +7155,8 @@ CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
}
unsigned Code = MaybeCode.get();
- Expected<unsigned> MaybeRecCode = Cursor.readRecord(Code, Record);
+ ASTRecordReader Record(*this, *Loc.F);
+ Expected<unsigned> MaybeRecCode = Record.readRecord(Cursor, Code);
if (!MaybeRecCode) {
Error(MaybeCode.takeError());
return nullptr;
@@ -7717,12 +7168,11 @@ CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
return nullptr;
}
- unsigned Idx = 0;
- unsigned NumBases = Record[Idx++];
+ unsigned NumBases = Record.readInt();
void *Mem = Context.Allocate(sizeof(CXXBaseSpecifier) * NumBases);
CXXBaseSpecifier *Bases = new (Mem) CXXBaseSpecifier [NumBases];
for (unsigned I = 0; I != NumBases; ++I)
- Bases[I] = ReadCXXBaseSpecifier(*Loc.F, Record, Idx);
+ Bases[I] = Record.readCXXBaseSpecifier();
return Bases;
}
@@ -9112,72 +8562,26 @@ ASTReader::getGlobalSelectorID(ModuleFile &M, unsigned LocalID) const {
return LocalID + I->second;
}
-DeclarationName
-ASTReader::ReadDeclarationName(ModuleFile &F,
- const RecordData &Record, unsigned &Idx) {
- ASTContext &Context = getContext();
- DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++];
- switch (Kind) {
- case DeclarationName::Identifier:
- return DeclarationName(GetIdentifierInfo(F, Record, Idx));
-
- case DeclarationName::ObjCZeroArgSelector:
- case DeclarationName::ObjCOneArgSelector:
- case DeclarationName::ObjCMultiArgSelector:
- return DeclarationName(ReadSelector(F, Record, Idx));
-
- case DeclarationName::CXXConstructorName:
- return Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(readType(F, Record, Idx)));
-
- case DeclarationName::CXXDestructorName:
- return Context.DeclarationNames.getCXXDestructorName(
- Context.getCanonicalType(readType(F, Record, Idx)));
-
- case DeclarationName::CXXDeductionGuideName:
- return Context.DeclarationNames.getCXXDeductionGuideName(
- ReadDeclAs<TemplateDecl>(F, Record, Idx));
-
- case DeclarationName::CXXConversionFunctionName:
- return Context.DeclarationNames.getCXXConversionFunctionName(
- Context.getCanonicalType(readType(F, Record, Idx)));
-
- case DeclarationName::CXXOperatorName:
- return Context.DeclarationNames.getCXXOperatorName(
- (OverloadedOperatorKind)Record[Idx++]);
-
- case DeclarationName::CXXLiteralOperatorName:
- return Context.DeclarationNames.getCXXLiteralOperatorName(
- GetIdentifierInfo(F, Record, Idx));
-
- case DeclarationName::CXXUsingDirective:
- return DeclarationName::getUsingDirectiveName();
- }
-
- llvm_unreachable("Invalid NameKind!");
-}
-
-void ASTReader::ReadDeclarationNameLoc(ModuleFile &F,
- DeclarationNameLoc &DNLoc,
- DeclarationName Name,
- const RecordData &Record, unsigned &Idx) {
+DeclarationNameLoc
+ASTRecordReader::readDeclarationNameLoc(DeclarationName Name) {
+ DeclarationNameLoc DNLoc;
switch (Name.getNameKind()) {
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
- DNLoc.NamedType.TInfo = GetTypeSourceInfo(F, Record, Idx);
+ DNLoc.NamedType.TInfo = readTypeSourceInfo();
break;
case DeclarationName::CXXOperatorName:
DNLoc.CXXOperatorName.BeginOpNameLoc
- = ReadSourceLocation(F, Record, Idx).getRawEncoding();
+ = readSourceLocation().getRawEncoding();
DNLoc.CXXOperatorName.EndOpNameLoc
- = ReadSourceLocation(F, Record, Idx).getRawEncoding();
+ = readSourceLocation().getRawEncoding();
break;
case DeclarationName::CXXLiteralOperatorName:
DNLoc.CXXLiteralOperatorName.OpNameLoc
- = ReadSourceLocation(F, Record, Idx).getRawEncoding();
+ = readSourceLocation().getRawEncoding();
break;
case DeclarationName::Identifier:
@@ -9188,204 +8592,78 @@ void ASTReader::ReadDeclarationNameLoc(ModuleFile &F,
case DeclarationName::CXXDeductionGuideName:
break;
}
+ return DNLoc;
}
-void ASTReader::ReadDeclarationNameInfo(ModuleFile &F,
- DeclarationNameInfo &NameInfo,
- const RecordData &Record, unsigned &Idx) {
- NameInfo.setName(ReadDeclarationName(F, Record, Idx));
- NameInfo.setLoc(ReadSourceLocation(F, Record, Idx));
- DeclarationNameLoc DNLoc;
- ReadDeclarationNameLoc(F, DNLoc, NameInfo.getName(), Record, Idx);
- NameInfo.setInfo(DNLoc);
+DeclarationNameInfo ASTRecordReader::readDeclarationNameInfo() {
+ DeclarationNameInfo NameInfo;
+ NameInfo.setName(readDeclarationName());
+ NameInfo.setLoc(readSourceLocation());
+ NameInfo.setInfo(readDeclarationNameLoc(NameInfo.getName()));
+ return NameInfo;
}
-void ASTReader::ReadQualifierInfo(ModuleFile &F, QualifierInfo &Info,
- const RecordData &Record, unsigned &Idx) {
- Info.QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, Idx);
- unsigned NumTPLists = Record[Idx++];
+void ASTRecordReader::readQualifierInfo(QualifierInfo &Info) {
+ Info.QualifierLoc = readNestedNameSpecifierLoc();
+ unsigned NumTPLists = readInt();
Info.NumTemplParamLists = NumTPLists;
if (NumTPLists) {
Info.TemplParamLists =
new (getContext()) TemplateParameterList *[NumTPLists];
for (unsigned i = 0; i != NumTPLists; ++i)
- Info.TemplParamLists[i] = ReadTemplateParameterList(F, Record, Idx);
- }
-}
-
-TemplateName
-ASTReader::ReadTemplateName(ModuleFile &F, const RecordData &Record,
- unsigned &Idx) {
- ASTContext &Context = getContext();
- TemplateName::NameKind Kind = (TemplateName::NameKind)Record[Idx++];
- switch (Kind) {
- case TemplateName::Template:
- return TemplateName(ReadDeclAs<TemplateDecl>(F, Record, Idx));
-
- case TemplateName::OverloadedTemplate: {
- unsigned size = Record[Idx++];
- UnresolvedSet<8> Decls;
- while (size--)
- Decls.addDecl(ReadDeclAs<NamedDecl>(F, Record, Idx));
-
- return Context.getOverloadedTemplateName(Decls.begin(), Decls.end());
- }
-
- case TemplateName::AssumedTemplate: {
- DeclarationName Name = ReadDeclarationName(F, Record, Idx);
- return Context.getAssumedTemplateName(Name);
- }
-
- case TemplateName::QualifiedTemplate: {
- NestedNameSpecifier *NNS = ReadNestedNameSpecifier(F, Record, Idx);
- bool hasTemplKeyword = Record[Idx++];
- TemplateDecl *Template = ReadDeclAs<TemplateDecl>(F, Record, Idx);
- return Context.getQualifiedTemplateName(NNS, hasTemplKeyword, Template);
- }
-
- case TemplateName::DependentTemplate: {
- NestedNameSpecifier *NNS = ReadNestedNameSpecifier(F, Record, Idx);
- if (Record[Idx++]) // isIdentifier
- return Context.getDependentTemplateName(NNS,
- GetIdentifierInfo(F, Record,
- Idx));
- return Context.getDependentTemplateName(NNS,
- (OverloadedOperatorKind)Record[Idx++]);
- }
-
- case TemplateName::SubstTemplateTemplateParm: {
- TemplateTemplateParmDecl *param
- = ReadDeclAs<TemplateTemplateParmDecl>(F, Record, Idx);
- if (!param) return TemplateName();
- TemplateName replacement = ReadTemplateName(F, Record, Idx);
- return Context.getSubstTemplateTemplateParm(param, replacement);
- }
-
- case TemplateName::SubstTemplateTemplateParmPack: {
- TemplateTemplateParmDecl *Param
- = ReadDeclAs<TemplateTemplateParmDecl>(F, Record, Idx);
- if (!Param)
- return TemplateName();
-
- TemplateArgument ArgPack = ReadTemplateArgument(F, Record, Idx);
- if (ArgPack.getKind() != TemplateArgument::Pack)
- return TemplateName();
-
- return Context.getSubstTemplateTemplateParmPack(Param, ArgPack);
- }
- }
-
- llvm_unreachable("Unhandled template name kind!");
-}
-
-TemplateArgument ASTReader::ReadTemplateArgument(ModuleFile &F,
- const RecordData &Record,
- unsigned &Idx,
- bool Canonicalize) {
- ASTContext &Context = getContext();
- if (Canonicalize) {
- // The caller wants a canonical template argument. Sometimes the AST only
- // wants template arguments in canonical form (particularly as the template
- // argument lists of template specializations) so ensure we preserve that
- // canonical form across serialization.
- TemplateArgument Arg = ReadTemplateArgument(F, Record, Idx, false);
- return Context.getCanonicalTemplateArgument(Arg);
- }
-
- TemplateArgument::ArgKind Kind = (TemplateArgument::ArgKind)Record[Idx++];
- switch (Kind) {
- case TemplateArgument::Null:
- return TemplateArgument();
- case TemplateArgument::Type:
- return TemplateArgument(readType(F, Record, Idx));
- case TemplateArgument::Declaration: {
- ValueDecl *D = ReadDeclAs<ValueDecl>(F, Record, Idx);
- return TemplateArgument(D, readType(F, Record, Idx));
- }
- case TemplateArgument::NullPtr:
- return TemplateArgument(readType(F, Record, Idx), /*isNullPtr*/true);
- case TemplateArgument::Integral: {
- llvm::APSInt Value = ReadAPSInt(Record, Idx);
- QualType T = readType(F, Record, Idx);
- return TemplateArgument(Context, Value, T);
- }
- case TemplateArgument::Template:
- return TemplateArgument(ReadTemplateName(F, Record, Idx));
- case TemplateArgument::TemplateExpansion: {
- TemplateName Name = ReadTemplateName(F, Record, Idx);
- Optional<unsigned> NumTemplateExpansions;
- if (unsigned NumExpansions = Record[Idx++])
- NumTemplateExpansions = NumExpansions - 1;
- return TemplateArgument(Name, NumTemplateExpansions);
+ Info.TemplParamLists[i] = readTemplateParameterList();
}
- case TemplateArgument::Expression:
- return TemplateArgument(ReadExpr(F));
- case TemplateArgument::Pack: {
- unsigned NumArgs = Record[Idx++];
- TemplateArgument *Args = new (Context) TemplateArgument[NumArgs];
- for (unsigned I = 0; I != NumArgs; ++I)
- Args[I] = ReadTemplateArgument(F, Record, Idx);
- return TemplateArgument(llvm::makeArrayRef(Args, NumArgs));
- }
- }
-
- llvm_unreachable("Unhandled template argument kind!");
}
TemplateParameterList *
-ASTReader::ReadTemplateParameterList(ModuleFile &F,
- const RecordData &Record, unsigned &Idx) {
- SourceLocation TemplateLoc = ReadSourceLocation(F, Record, Idx);
- SourceLocation LAngleLoc = ReadSourceLocation(F, Record, Idx);
- SourceLocation RAngleLoc = ReadSourceLocation(F, Record, Idx);
+ASTRecordReader::readTemplateParameterList() {
+ SourceLocation TemplateLoc = readSourceLocation();
+ SourceLocation LAngleLoc = readSourceLocation();
+ SourceLocation RAngleLoc = readSourceLocation();
- unsigned NumParams = Record[Idx++];
+ unsigned NumParams = readInt();
SmallVector<NamedDecl *, 16> Params;
Params.reserve(NumParams);
while (NumParams--)
- Params.push_back(ReadDeclAs<NamedDecl>(F, Record, Idx));
+ Params.push_back(readDeclAs<NamedDecl>());
- bool HasRequiresClause = Record[Idx++];
- Expr *RequiresClause = HasRequiresClause ? ReadExpr(F) : nullptr;
+ bool HasRequiresClause = readBool();
+ Expr *RequiresClause = HasRequiresClause ? readExpr() : nullptr;
TemplateParameterList *TemplateParams = TemplateParameterList::Create(
getContext(), TemplateLoc, LAngleLoc, Params, RAngleLoc, RequiresClause);
return TemplateParams;
}
-void
-ASTReader::
-ReadTemplateArgumentList(SmallVectorImpl<TemplateArgument> &TemplArgs,
- ModuleFile &F, const RecordData &Record,
- unsigned &Idx, bool Canonicalize) {
- unsigned NumTemplateArgs = Record[Idx++];
+void ASTRecordReader::readTemplateArgumentList(
+ SmallVectorImpl<TemplateArgument> &TemplArgs,
+ bool Canonicalize) {
+ unsigned NumTemplateArgs = readInt();
TemplArgs.reserve(NumTemplateArgs);
while (NumTemplateArgs--)
- TemplArgs.push_back(ReadTemplateArgument(F, Record, Idx, Canonicalize));
+ TemplArgs.push_back(readTemplateArgument(Canonicalize));
}
/// Read a UnresolvedSet structure.
-void ASTReader::ReadUnresolvedSet(ModuleFile &F, LazyASTUnresolvedSet &Set,
- const RecordData &Record, unsigned &Idx) {
- unsigned NumDecls = Record[Idx++];
+void ASTRecordReader::readUnresolvedSet(LazyASTUnresolvedSet &Set) {
+ unsigned NumDecls = readInt();
Set.reserve(getContext(), NumDecls);
while (NumDecls--) {
- DeclID ID = ReadDeclID(F, Record, Idx);
- AccessSpecifier AS = (AccessSpecifier)Record[Idx++];
+ DeclID ID = readDeclID();
+ AccessSpecifier AS = (AccessSpecifier) readInt();
Set.addLazyDecl(getContext(), ID, AS);
}
}
CXXBaseSpecifier
-ASTReader::ReadCXXBaseSpecifier(ModuleFile &F,
- const RecordData &Record, unsigned &Idx) {
- bool isVirtual = static_cast<bool>(Record[Idx++]);
- bool isBaseOfClass = static_cast<bool>(Record[Idx++]);
- AccessSpecifier AS = static_cast<AccessSpecifier>(Record[Idx++]);
- bool inheritConstructors = static_cast<bool>(Record[Idx++]);
- TypeSourceInfo *TInfo = GetTypeSourceInfo(F, Record, Idx);
- SourceRange Range = ReadSourceRange(F, Record, Idx);
- SourceLocation EllipsisLoc = ReadSourceLocation(F, Record, Idx);
+ASTRecordReader::readCXXBaseSpecifier() {
+ bool isVirtual = readBool();
+ bool isBaseOfClass = readBool();
+ AccessSpecifier AS = static_cast<AccessSpecifier>(readInt());
+ bool inheritConstructors = readBool();
+ TypeSourceInfo *TInfo = readTypeSourceInfo();
+ SourceRange Range = readSourceRange();
+ SourceLocation EllipsisLoc = readSourceLocation();
CXXBaseSpecifier Result(Range, isVirtual, isBaseOfClass, AS, TInfo,
EllipsisLoc);
Result.setInheritConstructors(inheritConstructors);
@@ -9393,10 +8671,9 @@ ASTReader::ReadCXXBaseSpecifier(ModuleFile &F,
}
CXXCtorInitializer **
-ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record,
- unsigned &Idx) {
+ASTRecordReader::readCXXCtorInitializers() {
ASTContext &Context = getContext();
- unsigned NumInitializers = Record[Idx++];
+ unsigned NumInitializers = readInt();
assert(NumInitializers && "wrote ctor initializers but have no inits");
auto **CtorInitializers = new (Context) CXXCtorInitializer*[NumInitializers];
for (unsigned i = 0; i != NumInitializers; ++i) {
@@ -9405,30 +8682,30 @@ ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record,
FieldDecl *Member = nullptr;
IndirectFieldDecl *IndirectMember = nullptr;
- CtorInitializerType Type = (CtorInitializerType)Record[Idx++];
+ CtorInitializerType Type = (CtorInitializerType) readInt();
switch (Type) {
case CTOR_INITIALIZER_BASE:
- TInfo = GetTypeSourceInfo(F, Record, Idx);
- IsBaseVirtual = Record[Idx++];
+ TInfo = readTypeSourceInfo();
+ IsBaseVirtual = readBool();
break;
case CTOR_INITIALIZER_DELEGATING:
- TInfo = GetTypeSourceInfo(F, Record, Idx);
+ TInfo = readTypeSourceInfo();
break;
case CTOR_INITIALIZER_MEMBER:
- Member = ReadDeclAs<FieldDecl>(F, Record, Idx);
+ Member = readDeclAs<FieldDecl>();
break;
case CTOR_INITIALIZER_INDIRECT_MEMBER:
- IndirectMember = ReadDeclAs<IndirectFieldDecl>(F, Record, Idx);
+ IndirectMember = readDeclAs<IndirectFieldDecl>();
break;
}
- SourceLocation MemberOrEllipsisLoc = ReadSourceLocation(F, Record, Idx);
- Expr *Init = ReadExpr(F);
- SourceLocation LParenLoc = ReadSourceLocation(F, Record, Idx);
- SourceLocation RParenLoc = ReadSourceLocation(F, Record, Idx);
+ SourceLocation MemberOrEllipsisLoc = readSourceLocation();
+ Expr *Init = readExpr();
+ SourceLocation LParenLoc = readSourceLocation();
+ SourceLocation RParenLoc = readSourceLocation();
CXXCtorInitializer *BOMInit;
if (Type == CTOR_INITIALIZER_BASE)
@@ -9447,8 +8724,8 @@ ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record,
CXXCtorInitializer(Context, IndirectMember, MemberOrEllipsisLoc,
LParenLoc, Init, RParenLoc);
- if (/*IsWritten*/Record[Idx++]) {
- unsigned SourceOrder = Record[Idx++];
+ if (/*IsWritten*/readBool()) {
+ unsigned SourceOrder = readInt();
BOMInit->setSourceOrder(SourceOrder);
}
@@ -9458,99 +8735,42 @@ ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record,
return CtorInitializers;
}
-NestedNameSpecifier *
-ASTReader::ReadNestedNameSpecifier(ModuleFile &F,
- const RecordData &Record, unsigned &Idx) {
- ASTContext &Context = getContext();
- unsigned N = Record[Idx++];
- NestedNameSpecifier *NNS = nullptr, *Prev = nullptr;
- for (unsigned I = 0; I != N; ++I) {
- NestedNameSpecifier::SpecifierKind Kind
- = (NestedNameSpecifier::SpecifierKind)Record[Idx++];
- switch (Kind) {
- case NestedNameSpecifier::Identifier: {
- IdentifierInfo *II = GetIdentifierInfo(F, Record, Idx);
- NNS = NestedNameSpecifier::Create(Context, Prev, II);
- break;
- }
-
- case NestedNameSpecifier::Namespace: {
- NamespaceDecl *NS = ReadDeclAs<NamespaceDecl>(F, Record, Idx);
- NNS = NestedNameSpecifier::Create(Context, Prev, NS);
- break;
- }
-
- case NestedNameSpecifier::NamespaceAlias: {
- NamespaceAliasDecl *Alias =ReadDeclAs<NamespaceAliasDecl>(F, Record, Idx);
- NNS = NestedNameSpecifier::Create(Context, Prev, Alias);
- break;
- }
-
- case NestedNameSpecifier::TypeSpec:
- case NestedNameSpecifier::TypeSpecWithTemplate: {
- const Type *T = readType(F, Record, Idx).getTypePtrOrNull();
- if (!T)
- return nullptr;
-
- bool Template = Record[Idx++];
- NNS = NestedNameSpecifier::Create(Context, Prev, Template, T);
- break;
- }
-
- case NestedNameSpecifier::Global:
- NNS = NestedNameSpecifier::GlobalSpecifier(Context);
- // No associated value, and there can't be a prefix.
- break;
-
- case NestedNameSpecifier::Super: {
- CXXRecordDecl *RD = ReadDeclAs<CXXRecordDecl>(F, Record, Idx);
- NNS = NestedNameSpecifier::SuperSpecifier(Context, RD);
- break;
- }
- }
- Prev = NNS;
- }
- return NNS;
-}
-
NestedNameSpecifierLoc
-ASTReader::ReadNestedNameSpecifierLoc(ModuleFile &F, const RecordData &Record,
- unsigned &Idx) {
+ASTRecordReader::readNestedNameSpecifierLoc() {
ASTContext &Context = getContext();
- unsigned N = Record[Idx++];
+ unsigned N = readInt();
NestedNameSpecifierLocBuilder Builder;
for (unsigned I = 0; I != N; ++I) {
- NestedNameSpecifier::SpecifierKind Kind
- = (NestedNameSpecifier::SpecifierKind)Record[Idx++];
+ auto Kind = readNestedNameSpecifierKind();
switch (Kind) {
case NestedNameSpecifier::Identifier: {
- IdentifierInfo *II = GetIdentifierInfo(F, Record, Idx);
- SourceRange Range = ReadSourceRange(F, Record, Idx);
+ IdentifierInfo *II = readIdentifier();
+ SourceRange Range = readSourceRange();
Builder.Extend(Context, II, Range.getBegin(), Range.getEnd());
break;
}
case NestedNameSpecifier::Namespace: {
- NamespaceDecl *NS = ReadDeclAs<NamespaceDecl>(F, Record, Idx);
- SourceRange Range = ReadSourceRange(F, Record, Idx);
+ NamespaceDecl *NS = readDeclAs<NamespaceDecl>();
+ SourceRange Range = readSourceRange();
Builder.Extend(Context, NS, Range.getBegin(), Range.getEnd());
break;
}
case NestedNameSpecifier::NamespaceAlias: {
- NamespaceAliasDecl *Alias =ReadDeclAs<NamespaceAliasDecl>(F, Record, Idx);
- SourceRange Range = ReadSourceRange(F, Record, Idx);
+ NamespaceAliasDecl *Alias = readDeclAs<NamespaceAliasDecl>();
+ SourceRange Range = readSourceRange();
Builder.Extend(Context, Alias, Range.getBegin(), Range.getEnd());
break;
}
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
- bool Template = Record[Idx++];
- TypeSourceInfo *T = GetTypeSourceInfo(F, Record, Idx);
+ bool Template = readBool();
+ TypeSourceInfo *T = readTypeSourceInfo();
if (!T)
return NestedNameSpecifierLoc();
- SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx);
+ SourceLocation ColonColonLoc = readSourceLocation();
// FIXME: 'template' keyword location not saved anywhere, so we fake it.
Builder.Extend(Context,
@@ -9560,14 +8780,14 @@ ASTReader::ReadNestedNameSpecifierLoc(ModuleFile &F, const RecordData &Record,
}
case NestedNameSpecifier::Global: {
- SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx);
+ SourceLocation ColonColonLoc = readSourceLocation();
Builder.MakeGlobal(Context, ColonColonLoc);
break;
}
case NestedNameSpecifier::Super: {
- CXXRecordDecl *RD = ReadDeclAs<CXXRecordDecl>(F, Record, Idx);
- SourceRange Range = ReadSourceRange(F, Record, Idx);
+ CXXRecordDecl *RD = readDeclAs<CXXRecordDecl>();
+ SourceRange Range = readSourceRange();
Builder.MakeSuper(Context, RD, Range.getBegin(), Range.getEnd());
break;
}
@@ -9598,35 +8818,38 @@ ReadFixedPointSemantics(const SmallVectorImpl<uint64_t> &Record,
HasUnsignedPadding);
}
-APValue ASTReader::ReadAPValue(const RecordData &Record, unsigned &Idx) {
- unsigned Kind = Record[Idx++];
- switch (Kind) {
+static const llvm::fltSemantics &
+readAPFloatSemantics(ASTRecordReader &reader) {
+ return llvm::APFloatBase::EnumToSemantics(
+ static_cast<llvm::APFloatBase::Semantics>(reader.readInt()));
+}
+
+APValue ASTRecordReader::readAPValue() {
+ unsigned Kind = readInt();
+ switch ((APValue::ValueKind) Kind) {
case APValue::None:
return APValue();
case APValue::Indeterminate:
return APValue::IndeterminateValue();
case APValue::Int:
- return APValue(ReadAPSInt(Record, Idx));
+ return APValue(readAPSInt());
case APValue::Float: {
- const llvm::fltSemantics &FloatSema = llvm::APFloatBase::EnumToSemantics(
- static_cast<llvm::APFloatBase::Semantics>(Record[Idx++]));
- return APValue(ReadAPFloat(Record, FloatSema, Idx));
+ const llvm::fltSemantics &FloatSema = readAPFloatSemantics(*this);
+ return APValue(readAPFloat(FloatSema));
}
case APValue::FixedPoint: {
FixedPointSemantics FPSema = ReadFixedPointSemantics(Record, Idx);
- return APValue(APFixedPoint(ReadAPInt(Record, Idx), FPSema));
+ return APValue(APFixedPoint(readAPInt(), FPSema));
}
case APValue::ComplexInt: {
- llvm::APSInt First = ReadAPSInt(Record, Idx);
- return APValue(std::move(First), ReadAPSInt(Record, Idx));
+ llvm::APSInt First = readAPSInt();
+ return APValue(std::move(First), readAPSInt());
}
case APValue::ComplexFloat: {
- const llvm::fltSemantics &FloatSema1 = llvm::APFloatBase::EnumToSemantics(
- static_cast<llvm::APFloatBase::Semantics>(Record[Idx++]));
- llvm::APFloat First = ReadAPFloat(Record, FloatSema1, Idx);
- const llvm::fltSemantics &FloatSema2 = llvm::APFloatBase::EnumToSemantics(
- static_cast<llvm::APFloatBase::Semantics>(Record[Idx++]));
- return APValue(std::move(First), ReadAPFloat(Record, FloatSema2, Idx));
+ const llvm::fltSemantics &FloatSema1 = readAPFloatSemantics(*this);
+ llvm::APFloat First = readAPFloat(FloatSema1);
+ const llvm::fltSemantics &FloatSema2 = readAPFloatSemantics(*this);
+ return APValue(std::move(First), readAPFloat(FloatSema2));
}
case APValue::LValue:
case APValue::Vector:
@@ -9641,26 +8864,9 @@ APValue ASTReader::ReadAPValue(const RecordData &Record, unsigned &Idx) {
llvm_unreachable("Invalid APValue::ValueKind");
}
-/// Read an integral value
-llvm::APInt ASTReader::ReadAPInt(const RecordData &Record, unsigned &Idx) {
- unsigned BitWidth = Record[Idx++];
- unsigned NumWords = llvm::APInt::getNumWords(BitWidth);
- llvm::APInt Result(BitWidth, NumWords, &Record[Idx]);
- Idx += NumWords;
- return Result;
-}
-
-/// Read a signed integral value
-llvm::APSInt ASTReader::ReadAPSInt(const RecordData &Record, unsigned &Idx) {
- bool isUnsigned = Record[Idx++];
- return llvm::APSInt(ReadAPInt(Record, Idx), isUnsigned);
-}
-
/// Read a floating-point value
-llvm::APFloat ASTReader::ReadAPFloat(const RecordData &Record,
- const llvm::fltSemantics &Sem,
- unsigned &Idx) {
- return llvm::APFloat(Sem, ReadAPInt(Record, Idx));
+llvm::APFloat ASTRecordReader::readAPFloat(const llvm::fltSemantics &Sem) {
+ return llvm::APFloat(Sem, readAPInt());
}
// Read a string
@@ -10888,14 +10094,22 @@ void ASTReader::diagnoseOdrViolations() {
}
if (IsFirstBitField && IsSecondBitField) {
- ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(),
- FieldDifferentWidthBitField)
- << FirstII << FirstField->getBitWidth()->getSourceRange();
- ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(),
- FieldDifferentWidthBitField)
- << SecondII << SecondField->getBitWidth()->getSourceRange();
- Diagnosed = true;
- break;
+ unsigned FirstBitWidthHash =
+ ComputeODRHash(FirstField->getBitWidth());
+ unsigned SecondBitWidthHash =
+ ComputeODRHash(SecondField->getBitWidth());
+ if (FirstBitWidthHash != SecondBitWidthHash) {
+ ODRDiagError(FirstField->getLocation(),
+ FirstField->getSourceRange(),
+ FieldDifferentWidthBitField)
+ << FirstII << FirstField->getBitWidth()->getSourceRange();
+ ODRDiagNote(SecondField->getLocation(),
+ SecondField->getSourceRange(),
+ FieldDifferentWidthBitField)
+ << SecondII << SecondField->getBitWidth()->getSourceRange();
+ Diagnosed = true;
+ break;
+ }
}
const bool IsFirstMutable = FirstField->isMutable();
@@ -12268,6 +11482,31 @@ Expected<unsigned> ASTRecordReader::readRecord(llvm::BitstreamCursor &Cursor,
//// OMPClauseReader implementation
////===----------------------------------------------------------------------===//
+// This has to be in namespace clang because it's friended by all
+// of the OMP clauses.
+namespace clang {
+
+class OMPClauseReader : public OMPClauseVisitor<OMPClauseReader> {
+ ASTRecordReader &Record;
+ ASTContext &Context;
+
+public:
+ OMPClauseReader(ASTRecordReader &Record)
+ : Record(Record), Context(Record.getContext()) {}
+
+#define OPENMP_CLAUSE(Name, Class) void Visit##Class(Class *C);
+#include "clang/Basic/OpenMPKinds.def"
+ OMPClause *readClause();
+ void VisitOMPClauseWithPreInit(OMPClauseWithPreInit *C);
+ void VisitOMPClauseWithPostUpdate(OMPClauseWithPostUpdate *C);
+};
+
+} // end namespace clang
+
+OMPClause *ASTRecordReader::readOMPClause() {
+ return OMPClauseReader(*this).readClause();
+}
+
OMPClause *OMPClauseReader::readClause() {
OMPClause *C = nullptr;
switch (Record.readInt()) {
@@ -12469,6 +11708,9 @@ OMPClause *OMPClauseReader::readClause() {
case OMPC_allocate:
C = OMPAllocateClause::CreateEmpty(Context, Record.readInt());
break;
+ case OMPC_nontemporal:
+ C = OMPNontemporalClause::CreateEmpty(Context, Record.readInt());
+ break;
}
assert(C && "Unknown OMPClause type");
@@ -12538,8 +11780,7 @@ void OMPClauseReader::VisitOMPDefaultClause(OMPDefaultClause *C) {
}
void OMPClauseReader::VisitOMPProcBindClause(OMPProcBindClause *C) {
- C->setProcBindKind(
- static_cast<OpenMPProcBindClauseKind>(Record.readInt()));
+ C->setProcBindKind(static_cast<llvm::omp::ProcBindKind>(Record.readInt()));
C->setLParenLoc(Record.readSourceLocation());
C->setProcBindKindKwLoc(Record.readSourceLocation());
}
@@ -12646,6 +11887,9 @@ void OMPClauseReader::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
void OMPClauseReader::VisitOMPLastprivateClause(OMPLastprivateClause *C) {
VisitOMPClauseWithPostUpdate(C);
C->setLParenLoc(Record.readSourceLocation());
+ C->setKind(Record.readEnum<OpenMPLastprivateModifier>());
+ C->setKindLoc(Record.readSourceLocation());
+ C->setColonLoc(Record.readSourceLocation());
unsigned NumVars = C->varlist_size();
SmallVector<Expr *, 16> Vars;
Vars.reserve(NumVars);
@@ -12685,8 +11929,7 @@ void OMPClauseReader::VisitOMPReductionClause(OMPReductionClause *C) {
C->setLParenLoc(Record.readSourceLocation());
C->setColonLoc(Record.readSourceLocation());
NestedNameSpecifierLoc NNSL = Record.readNestedNameSpecifierLoc();
- DeclarationNameInfo DNI;
- Record.readDeclarationNameInfo(DNI);
+ DeclarationNameInfo DNI = Record.readDeclarationNameInfo();
C->setQualifierLoc(NNSL);
C->setNameInfo(DNI);
@@ -12719,8 +11962,7 @@ void OMPClauseReader::VisitOMPTaskReductionClause(OMPTaskReductionClause *C) {
C->setLParenLoc(Record.readSourceLocation());
C->setColonLoc(Record.readSourceLocation());
NestedNameSpecifierLoc NNSL = Record.readNestedNameSpecifierLoc();
- DeclarationNameInfo DNI;
- Record.readDeclarationNameInfo(DNI);
+ DeclarationNameInfo DNI = Record.readDeclarationNameInfo();
C->setQualifierLoc(NNSL);
C->setNameInfo(DNI);
@@ -12753,8 +11995,7 @@ void OMPClauseReader::VisitOMPInReductionClause(OMPInReductionClause *C) {
C->setLParenLoc(Record.readSourceLocation());
C->setColonLoc(Record.readSourceLocation());
NestedNameSpecifierLoc NNSL = Record.readNestedNameSpecifierLoc();
- DeclarationNameInfo DNI;
- Record.readDeclarationNameInfo(DNI);
+ DeclarationNameInfo DNI = Record.readDeclarationNameInfo();
C->setQualifierLoc(NNSL);
C->setNameInfo(DNI);
@@ -12918,9 +12159,7 @@ void OMPClauseReader::VisitOMPMapClause(OMPMapClause *C) {
C->setMapTypeModifierLoc(I, Record.readSourceLocation());
}
C->setMapperQualifierLoc(Record.readNestedNameSpecifierLoc());
- DeclarationNameInfo DNI;
- Record.readDeclarationNameInfo(DNI);
- C->setMapperIdInfo(DNI);
+ C->setMapperIdInfo(Record.readDeclarationNameInfo());
C->setMapType(
static_cast<OpenMPMapClauseKind>(Record.readInt()));
C->setMapLoc(Record.readSourceLocation());
@@ -13041,9 +12280,7 @@ void OMPClauseReader::VisitOMPDefaultmapClause(OMPDefaultmapClause *C) {
void OMPClauseReader::VisitOMPToClause(OMPToClause *C) {
C->setLParenLoc(Record.readSourceLocation());
C->setMapperQualifierLoc(Record.readNestedNameSpecifierLoc());
- DeclarationNameInfo DNI;
- Record.readDeclarationNameInfo(DNI);
- C->setMapperIdInfo(DNI);
+ C->setMapperIdInfo(Record.readDeclarationNameInfo());
auto NumVars = C->varlist_size();
auto UniqueDecls = C->getUniqueDeclarationsNum();
auto TotalLists = C->getTotalComponentListNum();
@@ -13093,9 +12330,7 @@ void OMPClauseReader::VisitOMPToClause(OMPToClause *C) {
void OMPClauseReader::VisitOMPFromClause(OMPFromClause *C) {
C->setLParenLoc(Record.readSourceLocation());
C->setMapperQualifierLoc(Record.readNestedNameSpecifierLoc());
- DeclarationNameInfo DNI;
- Record.readDeclarationNameInfo(DNI);
- C->setMapperIdInfo(DNI);
+ C->setMapperIdInfo(Record.readDeclarationNameInfo());
auto NumVars = C->varlist_size();
auto UniqueDecls = C->getUniqueDeclarationsNum();
auto TotalLists = C->getTotalComponentListNum();
@@ -13234,3 +12469,18 @@ void OMPClauseReader::VisitOMPIsDevicePtrClause(OMPIsDevicePtrClause *C) {
}
C->setComponents(Components, ListSizes);
}
+
+void OMPClauseReader::VisitOMPNontemporalClause(OMPNontemporalClause *C) {
+ C->setLParenLoc(Record.readSourceLocation());
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Record.readSubExpr());
+ C->setVarRefs(Vars);
+ Vars.clear();
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Record.readSubExpr());
+ C->setPrivateRefs(Vars);
+}
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 9aa8c77c6231..96a7d5ae0a31 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements the ASTReader::ReadDeclRecord method, which is the
+// This file implements the ASTReader::readDeclRecord method, which is the
// entrypoint for loading a decl.
//
//===----------------------------------------------------------------------===//
@@ -48,9 +48,9 @@
#include "clang/Basic/Specifiers.h"
#include "clang/Sema/IdentifierResolver.h"
#include "clang/Serialization/ASTBitCodes.h"
-#include "clang/Serialization/ASTReader.h"
+#include "clang/Serialization/ASTRecordReader.h"
#include "clang/Serialization/ContinuousRangeMap.h"
-#include "clang/Serialization/Module.h"
+#include "clang/Serialization/ModuleFile.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/STLExtras.h"
@@ -111,48 +111,40 @@ namespace clang {
return Local ? Record.getGlobalBitOffset(Local) : 0;
}
- SourceLocation ReadSourceLocation() {
+ SourceLocation readSourceLocation() {
return Record.readSourceLocation();
}
- SourceRange ReadSourceRange() {
+ SourceRange readSourceRange() {
return Record.readSourceRange();
}
- TypeSourceInfo *GetTypeSourceInfo() {
- return Record.getTypeSourceInfo();
+ TypeSourceInfo *readTypeSourceInfo() {
+ return Record.readTypeSourceInfo();
}
- serialization::DeclID ReadDeclID() {
+ serialization::DeclID readDeclID() {
return Record.readDeclID();
}
- std::string ReadString() {
+ std::string readString() {
return Record.readString();
}
- void ReadDeclIDList(SmallVectorImpl<DeclID> &IDs) {
+ void readDeclIDList(SmallVectorImpl<DeclID> &IDs) {
for (unsigned I = 0, Size = Record.readInt(); I != Size; ++I)
- IDs.push_back(ReadDeclID());
+ IDs.push_back(readDeclID());
}
- Decl *ReadDecl() {
+ Decl *readDecl() {
return Record.readDecl();
}
template<typename T>
- T *ReadDeclAs() {
+ T *readDeclAs() {
return Record.readDeclAs<T>();
}
- void ReadQualifierInfo(QualifierInfo &Info) {
- Record.readQualifierInfo(Info);
- }
-
- void ReadDeclarationNameLoc(DeclarationNameLoc &DNLoc, DeclarationName Name) {
- Record.readDeclarationNameLoc(DNLoc, Name);
- }
-
serialization::SubmoduleID readSubmoduleID() {
if (Record.getIdx() == Record.size())
return 0;
@@ -405,6 +397,7 @@ namespace clang {
void VisitBlockDecl(BlockDecl *BD);
void VisitCapturedDecl(CapturedDecl *CD);
void VisitEmptyDecl(EmptyDecl *D);
+ void VisitLifetimeExtendedTemporaryDecl(LifetimeExtendedTemporaryDecl *D);
std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC);
@@ -423,6 +416,8 @@ namespace clang {
template<typename T>
void mergeMergeable(Mergeable<T> *D);
+ void mergeMergeable(LifetimeExtendedTemporaryDecl *D);
+
void mergeTemplatePattern(RedeclarableTemplateDecl *D,
RedeclarableTemplateDecl *Existing,
DeclID DsID, bool IsKeyDecl);
@@ -506,8 +501,12 @@ uint64_t ASTDeclReader::GetCurrentCursorOffset() {
}
void ASTDeclReader::ReadFunctionDefinition(FunctionDecl *FD) {
- if (Record.readInt())
+ if (Record.readInt()) {
Reader.DefinitionSource[FD] = Loc.F->Kind == ModuleKind::MK_MainFile;
+ if (Reader.getContext().getLangOpts().BuildingPCHWithObjectFile &&
+ Reader.DeclIsFromPCHWithObjectFile(FD))
+ Reader.DefinitionSource[FD] = true;
+ }
if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) {
CD->setNumCtorInitializers(Record.readInt());
if (CD->getNumCtorInitializers())
@@ -562,8 +561,8 @@ void ASTDeclReader::VisitDecl(Decl *D) {
// example, a function parameter can be used in decltype() in trailing
// return type of the function). Use the translation unit DeclContext as a
// placeholder.
- GlobalDeclID SemaDCIDForTemplateParmDecl = ReadDeclID();
- GlobalDeclID LexicalDCIDForTemplateParmDecl = ReadDeclID();
+ GlobalDeclID SemaDCIDForTemplateParmDecl = readDeclID();
+ GlobalDeclID LexicalDCIDForTemplateParmDecl = readDeclID();
if (!LexicalDCIDForTemplateParmDecl)
LexicalDCIDForTemplateParmDecl = SemaDCIDForTemplateParmDecl;
Reader.addPendingDeclContextInfo(D,
@@ -571,8 +570,8 @@ void ASTDeclReader::VisitDecl(Decl *D) {
LexicalDCIDForTemplateParmDecl);
D->setDeclContext(Reader.getContext().getTranslationUnitDecl());
} else {
- auto *SemaDC = ReadDeclAs<DeclContext>();
- auto *LexicalDC = ReadDeclAs<DeclContext>();
+ auto *SemaDC = readDeclAs<DeclContext>();
+ auto *LexicalDC = readDeclAs<DeclContext>();
if (!LexicalDC)
LexicalDC = SemaDC;
DeclContext *MergedSemaDC = Reader.MergedDeclContexts.lookup(SemaDC);
@@ -628,22 +627,22 @@ void ASTDeclReader::VisitDecl(Decl *D) {
void ASTDeclReader::VisitPragmaCommentDecl(PragmaCommentDecl *D) {
VisitDecl(D);
- D->setLocation(ReadSourceLocation());
+ D->setLocation(readSourceLocation());
D->CommentKind = (PragmaMSCommentKind)Record.readInt();
- std::string Arg = ReadString();
+ std::string Arg = readString();
memcpy(D->getTrailingObjects<char>(), Arg.data(), Arg.size());
D->getTrailingObjects<char>()[Arg.size()] = '\0';
}
void ASTDeclReader::VisitPragmaDetectMismatchDecl(PragmaDetectMismatchDecl *D) {
VisitDecl(D);
- D->setLocation(ReadSourceLocation());
- std::string Name = ReadString();
+ D->setLocation(readSourceLocation());
+ std::string Name = readString();
memcpy(D->getTrailingObjects<char>(), Name.data(), Name.size());
D->getTrailingObjects<char>()[Name.size()] = '\0';
D->ValueStart = Name.size() + 1;
- std::string Value = ReadString();
+ std::string Value = readString();
memcpy(D->getTrailingObjects<char>() + D->ValueStart, Value.data(),
Value.size());
D->getTrailingObjects<char>()[D->ValueStart + Value.size()] = '\0';
@@ -661,7 +660,7 @@ void ASTDeclReader::VisitNamedDecl(NamedDecl *ND) {
void ASTDeclReader::VisitTypeDecl(TypeDecl *TD) {
VisitNamedDecl(TD);
- TD->setLocStart(ReadSourceLocation());
+ TD->setLocStart(readSourceLocation());
// Delay type reading until after we have fully initialized the decl.
DeferredTypeID = Record.getGlobalTypeID(Record.readInt());
}
@@ -670,7 +669,7 @@ ASTDeclReader::RedeclarableResult
ASTDeclReader::VisitTypedefNameDecl(TypedefNameDecl *TD) {
RedeclarableResult Redecl = VisitRedeclarable(TD);
VisitTypeDecl(TD);
- TypeSourceInfo *TInfo = GetTypeSourceInfo();
+ TypeSourceInfo *TInfo = readTypeSourceInfo();
if (Record.readInt()) { // isModed
QualType modedT = Record.readType();
TD->setModedTypeSourceInfo(TInfo, modedT);
@@ -680,7 +679,7 @@ ASTDeclReader::VisitTypedefNameDecl(TypedefNameDecl *TD) {
// linkage, if it exists. We cannot rely on our type to pull in this decl,
// because it might have been merged with a type from another module and
// thus might not refer to our version of the declaration.
- ReadDecl();
+ readDecl();
return Redecl;
}
@@ -691,7 +690,7 @@ void ASTDeclReader::VisitTypedefDecl(TypedefDecl *TD) {
void ASTDeclReader::VisitTypeAliasDecl(TypeAliasDecl *TD) {
RedeclarableResult Redecl = VisitTypedefNameDecl(TD);
- if (auto *Template = ReadDeclAs<TypeAliasTemplateDecl>())
+ if (auto *Template = readDeclAs<TypeAliasTemplateDecl>())
// Merged when we merge the template.
TD->setDescribedAliasTemplate(Template);
else
@@ -709,20 +708,20 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitTagDecl(TagDecl *TD) {
TD->setEmbeddedInDeclarator(Record.readInt());
TD->setFreeStanding(Record.readInt());
TD->setCompleteDefinitionRequired(Record.readInt());
- TD->setBraceRange(ReadSourceRange());
+ TD->setBraceRange(readSourceRange());
switch (Record.readInt()) {
case 0:
break;
case 1: { // ExtInfo
auto *Info = new (Reader.getContext()) TagDecl::ExtInfo();
- ReadQualifierInfo(*Info);
+ Record.readQualifierInfo(*Info);
TD->TypedefNameDeclOrQualifier = Info;
break;
}
case 2: // TypedefNameForAnonDecl
- NamedDeclForTagDecl = ReadDeclID();
- TypedefNameForLinkage = Record.getIdentifierInfo();
+ NamedDeclForTagDecl = readDeclID();
+ TypedefNameForLinkage = Record.readIdentifier();
break;
default:
llvm_unreachable("unexpected tag info kind");
@@ -735,7 +734,7 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitTagDecl(TagDecl *TD) {
void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
VisitTagDecl(ED);
- if (TypeSourceInfo *TI = GetTypeSourceInfo())
+ if (TypeSourceInfo *TI = readTypeSourceInfo())
ED->setIntegerTypeSourceInfo(TI);
else
ED->setIntegerType(Record.readType());
@@ -776,9 +775,9 @@ void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
}
}
- if (auto *InstED = ReadDeclAs<EnumDecl>()) {
+ if (auto *InstED = readDeclAs<EnumDecl>()) {
auto TSK = (TemplateSpecializationKind)Record.readInt();
- SourceLocation POI = ReadSourceLocation();
+ SourceLocation POI = readSourceLocation();
ED->setInstantiationOfMemberEnum(Reader.getContext(), InstED, TSK);
ED->getMemberSpecializationInfo()->setPointOfInstantiation(POI);
}
@@ -823,10 +822,11 @@ void ASTDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) {
void ASTDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) {
VisitValueDecl(DD);
- DD->setInnerLocStart(ReadSourceLocation());
+ DD->setInnerLocStart(readSourceLocation());
if (Record.readInt()) { // hasExtInfo
auto *Info = new (Reader.getContext()) DeclaratorDecl::ExtInfo();
- ReadQualifierInfo(*Info);
+ Record.readQualifierInfo(*Info);
+ Info->TrailingRequiresClause = Record.readExpr();
DD->DeclInfo = Info;
}
QualType TSIType = Record.readType();
@@ -853,7 +853,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
}
DeferredTypeID = 0;
- ReadDeclarationNameLoc(FD->DNLoc, FD->getDeclName());
+ FD->DNLoc = Record.readDeclarationNameLoc(FD->getDeclName());
FD->IdentifierNamespace = Record.readInt();
// FunctionDecl's body is handled last at ASTDeclReader::Visit,
@@ -879,10 +879,24 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FD->setLateTemplateParsed(Record.readInt());
FD->setCachedLinkage(static_cast<Linkage>(Record.readInt()));
- FD->EndRangeLoc = ReadSourceLocation();
+ FD->EndRangeLoc = readSourceLocation();
FD->ODRHash = Record.readInt();
FD->setHasODRHash(true);
+ FD->setUsesFPIntrin(Record.readInt());
+
+ 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));
+ }
+ }
switch ((FunctionDecl::TemplatedKind)Record.readInt()) {
case FunctionDecl::TK_NonTemplate:
@@ -890,19 +904,19 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
break;
case FunctionDecl::TK_FunctionTemplate:
// Merged when we merge the template.
- FD->setDescribedFunctionTemplate(ReadDeclAs<FunctionTemplateDecl>());
+ FD->setDescribedFunctionTemplate(readDeclAs<FunctionTemplateDecl>());
break;
case FunctionDecl::TK_MemberSpecialization: {
- auto *InstFD = ReadDeclAs<FunctionDecl>();
+ auto *InstFD = readDeclAs<FunctionDecl>();
auto TSK = (TemplateSpecializationKind)Record.readInt();
- SourceLocation POI = ReadSourceLocation();
+ SourceLocation POI = readSourceLocation();
FD->setInstantiationOfMemberFunction(Reader.getContext(), InstFD, TSK);
FD->getMemberSpecializationInfo()->setPointOfInstantiation(POI);
mergeRedeclarable(FD, Redecl);
break;
}
case FunctionDecl::TK_FunctionTemplateSpecialization: {
- auto *Template = ReadDeclAs<FunctionTemplateDecl>();
+ auto *Template = readDeclAs<FunctionTemplateDecl>();
auto TSK = (TemplateSpecializationKind)Record.readInt();
// Template arguments.
@@ -919,11 +933,11 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
for (unsigned i = 0; i != NumTemplateArgLocs; ++i)
TemplArgLocs.push_back(Record.readTemplateArgumentLoc());
- LAngleLoc = ReadSourceLocation();
- RAngleLoc = ReadSourceLocation();
+ LAngleLoc = readSourceLocation();
+ RAngleLoc = readSourceLocation();
}
- SourceLocation POI = ReadSourceLocation();
+ SourceLocation POI = readSourceLocation();
ASTContext &C = Reader.getContext();
TemplateArgumentList *TemplArgList
@@ -934,9 +948,9 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
MemberSpecializationInfo *MSInfo = nullptr;
if (Record.readInt()) {
- auto *FD = ReadDeclAs<FunctionDecl>();
+ auto *FD = readDeclAs<FunctionDecl>();
auto TSK = (TemplateSpecializationKind)Record.readInt();
- SourceLocation POI = ReadSourceLocation();
+ SourceLocation POI = readSourceLocation();
MSInfo = new (C) MemberSpecializationInfo(FD, TSK);
MSInfo->setPointOfInstantiation(POI);
@@ -952,7 +966,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
if (FD->isCanonicalDecl()) { // if canonical add to template's set.
// The template that contains the specializations set. It's not safe to
// use getCanonicalDecl on Template since it may still be initializing.
- auto *CanonTemplate = ReadDeclAs<FunctionTemplateDecl>();
+ auto *CanonTemplate = readDeclAs<FunctionTemplateDecl>();
// Get the InsertPos by FindNodeOrInsertPos() instead of calling
// InsertNode(FTInfo) directly to avoid the getASTContext() call in
// FunctionTemplateSpecializationInfo's Profile().
@@ -979,15 +993,15 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
UnresolvedSet<8> TemplDecls;
unsigned NumTemplates = Record.readInt();
while (NumTemplates--)
- TemplDecls.addDecl(ReadDeclAs<NamedDecl>());
+ TemplDecls.addDecl(readDeclAs<NamedDecl>());
// Templates args.
TemplateArgumentListInfo TemplArgs;
unsigned NumArgs = Record.readInt();
while (NumArgs--)
TemplArgs.addArgument(Record.readTemplateArgumentLoc());
- TemplArgs.setLAngleLoc(ReadSourceLocation());
- TemplArgs.setRAngleLoc(ReadSourceLocation());
+ TemplArgs.setLAngleLoc(readSourceLocation());
+ TemplArgs.setRAngleLoc(readSourceLocation());
FD->setDependentTemplateSpecialization(Reader.getContext(),
TemplDecls, TemplArgs);
@@ -1002,7 +1016,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
SmallVector<ParmVarDecl *, 16> Params;
Params.reserve(NumParams);
for (unsigned I = 0; I != NumParams; ++I)
- Params.push_back(ReadDeclAs<ParmVarDecl>());
+ Params.push_back(readDeclAs<ParmVarDecl>());
FD->setParams(Reader.getContext(), Params);
}
@@ -1013,12 +1027,13 @@ void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
// definitions rarely show up in headers.
Reader.PendingBodies[MD] = GetCurrentCursorOffset();
HasPendingBody = true;
- MD->setSelfDecl(ReadDeclAs<ImplicitParamDecl>());
- MD->setCmdDecl(ReadDeclAs<ImplicitParamDecl>());
}
+ MD->setSelfDecl(readDeclAs<ImplicitParamDecl>());
+ MD->setCmdDecl(readDeclAs<ImplicitParamDecl>());
MD->setInstanceMethod(Record.readInt());
MD->setVariadic(Record.readInt());
MD->setPropertyAccessor(Record.readInt());
+ MD->setSynthesizedAccessorStub(Record.readInt());
MD->setDefined(Record.readInt());
MD->setOverriding(Record.readInt());
MD->setHasSkippedBody(Record.readInt());
@@ -1027,26 +1042,26 @@ void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
MD->setHasRedeclaration(Record.readInt());
if (MD->hasRedeclaration())
Reader.getContext().setObjCMethodRedeclaration(MD,
- ReadDeclAs<ObjCMethodDecl>());
+ readDeclAs<ObjCMethodDecl>());
MD->setDeclImplementation((ObjCMethodDecl::ImplementationControl)Record.readInt());
MD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record.readInt());
MD->setRelatedResultType(Record.readInt());
MD->setReturnType(Record.readType());
- MD->setReturnTypeSourceInfo(GetTypeSourceInfo());
- MD->DeclEndLoc = ReadSourceLocation();
+ MD->setReturnTypeSourceInfo(readTypeSourceInfo());
+ MD->DeclEndLoc = readSourceLocation();
unsigned NumParams = Record.readInt();
SmallVector<ParmVarDecl *, 16> Params;
Params.reserve(NumParams);
for (unsigned I = 0; I != NumParams; ++I)
- Params.push_back(ReadDeclAs<ParmVarDecl>());
+ Params.push_back(readDeclAs<ParmVarDecl>());
MD->setSelLocsKind((SelectorLocationsKind)Record.readInt());
unsigned NumStoredSelLocs = Record.readInt();
SmallVector<SourceLocation, 16> SelLocs;
SelLocs.reserve(NumStoredSelLocs);
for (unsigned i = 0; i != NumStoredSelLocs; ++i)
- SelLocs.push_back(ReadSourceLocation());
+ SelLocs.push_back(readSourceLocation());
MD->setParamsAndSelLocs(Reader.getContext(), Params, SelLocs);
}
@@ -1056,14 +1071,14 @@ void ASTDeclReader::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) {
D->Variance = Record.readInt();
D->Index = Record.readInt();
- D->VarianceLoc = ReadSourceLocation();
- D->ColonLoc = ReadSourceLocation();
+ D->VarianceLoc = readSourceLocation();
+ D->ColonLoc = readSourceLocation();
}
void ASTDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) {
VisitNamedDecl(CD);
- CD->setAtStartLoc(ReadSourceLocation());
- CD->setAtEndRange(ReadSourceRange());
+ CD->setAtStartLoc(readSourceLocation());
+ CD->setAtEndRange(readSourceRange());
}
ObjCTypeParamList *ASTDeclReader::ReadObjCTypeParamList() {
@@ -1074,15 +1089,15 @@ ObjCTypeParamList *ASTDeclReader::ReadObjCTypeParamList() {
SmallVector<ObjCTypeParamDecl *, 4> typeParams;
typeParams.reserve(numParams);
for (unsigned i = 0; i != numParams; ++i) {
- auto *typeParam = ReadDeclAs<ObjCTypeParamDecl>();
+ auto *typeParam = readDeclAs<ObjCTypeParamDecl>();
if (!typeParam)
return nullptr;
typeParams.push_back(typeParam);
}
- SourceLocation lAngleLoc = ReadSourceLocation();
- SourceLocation rAngleLoc = ReadSourceLocation();
+ SourceLocation lAngleLoc = readSourceLocation();
+ SourceLocation rAngleLoc = readSourceLocation();
return ObjCTypeParamList::create(Reader.getContext(), lAngleLoc,
typeParams, rAngleLoc);
@@ -1091,9 +1106,9 @@ ObjCTypeParamList *ASTDeclReader::ReadObjCTypeParamList() {
void ASTDeclReader::ReadObjCDefinitionData(
struct ObjCInterfaceDecl::DefinitionData &Data) {
// Read the superclass.
- Data.SuperClassTInfo = GetTypeSourceInfo();
+ Data.SuperClassTInfo = readTypeSourceInfo();
- Data.EndLoc = ReadSourceLocation();
+ Data.EndLoc = readSourceLocation();
Data.HasDesignatedInitializers = Record.readInt();
// Read the directly referenced protocols and their SourceLocations.
@@ -1101,11 +1116,11 @@ void ASTDeclReader::ReadObjCDefinitionData(
SmallVector<ObjCProtocolDecl *, 16> Protocols;
Protocols.reserve(NumProtocols);
for (unsigned I = 0; I != NumProtocols; ++I)
- Protocols.push_back(ReadDeclAs<ObjCProtocolDecl>());
+ Protocols.push_back(readDeclAs<ObjCProtocolDecl>());
SmallVector<SourceLocation, 16> ProtoLocs;
ProtoLocs.reserve(NumProtocols);
for (unsigned I = 0; I != NumProtocols; ++I)
- ProtoLocs.push_back(ReadSourceLocation());
+ ProtoLocs.push_back(readSourceLocation());
Data.ReferencedProtocols.set(Protocols.data(), NumProtocols, ProtoLocs.data(),
Reader.getContext());
@@ -1114,7 +1129,7 @@ void ASTDeclReader::ReadObjCDefinitionData(
Protocols.clear();
Protocols.reserve(NumProtocols);
for (unsigned I = 0; I != NumProtocols; ++I)
- Protocols.push_back(ReadDeclAs<ObjCProtocolDecl>());
+ Protocols.push_back(readDeclAs<ObjCProtocolDecl>());
Data.AllReferencedProtocols.set(Protocols.data(), NumProtocols,
Reader.getContext());
}
@@ -1176,11 +1191,11 @@ void ASTDeclReader::ReadObjCDefinitionData(
SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
ProtoRefs.reserve(NumProtoRefs);
for (unsigned I = 0; I != NumProtoRefs; ++I)
- ProtoRefs.push_back(ReadDeclAs<ObjCProtocolDecl>());
+ ProtoRefs.push_back(readDeclAs<ObjCProtocolDecl>());
SmallVector<SourceLocation, 16> ProtoLocs;
ProtoLocs.reserve(NumProtoRefs);
for (unsigned I = 0; I != NumProtoRefs; ++I)
- ProtoLocs.push_back(ReadSourceLocation());
+ ProtoLocs.push_back(readSourceLocation());
Data.ReferencedProtocols.set(ProtoRefs.data(), NumProtoRefs,
ProtoLocs.data(), Reader.getContext());
}
@@ -1225,26 +1240,26 @@ void ASTDeclReader::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *FD) {
void ASTDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) {
VisitObjCContainerDecl(CD);
- CD->setCategoryNameLoc(ReadSourceLocation());
- CD->setIvarLBraceLoc(ReadSourceLocation());
- CD->setIvarRBraceLoc(ReadSourceLocation());
+ CD->setCategoryNameLoc(readSourceLocation());
+ CD->setIvarLBraceLoc(readSourceLocation());
+ CD->setIvarRBraceLoc(readSourceLocation());
// Note that this category has been deserialized. We do this before
// deserializing the interface declaration, so that it will consider this
/// category.
Reader.CategoriesDeserialized.insert(CD);
- CD->ClassInterface = ReadDeclAs<ObjCInterfaceDecl>();
+ CD->ClassInterface = readDeclAs<ObjCInterfaceDecl>();
CD->TypeParamList = ReadObjCTypeParamList();
unsigned NumProtoRefs = Record.readInt();
SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
ProtoRefs.reserve(NumProtoRefs);
for (unsigned I = 0; I != NumProtoRefs; ++I)
- ProtoRefs.push_back(ReadDeclAs<ObjCProtocolDecl>());
+ ProtoRefs.push_back(readDeclAs<ObjCProtocolDecl>());
SmallVector<SourceLocation, 16> ProtoLocs;
ProtoLocs.reserve(NumProtoRefs);
for (unsigned I = 0; I != NumProtoRefs; ++I)
- ProtoLocs.push_back(ReadSourceLocation());
+ ProtoLocs.push_back(readSourceLocation());
CD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(),
Reader.getContext());
@@ -1257,15 +1272,15 @@ void ASTDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) {
void ASTDeclReader::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) {
VisitNamedDecl(CAD);
- CAD->setClassInterface(ReadDeclAs<ObjCInterfaceDecl>());
+ CAD->setClassInterface(readDeclAs<ObjCInterfaceDecl>());
}
void ASTDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
VisitNamedDecl(D);
- D->setAtLoc(ReadSourceLocation());
- D->setLParenLoc(ReadSourceLocation());
+ D->setAtLoc(readSourceLocation());
+ D->setLParenLoc(readSourceLocation());
QualType T = Record.readType();
- TypeSourceInfo *TSI = GetTypeSourceInfo();
+ TypeSourceInfo *TSI = readTypeSourceInfo();
D->setType(T, TSI);
D->setPropertyAttributes(
(ObjCPropertyDecl::PropertyAttributeKind)Record.readInt());
@@ -1274,32 +1289,32 @@ void ASTDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
D->setPropertyImplementation(
(ObjCPropertyDecl::PropertyControl)Record.readInt());
DeclarationName GetterName = Record.readDeclarationName();
- SourceLocation GetterLoc = ReadSourceLocation();
+ SourceLocation GetterLoc = readSourceLocation();
D->setGetterName(GetterName.getObjCSelector(), GetterLoc);
DeclarationName SetterName = Record.readDeclarationName();
- SourceLocation SetterLoc = ReadSourceLocation();
+ SourceLocation SetterLoc = readSourceLocation();
D->setSetterName(SetterName.getObjCSelector(), SetterLoc);
- D->setGetterMethodDecl(ReadDeclAs<ObjCMethodDecl>());
- D->setSetterMethodDecl(ReadDeclAs<ObjCMethodDecl>());
- D->setPropertyIvarDecl(ReadDeclAs<ObjCIvarDecl>());
+ D->setGetterMethodDecl(readDeclAs<ObjCMethodDecl>());
+ D->setSetterMethodDecl(readDeclAs<ObjCMethodDecl>());
+ D->setPropertyIvarDecl(readDeclAs<ObjCIvarDecl>());
}
void ASTDeclReader::VisitObjCImplDecl(ObjCImplDecl *D) {
VisitObjCContainerDecl(D);
- D->setClassInterface(ReadDeclAs<ObjCInterfaceDecl>());
+ D->setClassInterface(readDeclAs<ObjCInterfaceDecl>());
}
void ASTDeclReader::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
VisitObjCImplDecl(D);
- D->CategoryNameLoc = ReadSourceLocation();
+ D->CategoryNameLoc = readSourceLocation();
}
void ASTDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
VisitObjCImplDecl(D);
- D->setSuperClass(ReadDeclAs<ObjCInterfaceDecl>());
- D->SuperLoc = ReadSourceLocation();
- D->setIvarLBraceLoc(ReadSourceLocation());
- D->setIvarRBraceLoc(ReadSourceLocation());
+ D->setSuperClass(readDeclAs<ObjCInterfaceDecl>());
+ D->SuperLoc = readSourceLocation();
+ D->setIvarLBraceLoc(readSourceLocation());
+ D->setIvarRBraceLoc(readSourceLocation());
D->setHasNonZeroConstructors(Record.readInt());
D->setHasDestructors(Record.readInt());
D->NumIvarInitializers = Record.readInt();
@@ -1309,10 +1324,12 @@ void ASTDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
void ASTDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
VisitDecl(D);
- D->setAtLoc(ReadSourceLocation());
- D->setPropertyDecl(ReadDeclAs<ObjCPropertyDecl>());
- D->PropertyIvarDecl = ReadDeclAs<ObjCIvarDecl>();
- D->IvarLoc = ReadSourceLocation();
+ D->setAtLoc(readSourceLocation());
+ D->setPropertyDecl(readDeclAs<ObjCPropertyDecl>());
+ D->PropertyIvarDecl = readDeclAs<ObjCIvarDecl>();
+ D->IvarLoc = readSourceLocation();
+ D->setGetterMethodDecl(readDeclAs<ObjCMethodDecl>());
+ D->setSetterMethodDecl(readDeclAs<ObjCMethodDecl>());
D->setGetterCXXConstructor(Record.readExpr());
D->setSetterCXXAssignment(Record.readExpr());
}
@@ -1332,7 +1349,7 @@ void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) {
FD->setBitWidth(BW);
if (!FD->getDeclName()) {
- if (auto *Tmpl = ReadDeclAs<FieldDecl>())
+ if (auto *Tmpl = readDeclAs<FieldDecl>())
Reader.getContext().setInstantiatedFromUnnamedFieldDecl(FD, Tmpl);
}
mergeMergeable(FD);
@@ -1340,8 +1357,8 @@ void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) {
void ASTDeclReader::VisitMSPropertyDecl(MSPropertyDecl *PD) {
VisitDeclaratorDecl(PD);
- PD->GetterId = Record.getIdentifierInfo();
- PD->SetterId = Record.getIdentifierInfo();
+ PD->GetterId = Record.readIdentifier();
+ PD->SetterId = Record.readIdentifier();
}
void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) {
@@ -1352,7 +1369,7 @@ void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) {
FD->Chaining = new (Reader.getContext())NamedDecl*[FD->ChainingSize];
for (unsigned I = 0; I != FD->ChainingSize; ++I)
- FD->Chaining[I] = ReadDeclAs<NamedDecl>();
+ FD->Chaining[I] = readDeclAs<NamedDecl>();
mergeMergeable(FD);
}
@@ -1404,8 +1421,12 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
Reader.getContext().setBlockVarCopyInit(VD, CopyExpr, Record.readInt());
}
- if (VD->getStorageDuration() == SD_Static && Record.readInt())
+ if (VD->getStorageDuration() == SD_Static && Record.readInt()) {
Reader.DefinitionSource[VD] = Loc.F->Kind == ModuleKind::MK_MainFile;
+ if (Reader.getContext().getLangOpts().BuildingPCHWithObjectFile &&
+ Reader.DeclIsFromPCHWithObjectFile(VD))
+ Reader.DefinitionSource[VD] = true;
+ }
enum VarKind {
VarNotTemplate = 0, VarTemplate, StaticDataMemberSpecialization
@@ -1420,12 +1441,12 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
break;
case VarTemplate:
// Merged when we merge the template.
- VD->setDescribedVarTemplate(ReadDeclAs<VarTemplateDecl>());
+ VD->setDescribedVarTemplate(readDeclAs<VarTemplateDecl>());
break;
case StaticDataMemberSpecialization: { // HasMemberSpecializationInfo.
- auto *Tmpl = ReadDeclAs<VarDecl>();
+ auto *Tmpl = readDeclAs<VarDecl>();
auto TSK = (TemplateSpecializationKind)Record.readInt();
- SourceLocation POI = ReadSourceLocation();
+ SourceLocation POI = readSourceLocation();
Reader.getContext().setInstantiatedFromStaticDataMember(VD, Tmpl, TSK,POI);
mergeRedeclarable(VD, Redecl);
break;
@@ -1465,7 +1486,7 @@ void ASTDeclReader::VisitDecompositionDecl(DecompositionDecl *DD) {
VisitVarDecl(DD);
auto **BDs = DD->getTrailingObjects<BindingDecl *>();
for (unsigned I = 0; I != DD->NumBindings; ++I) {
- BDs[I] = ReadDeclAs<BindingDecl>();
+ BDs[I] = readDeclAs<BindingDecl>();
BDs[I]->setDecomposedDecl(DD);
}
}
@@ -1478,18 +1499,18 @@ void ASTDeclReader::VisitBindingDecl(BindingDecl *BD) {
void ASTDeclReader::VisitFileScopeAsmDecl(FileScopeAsmDecl *AD) {
VisitDecl(AD);
AD->setAsmString(cast<StringLiteral>(Record.readExpr()));
- AD->setRParenLoc(ReadSourceLocation());
+ AD->setRParenLoc(readSourceLocation());
}
void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) {
VisitDecl(BD);
BD->setBody(cast_or_null<CompoundStmt>(Record.readStmt()));
- BD->setSignatureAsWritten(GetTypeSourceInfo());
+ BD->setSignatureAsWritten(readTypeSourceInfo());
unsigned NumParams = Record.readInt();
SmallVector<ParmVarDecl *, 16> Params;
Params.reserve(NumParams);
for (unsigned I = 0; I != NumParams; ++I)
- Params.push_back(ReadDeclAs<ParmVarDecl>());
+ Params.push_back(readDeclAs<ParmVarDecl>());
BD->setParams(Params);
BD->setIsVariadic(Record.readInt());
@@ -1503,7 +1524,7 @@ void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) {
SmallVector<BlockDecl::Capture, 16> captures;
captures.reserve(numCaptures);
for (unsigned i = 0; i != numCaptures; ++i) {
- auto *decl = ReadDeclAs<VarDecl>();
+ auto *decl = readDeclAs<VarDecl>();
unsigned flags = Record.readInt();
bool byRef = (flags & 1);
bool nested = (flags & 2);
@@ -1521,35 +1542,35 @@ void ASTDeclReader::VisitCapturedDecl(CapturedDecl *CD) {
// Body is set by VisitCapturedStmt.
for (unsigned I = 0; I < CD->NumParams; ++I) {
if (I != ContextParamPos)
- CD->setParam(I, ReadDeclAs<ImplicitParamDecl>());
+ CD->setParam(I, readDeclAs<ImplicitParamDecl>());
else
- CD->setContextParam(I, ReadDeclAs<ImplicitParamDecl>());
+ CD->setContextParam(I, readDeclAs<ImplicitParamDecl>());
}
}
void ASTDeclReader::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
VisitDecl(D);
D->setLanguage((LinkageSpecDecl::LanguageIDs)Record.readInt());
- D->setExternLoc(ReadSourceLocation());
- D->setRBraceLoc(ReadSourceLocation());
+ D->setExternLoc(readSourceLocation());
+ D->setRBraceLoc(readSourceLocation());
}
void ASTDeclReader::VisitExportDecl(ExportDecl *D) {
VisitDecl(D);
- D->RBraceLoc = ReadSourceLocation();
+ D->RBraceLoc = readSourceLocation();
}
void ASTDeclReader::VisitLabelDecl(LabelDecl *D) {
VisitNamedDecl(D);
- D->setLocStart(ReadSourceLocation());
+ D->setLocStart(readSourceLocation());
}
void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
RedeclarableResult Redecl = VisitRedeclarable(D);
VisitNamedDecl(D);
D->setInline(Record.readInt());
- D->LocStart = ReadSourceLocation();
- D->RBraceLoc = ReadSourceLocation();
+ D->LocStart = readSourceLocation();
+ D->RBraceLoc = readSourceLocation();
// Defer loading the anonymous namespace until we've finished merging
// this namespace; loading it might load a later declaration of the
@@ -1557,7 +1578,7 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
// get merged before newer ones try to merge.
GlobalDeclID AnonNamespace = 0;
if (Redecl.getFirstID() == ThisDeclID) {
- AnonNamespace = ReadDeclID();
+ AnonNamespace = readDeclID();
} else {
// Link this namespace back to the first declaration, which has already
// been deserialized.
@@ -1579,41 +1600,41 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
void ASTDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
RedeclarableResult Redecl = VisitRedeclarable(D);
VisitNamedDecl(D);
- D->NamespaceLoc = ReadSourceLocation();
- D->IdentLoc = ReadSourceLocation();
+ D->NamespaceLoc = readSourceLocation();
+ D->IdentLoc = readSourceLocation();
D->QualifierLoc = Record.readNestedNameSpecifierLoc();
- D->Namespace = ReadDeclAs<NamedDecl>();
+ D->Namespace = readDeclAs<NamedDecl>();
mergeRedeclarable(D, Redecl);
}
void ASTDeclReader::VisitUsingDecl(UsingDecl *D) {
VisitNamedDecl(D);
- D->setUsingLoc(ReadSourceLocation());
+ D->setUsingLoc(readSourceLocation());
D->QualifierLoc = Record.readNestedNameSpecifierLoc();
- ReadDeclarationNameLoc(D->DNLoc, D->getDeclName());
- D->FirstUsingShadow.setPointer(ReadDeclAs<UsingShadowDecl>());
+ D->DNLoc = Record.readDeclarationNameLoc(D->getDeclName());
+ D->FirstUsingShadow.setPointer(readDeclAs<UsingShadowDecl>());
D->setTypename(Record.readInt());
- if (auto *Pattern = ReadDeclAs<NamedDecl>())
+ if (auto *Pattern = readDeclAs<NamedDecl>())
Reader.getContext().setInstantiatedFromUsingDecl(D, Pattern);
mergeMergeable(D);
}
void ASTDeclReader::VisitUsingPackDecl(UsingPackDecl *D) {
VisitNamedDecl(D);
- D->InstantiatedFrom = ReadDeclAs<NamedDecl>();
+ D->InstantiatedFrom = readDeclAs<NamedDecl>();
auto **Expansions = D->getTrailingObjects<NamedDecl *>();
for (unsigned I = 0; I != D->NumExpansions; ++I)
- Expansions[I] = ReadDeclAs<NamedDecl>();
+ Expansions[I] = readDeclAs<NamedDecl>();
mergeMergeable(D);
}
void ASTDeclReader::VisitUsingShadowDecl(UsingShadowDecl *D) {
RedeclarableResult Redecl = VisitRedeclarable(D);
VisitNamedDecl(D);
- D->Underlying = ReadDeclAs<NamedDecl>();
+ D->Underlying = readDeclAs<NamedDecl>();
D->IdentifierNamespace = Record.readInt();
- D->UsingOrNextShadow = ReadDeclAs<NamedDecl>();
- auto *Pattern = ReadDeclAs<UsingShadowDecl>();
+ D->UsingOrNextShadow = readDeclAs<NamedDecl>();
+ auto *Pattern = readDeclAs<UsingShadowDecl>();
if (Pattern)
Reader.getContext().setInstantiatedFromUsingShadowDecl(D, Pattern);
mergeRedeclarable(D, Redecl);
@@ -1622,35 +1643,35 @@ void ASTDeclReader::VisitUsingShadowDecl(UsingShadowDecl *D) {
void ASTDeclReader::VisitConstructorUsingShadowDecl(
ConstructorUsingShadowDecl *D) {
VisitUsingShadowDecl(D);
- D->NominatedBaseClassShadowDecl = ReadDeclAs<ConstructorUsingShadowDecl>();
- D->ConstructedBaseClassShadowDecl = ReadDeclAs<ConstructorUsingShadowDecl>();
+ D->NominatedBaseClassShadowDecl = readDeclAs<ConstructorUsingShadowDecl>();
+ D->ConstructedBaseClassShadowDecl = readDeclAs<ConstructorUsingShadowDecl>();
D->IsVirtual = Record.readInt();
}
void ASTDeclReader::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
VisitNamedDecl(D);
- D->UsingLoc = ReadSourceLocation();
- D->NamespaceLoc = ReadSourceLocation();
+ D->UsingLoc = readSourceLocation();
+ D->NamespaceLoc = readSourceLocation();
D->QualifierLoc = Record.readNestedNameSpecifierLoc();
- D->NominatedNamespace = ReadDeclAs<NamedDecl>();
- D->CommonAncestor = ReadDeclAs<DeclContext>();
+ D->NominatedNamespace = readDeclAs<NamedDecl>();
+ D->CommonAncestor = readDeclAs<DeclContext>();
}
void ASTDeclReader::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
VisitValueDecl(D);
- D->setUsingLoc(ReadSourceLocation());
+ D->setUsingLoc(readSourceLocation());
D->QualifierLoc = Record.readNestedNameSpecifierLoc();
- ReadDeclarationNameLoc(D->DNLoc, D->getDeclName());
- D->EllipsisLoc = ReadSourceLocation();
+ D->DNLoc = Record.readDeclarationNameLoc(D->getDeclName());
+ D->EllipsisLoc = readSourceLocation();
mergeMergeable(D);
}
void ASTDeclReader::VisitUnresolvedUsingTypenameDecl(
UnresolvedUsingTypenameDecl *D) {
VisitTypeDecl(D);
- D->TypenameLocation = ReadSourceLocation();
+ D->TypenameLocation = readSourceLocation();
D->QualifierLoc = Record.readNestedNameSpecifierLoc();
- D->EllipsisLoc = ReadSourceLocation();
+ D->EllipsisLoc = readSourceLocation();
mergeMergeable(D);
}
@@ -1664,8 +1685,12 @@ void ASTDeclReader::ReadCXXDefinitionData(
Data.ODRHash = Record.readInt();
Data.HasODRHash = true;
- if (Record.readInt())
+ if (Record.readInt()) {
Reader.DefinitionSource[D] = Loc.F->Kind == ModuleKind::MK_MainFile;
+ if (Reader.getContext().getLangOpts().BuildingPCHWithObjectFile &&
+ Reader.DeclIsFromPCHWithObjectFile(D))
+ Reader.DefinitionSource[D] = true;
+ }
Data.NumBases = Record.readInt();
if (Data.NumBases)
@@ -1679,7 +1704,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
if (Data.ComputedVisibleConversions)
Record.readUnresolvedSet(Data.VisibleConversions);
assert(Data.Definition && "Data.Definition should be already set!");
- Data.FirstFriend = ReadDeclID();
+ Data.FirstFriend = readDeclID();
if (Data.IsLambda) {
using Capture = LambdaCapture;
@@ -1692,13 +1717,13 @@ void ASTDeclReader::ReadCXXDefinitionData(
Lambda.NumExplicitCaptures = Record.readInt();
Lambda.HasKnownInternalLinkage = Record.readInt();
Lambda.ManglingNumber = Record.readInt();
- Lambda.ContextDecl = ReadDeclID();
+ Lambda.ContextDecl = readDeclID();
Lambda.Captures = (Capture *)Reader.getContext().Allocate(
sizeof(Capture) * Lambda.NumCaptures);
Capture *ToCapture = Lambda.Captures;
- Lambda.MethodTyInfo = GetTypeSourceInfo();
+ Lambda.MethodTyInfo = readTypeSourceInfo();
for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
- SourceLocation Loc = ReadSourceLocation();
+ SourceLocation Loc = readSourceLocation();
bool IsImplicit = Record.readInt();
auto Kind = static_cast<LambdaCaptureKind>(Record.readInt());
switch (Kind) {
@@ -1709,8 +1734,8 @@ void ASTDeclReader::ReadCXXDefinitionData(
break;
case LCK_ByCopy:
case LCK_ByRef:
- auto *Var = ReadDeclAs<VarDecl>();
- SourceLocation EllipsisLoc = ReadSourceLocation();
+ auto *Var = readDeclAs<VarDecl>();
+ SourceLocation EllipsisLoc = readSourceLocation();
*ToCapture++ = Capture(Loc, IsImplicit, Kind, Var, EllipsisLoc);
break;
}
@@ -1849,7 +1874,7 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) {
break;
case CXXRecTemplate: {
// Merged when we merge the template.
- auto *Template = ReadDeclAs<ClassTemplateDecl>();
+ auto *Template = readDeclAs<ClassTemplateDecl>();
D->TemplateOrInstantiation = Template;
if (!Template->getTemplatedDecl()) {
// We've not actually loaded the ClassTemplateDecl yet, because we're
@@ -1863,9 +1888,9 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) {
break;
}
case CXXRecMemberSpecialization: {
- auto *RD = ReadDeclAs<CXXRecordDecl>();
+ auto *RD = readDeclAs<CXXRecordDecl>();
auto TSK = (TemplateSpecializationKind)Record.readInt();
- SourceLocation POI = ReadSourceLocation();
+ SourceLocation POI = readSourceLocation();
MemberSpecializationInfo *MSI = new (C) MemberSpecializationInfo(RD, TSK);
MSI->setPointOfInstantiation(POI);
D->TemplateOrInstantiation = MSI;
@@ -1884,7 +1909,7 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) {
// Lazily load the key function to avoid deserializing every method so we can
// compute it.
if (WasDefinition) {
- DeclID KeyFn = ReadDeclID();
+ DeclID KeyFn = readDeclID();
if (KeyFn && D->isCompleteDefinition())
// FIXME: This is wrong for the ARM ABI, where some other module may have
// made this function no longer be a key function. We need an update
@@ -1909,7 +1934,7 @@ void ASTDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) {
while (NumOverridenMethods--) {
// Avoid invariant checking of CXXMethodDecl::addOverriddenMethod,
// MD may be initializing.
- if (auto *MD = ReadDeclAs<CXXMethodDecl>())
+ if (auto *MD = readDeclAs<CXXMethodDecl>())
Reader.getContext().addOverriddenMethod(D, MD->getCanonicalDecl());
}
} else {
@@ -1924,8 +1949,8 @@ void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
// so we have to read it before we call VisitCXXMethodDecl.
D->setExplicitSpecifier(Record.readExplicitSpec());
if (D->isInheritingConstructor()) {
- auto *Shadow = ReadDeclAs<ConstructorUsingShadowDecl>();
- auto *Ctor = ReadDeclAs<CXXConstructorDecl>();
+ auto *Shadow = readDeclAs<ConstructorUsingShadowDecl>();
+ auto *Ctor = readDeclAs<CXXConstructorDecl>();
*D->getTrailingObjects<InheritedConstructor>() =
InheritedConstructor(Shadow, Ctor);
}
@@ -1936,7 +1961,7 @@ void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
VisitCXXMethodDecl(D);
- if (auto *OperatorDelete = ReadDeclAs<FunctionDecl>()) {
+ if (auto *OperatorDelete = readDeclAs<FunctionDecl>()) {
CXXDestructorDecl *Canon = D->getCanonicalDecl();
auto *ThisArg = Record.readExpr();
// FIXME: Check consistency if we have an old and new operator delete.
@@ -1958,27 +1983,27 @@ void ASTDeclReader::VisitImportDecl(ImportDecl *D) {
D->ImportedAndComplete.setInt(Record.readInt());
auto *StoredLocs = D->getTrailingObjects<SourceLocation>();
for (unsigned I = 0, N = Record.back(); I != N; ++I)
- StoredLocs[I] = ReadSourceLocation();
+ StoredLocs[I] = readSourceLocation();
Record.skipInts(1); // The number of stored source locations.
}
void ASTDeclReader::VisitAccessSpecDecl(AccessSpecDecl *D) {
VisitDecl(D);
- D->setColonLoc(ReadSourceLocation());
+ D->setColonLoc(readSourceLocation());
}
void ASTDeclReader::VisitFriendDecl(FriendDecl *D) {
VisitDecl(D);
if (Record.readInt()) // hasFriendDecl
- D->Friend = ReadDeclAs<NamedDecl>();
+ D->Friend = readDeclAs<NamedDecl>();
else
- D->Friend = GetTypeSourceInfo();
+ D->Friend = readTypeSourceInfo();
for (unsigned i = 0; i != D->NumTPLists; ++i)
D->getTrailingObjects<TemplateParameterList *>()[i] =
Record.readTemplateParameterList();
- D->NextFriend = ReadDeclID();
+ D->NextFriend = readDeclID();
D->UnsupportedFriend = (Record.readInt() != 0);
- D->FriendLoc = ReadSourceLocation();
+ D->FriendLoc = readSourceLocation();
}
void ASTDeclReader::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
@@ -1989,16 +2014,16 @@ void ASTDeclReader::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
for (unsigned i = 0; i != NumParams; ++i)
D->Params[i] = Record.readTemplateParameterList();
if (Record.readInt()) // HasFriendDecl
- D->Friend = ReadDeclAs<NamedDecl>();
+ D->Friend = readDeclAs<NamedDecl>();
else
- D->Friend = GetTypeSourceInfo();
- D->FriendLoc = ReadSourceLocation();
+ D->Friend = readTypeSourceInfo();
+ D->FriendLoc = readSourceLocation();
}
DeclID ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) {
VisitNamedDecl(D);
- DeclID PatternID = ReadDeclID();
+ DeclID PatternID = readDeclID();
auto *TemplatedDecl = cast_or_null<NamedDecl>(Reader.GetDecl(PatternID));
TemplateParameterList *TemplateParams = Record.readTemplateParameterList();
D->init(TemplatedDecl, TemplateParams);
@@ -2028,7 +2053,7 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
// If this is the first declaration of the template, fill in the information
// for the 'common' pointer.
if (ThisDeclID == Redecl.getFirstID()) {
- if (auto *RTD = ReadDeclAs<RedeclarableTemplateDecl>()) {
+ if (auto *RTD = readDeclAs<RedeclarableTemplateDecl>()) {
assert(RTD->getKind() == D->getKind() &&
"InstantiatedFromMemberTemplate kind mismatch");
D->setInstantiatedFromMemberTemplate(RTD);
@@ -2057,7 +2082,7 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// This ClassTemplateDecl owns a CommonPtr; read it to keep track of all of
// the specializations.
SmallVector<serialization::DeclID, 32> SpecIDs;
- ReadDeclIDList(SpecIDs);
+ readDeclIDList(SpecIDs);
ASTDeclReader::AddLazySpecializations(D, SpecIDs);
}
@@ -2084,7 +2109,7 @@ void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) {
// This VarTemplateDecl owns a CommonPtr; read it to keep track of all of
// the specializations.
SmallVector<serialization::DeclID, 32> SpecIDs;
- ReadDeclIDList(SpecIDs);
+ readDeclIDList(SpecIDs);
ASTDeclReader::AddLazySpecializations(D, SpecIDs);
}
}
@@ -2095,7 +2120,7 @@ ASTDeclReader::VisitClassTemplateSpecializationDeclImpl(
RedeclarableResult Redecl = VisitCXXRecordDeclImpl(D);
ASTContext &C = Reader.getContext();
- if (Decl *InstD = ReadDecl()) {
+ if (Decl *InstD = readDecl()) {
if (auto *CTD = dyn_cast<ClassTemplateDecl>(InstD)) {
D->SpecializedTemplate = CTD;
} else {
@@ -2116,12 +2141,12 @@ ASTDeclReader::VisitClassTemplateSpecializationDeclImpl(
SmallVector<TemplateArgument, 8> TemplArgs;
Record.readTemplateArgumentList(TemplArgs, /*Canonicalize*/ true);
D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs);
- D->PointOfInstantiation = ReadSourceLocation();
+ D->PointOfInstantiation = readSourceLocation();
D->SpecializationKind = (TemplateSpecializationKind)Record.readInt();
bool writtenAsCanonicalDecl = Record.readInt();
if (writtenAsCanonicalDecl) {
- auto *CanonPattern = ReadDeclAs<ClassTemplateDecl>();
+ auto *CanonPattern = readDeclAs<ClassTemplateDecl>();
if (D->isCanonicalDecl()) { // It's kept in the folding set.
// Set this as, or find, the canonical declaration for this specialization
ClassTemplateSpecializationDecl *CanonSpec;
@@ -2150,12 +2175,12 @@ ASTDeclReader::VisitClassTemplateSpecializationDeclImpl(
}
// Explicit info.
- if (TypeSourceInfo *TyInfo = GetTypeSourceInfo()) {
+ if (TypeSourceInfo *TyInfo = readTypeSourceInfo()) {
auto *ExplicitInfo =
new (C) ClassTemplateSpecializationDecl::ExplicitSpecializationInfo;
ExplicitInfo->TypeAsWritten = TyInfo;
- ExplicitInfo->ExternLoc = ReadSourceLocation();
- ExplicitInfo->TemplateKeywordLoc = ReadSourceLocation();
+ ExplicitInfo->ExternLoc = readSourceLocation();
+ ExplicitInfo->TemplateKeywordLoc = readSourceLocation();
D->ExplicitInfo = ExplicitInfo;
}
@@ -2164,16 +2189,18 @@ ASTDeclReader::VisitClassTemplateSpecializationDeclImpl(
void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *D) {
- RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D);
-
+ // We need to read the template params first because redeclarable is going to
+ // need them for profiling
TemplateParameterList *Params = Record.readTemplateParameterList();
D->TemplateParams = Params;
D->ArgsAsWritten = Record.readASTTemplateArgumentListInfo();
+ RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D);
+
// These are read/set from/to the first declaration.
if (ThisDeclID == Redecl.getFirstID()) {
D->InstantiatedFromMember.setPointer(
- ReadDeclAs<ClassTemplatePartialSpecializationDecl>());
+ readDeclAs<ClassTemplatePartialSpecializationDecl>());
D->InstantiatedFromMember.setInt(Record.readInt());
}
}
@@ -2181,7 +2208,7 @@ void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl(
void ASTDeclReader::VisitClassScopeFunctionSpecializationDecl(
ClassScopeFunctionSpecializationDecl *D) {
VisitDecl(D);
- D->Specialization = ReadDeclAs<CXXMethodDecl>();
+ D->Specialization = readDeclAs<CXXMethodDecl>();
if (Record.readInt())
D->TemplateArgs = Record.readASTTemplateArgumentListInfo();
}
@@ -2192,7 +2219,7 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
if (ThisDeclID == Redecl.getFirstID()) {
// This FunctionTemplateDecl owns a CommonPtr; read it.
SmallVector<serialization::DeclID, 32> SpecIDs;
- ReadDeclIDList(SpecIDs);
+ readDeclIDList(SpecIDs);
ASTDeclReader::AddLazySpecializations(D, SpecIDs);
}
}
@@ -2208,7 +2235,7 @@ ASTDeclReader::VisitVarTemplateSpecializationDeclImpl(
RedeclarableResult Redecl = VisitVarDeclImpl(D);
ASTContext &C = Reader.getContext();
- if (Decl *InstD = ReadDecl()) {
+ if (Decl *InstD = readDecl()) {
if (auto *VTD = dyn_cast<VarTemplateDecl>(InstD)) {
D->SpecializedTemplate = VTD;
} else {
@@ -2227,25 +2254,25 @@ ASTDeclReader::VisitVarTemplateSpecializationDeclImpl(
}
// Explicit info.
- if (TypeSourceInfo *TyInfo = GetTypeSourceInfo()) {
+ if (TypeSourceInfo *TyInfo = readTypeSourceInfo()) {
auto *ExplicitInfo =
new (C) VarTemplateSpecializationDecl::ExplicitSpecializationInfo;
ExplicitInfo->TypeAsWritten = TyInfo;
- ExplicitInfo->ExternLoc = ReadSourceLocation();
- ExplicitInfo->TemplateKeywordLoc = ReadSourceLocation();
+ ExplicitInfo->ExternLoc = readSourceLocation();
+ ExplicitInfo->TemplateKeywordLoc = readSourceLocation();
D->ExplicitInfo = ExplicitInfo;
}
SmallVector<TemplateArgument, 8> TemplArgs;
Record.readTemplateArgumentList(TemplArgs, /*Canonicalize*/ true);
D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs);
- D->PointOfInstantiation = ReadSourceLocation();
+ D->PointOfInstantiation = readSourceLocation();
D->SpecializationKind = (TemplateSpecializationKind)Record.readInt();
D->IsCompleteDefinition = Record.readInt();
bool writtenAsCanonicalDecl = Record.readInt();
if (writtenAsCanonicalDecl) {
- auto *CanonPattern = ReadDeclAs<VarTemplateDecl>();
+ auto *CanonPattern = readDeclAs<VarTemplateDecl>();
if (D->isCanonicalDecl()) { // It's kept in the folding set.
// FIXME: If it's already present, merge it.
if (auto *Partial = dyn_cast<VarTemplatePartialSpecializationDecl>(D)) {
@@ -2267,16 +2294,16 @@ ASTDeclReader::VisitVarTemplateSpecializationDeclImpl(
/// using Template(Partial)SpecializationDecl as input type.
void ASTDeclReader::VisitVarTemplatePartialSpecializationDecl(
VarTemplatePartialSpecializationDecl *D) {
- RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D);
-
TemplateParameterList *Params = Record.readTemplateParameterList();
D->TemplateParams = Params;
D->ArgsAsWritten = Record.readASTTemplateArgumentListInfo();
+ RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D);
+
// These are read/set from/to the first declaration.
if (ThisDeclID == Redecl.getFirstID()) {
D->InstantiatedFromMember.setPointer(
- ReadDeclAs<VarTemplatePartialSpecializationDecl>());
+ readDeclAs<VarTemplatePartialSpecializationDecl>());
D->InstantiatedFromMember.setInt(Record.readInt());
}
}
@@ -2286,9 +2313,22 @@ void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
D->setDeclaredWithTypename(Record.readInt());
- // TODO: Concepts: Immediately introduced constraint
+ if (Record.readInt()) {
+ NestedNameSpecifierLoc NNS = Record.readNestedNameSpecifierLoc();
+ DeclarationNameInfo DN = Record.readDeclarationNameInfo();
+ ConceptDecl *NamedConcept = cast<ConceptDecl>(Record.readDecl());
+ const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr;
+ if (Record.readInt())
+ ArgsAsWritten = Record.readASTTemplateArgumentListInfo();
+ Expr *ImmediatelyDeclaredConstraint = Record.readExpr();
+ D->setTypeConstraint(NNS, DN, /*FoundDecl=*/nullptr, NamedConcept,
+ ArgsAsWritten, ImmediatelyDeclaredConstraint);
+ if ((D->ExpandedParameterPack = Record.readInt()))
+ D->NumExpanded = Record.readInt();
+ }
+
if (Record.readInt())
- D->setDefaultArgument(GetTypeSourceInfo());
+ D->setDefaultArgument(readTypeSourceInfo());
}
void ASTDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
@@ -2301,7 +2341,7 @@ void ASTDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
D->getTrailingObjects<std::pair<QualType, TypeSourceInfo *>>();
for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) {
new (&TypesAndInfos[I].first) QualType(Record.readType());
- TypesAndInfos[I].second = GetTypeSourceInfo();
+ TypesAndInfos[I].second = readTypeSourceInfo();
}
} else {
// Rest of NonTypeTemplateParmDecl.
@@ -2339,13 +2379,24 @@ void ASTDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) {
D->AssertExprAndFailed.setPointer(Record.readExpr());
D->AssertExprAndFailed.setInt(Record.readInt());
D->Message = cast_or_null<StringLiteral>(Record.readExpr());
- D->RParenLoc = ReadSourceLocation();
+ D->RParenLoc = readSourceLocation();
}
void ASTDeclReader::VisitEmptyDecl(EmptyDecl *D) {
VisitDecl(D);
}
+void ASTDeclReader::VisitLifetimeExtendedTemporaryDecl(
+ LifetimeExtendedTemporaryDecl *D) {
+ VisitDecl(D);
+ D->ExtendingDecl = readDeclAs<ValueDecl>();
+ D->ExprWithTemporary = Record.readStmt();
+ if (Record.readInt())
+ D->Value = new (D->getASTContext()) APValue(Record.readAPValue());
+ D->ManglingNumber = Record.readInt();
+ mergeMergeable(D);
+}
+
std::pair<uint64_t, uint64_t>
ASTDeclReader::VisitDeclContext(DeclContext *DC) {
uint64_t LexicalOffset = ReadLocalOffset();
@@ -2356,7 +2407,7 @@ ASTDeclReader::VisitDeclContext(DeclContext *DC) {
template <typename T>
ASTDeclReader::RedeclarableResult
ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
- DeclID FirstDeclID = ReadDeclID();
+ DeclID FirstDeclID = readDeclID();
Decl *MergeWith = nullptr;
bool IsKeyDecl = ThisDeclID == FirstDeclID;
@@ -2382,13 +2433,13 @@ ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
// FIXME: Provide a known merge target to the second and subsequent such
// declaration.
for (unsigned I = 0; I != N - 1; ++I)
- MergeWith = ReadDecl();
+ MergeWith = readDecl();
RedeclOffset = ReadLocalOffset();
} else {
// This declaration was not the first local declaration. Read the first
// local declaration now, to trigger the import of other redeclarations.
- (void)ReadDecl();
+ (void)readDecl();
}
auto *FirstDecl = cast_or_null<T>(Reader.GetDecl(FirstDeclID));
@@ -2541,6 +2592,25 @@ static bool allowODRLikeMergeInC(NamedDecl *ND) {
return false;
}
+/// Attempts to merge LifetimeExtendedTemporaryDecl with
+/// identical class definitions from two different modules.
+void ASTDeclReader::mergeMergeable(LifetimeExtendedTemporaryDecl *D) {
+ // If modules are not available, there is no reason to perform this merge.
+ if (!Reader.getContext().getLangOpts().Modules)
+ return;
+
+ LifetimeExtendedTemporaryDecl *LETDecl = D;
+
+ LifetimeExtendedTemporaryDecl *&LookupResult =
+ Reader.LETemporaryForMerging[std::make_pair(
+ LETDecl->getExtendingDecl(), LETDecl->getManglingNumber())];
+ if (LookupResult)
+ Reader.getContext().setPrimaryMergedDecl(LETDecl,
+ LookupResult->getCanonicalDecl());
+ else
+ LookupResult = LETDecl;
+}
+
/// Attempts to merge the given declaration (D) with another declaration
/// of the same entity, for the case where the entity is not actually
/// redeclarable. This happens, for instance, when merging the fields of
@@ -2588,9 +2658,8 @@ void ASTDeclReader::VisitOMPAllocateDecl(OMPAllocateDecl *D) {
D->setVars(Vars);
SmallVector<OMPClause *, 8> Clauses;
Clauses.reserve(NumClauses);
- OMPClauseReader ClauseReader(Record);
for (unsigned I = 0; I != NumClauses; ++I)
- Clauses.push_back(ClauseReader.readClause());
+ Clauses.push_back(Record.readOMPClause());
D->setClauses(Clauses);
}
@@ -2599,15 +2668,14 @@ void ASTDeclReader::VisitOMPRequiresDecl(OMPRequiresDecl * D) {
unsigned NumClauses = D->clauselist_size();
SmallVector<OMPClause *, 8> Clauses;
Clauses.reserve(NumClauses);
- OMPClauseReader ClauseReader(Record);
for (unsigned I = 0; I != NumClauses; ++I)
- Clauses.push_back(ClauseReader.readClause());
+ Clauses.push_back(Record.readOMPClause());
D->setClauses(Clauses);
}
void ASTDeclReader::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) {
VisitValueDecl(D);
- D->setLocation(ReadSourceLocation());
+ D->setLocation(readSourceLocation());
Expr *In = Record.readExpr();
Expr *Out = Record.readExpr();
D->setCombinerData(In, Out);
@@ -2619,22 +2687,21 @@ void ASTDeclReader::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) {
Expr *Init = Record.readExpr();
auto IK = static_cast<OMPDeclareReductionDecl::InitKind>(Record.readInt());
D->setInitializer(Init, IK);
- D->PrevDeclInScope = ReadDeclID();
+ D->PrevDeclInScope = readDeclID();
}
void ASTDeclReader::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) {
VisitValueDecl(D);
- D->setLocation(ReadSourceLocation());
+ D->setLocation(readSourceLocation());
Expr *MapperVarRefE = Record.readExpr();
D->setMapperVarRef(MapperVarRefE);
D->VarName = Record.readDeclarationName();
- D->PrevDeclInScope = ReadDeclID();
+ D->PrevDeclInScope = readDeclID();
unsigned NumClauses = D->clauselist_size();
SmallVector<OMPClause *, 8> Clauses;
Clauses.reserve(NumClauses);
- OMPClauseReader ClauseReader(Record);
for (unsigned I = 0; I != NumClauses; ++I)
- Clauses.push_back(ClauseReader.readClause());
+ Clauses.push_back(Record.readOMPClause());
D->setClauses(Clauses);
}
@@ -2648,53 +2715,49 @@ void ASTDeclReader::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) {
namespace {
class AttrReader {
- ModuleFile *F;
- ASTReader *Reader;
- const ASTReader::RecordData &Record;
- unsigned &Idx;
+ ASTRecordReader &Reader;
public:
- AttrReader(ModuleFile &F, ASTReader &Reader,
- const ASTReader::RecordData &Record, unsigned &Idx)
- : F(&F), Reader(&Reader), Record(Record), Idx(Idx) {}
+ AttrReader(ASTRecordReader &Reader) : Reader(Reader) {}
- const uint64_t &readInt() { return Record[Idx++]; }
+ uint64_t readInt() {
+ return Reader.readInt();
+ }
SourceRange readSourceRange() {
- return Reader->ReadSourceRange(*F, Record, Idx);
+ return Reader.readSourceRange();
}
SourceLocation readSourceLocation() {
- return Reader->ReadSourceLocation(*F, Record, Idx);
+ return Reader.readSourceLocation();
}
- Expr *readExpr() { return Reader->ReadExpr(*F); }
+ Expr *readExpr() { return Reader.readExpr(); }
std::string readString() {
- return Reader->ReadString(Record, Idx);
+ return Reader.readString();
}
- TypeSourceInfo *getTypeSourceInfo() {
- return Reader->GetTypeSourceInfo(*F, Record, Idx);
+ TypeSourceInfo *readTypeSourceInfo() {
+ return Reader.readTypeSourceInfo();
}
- IdentifierInfo *getIdentifierInfo() {
- return Reader->GetIdentifierInfo(*F, Record, Idx);
+ IdentifierInfo *readIdentifier() {
+ return Reader.readIdentifier();
}
VersionTuple readVersionTuple() {
- return ASTReader::ReadVersionTuple(Record, Idx);
+ return Reader.readVersionTuple();
}
template <typename T> T *GetLocalDeclAs(uint32_t LocalID) {
- return cast_or_null<T>(Reader->GetLocalDecl(*F, LocalID));
+ return Reader.GetLocalDeclAs<T>(LocalID);
}
};
}
-Attr *ASTReader::ReadAttr(ModuleFile &M, const RecordData &Rec,
- unsigned &Idx) {
- AttrReader Record(M, *this, Rec, Idx);
+Attr *ASTRecordReader::readAttr() {
+ AttrReader Record(*this);
auto V = Record.readInt();
if (!V)
return nullptr;
@@ -2705,8 +2768,8 @@ Attr *ASTReader::ReadAttr(ModuleFile &M, const RecordData &Rec,
auto Kind = static_cast<attr::Kind>(V - 1);
ASTContext &Context = getContext();
- IdentifierInfo *AttrName = Record.getIdentifierInfo();
- IdentifierInfo *ScopeName = Record.getIdentifierInfo();
+ IdentifierInfo *AttrName = Record.readIdentifier();
+ IdentifierInfo *ScopeName = Record.readIdentifier();
SourceRange AttrRange = Record.readSourceRange();
SourceLocation ScopeLoc = Record.readSourceLocation();
unsigned ParsedKind = Record.readInt();
@@ -2724,9 +2787,9 @@ Attr *ASTReader::ReadAttr(ModuleFile &M, const RecordData &Rec,
}
/// Reads attributes from the current stream position.
-void ASTReader::ReadAttributes(ASTRecordReader &Record, AttrVec &Attrs) {
- for (unsigned I = 0, E = Record.readInt(); I != E; ++I)
- Attrs.push_back(Record.readAttr());
+void ASTRecordReader::readAttributes(AttrVec &Attrs) {
+ for (unsigned I = 0, E = readInt(); I != E; ++I)
+ Attrs.push_back(readAttr());
}
//===----------------------------------------------------------------------===//
@@ -3621,7 +3684,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
Deserializing ADecl(this);
auto Fail = [](const char *what, llvm::Error &&Err) {
- llvm::report_fatal_error(Twine("ASTReader::ReadDeclRecord failed ") + what +
+ llvm::report_fatal_error(Twine("ASTReader::readDeclRecord failed ") + what +
": " + toString(std::move(Err)));
};
@@ -3639,12 +3702,12 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
Expected<unsigned> MaybeDeclCode = Record.readRecord(DeclsCursor, Code);
if (!MaybeDeclCode)
llvm::report_fatal_error(
- "ASTReader::ReadDeclRecord failed reading decl code: " +
+ "ASTReader::readDeclRecord failed reading decl code: " +
toString(MaybeDeclCode.takeError()));
switch ((DeclCode)MaybeDeclCode.get()) {
case DECL_CONTEXT_LEXICAL:
case DECL_CONTEXT_VISIBLE:
- llvm_unreachable("Record cannot be de-serialized with ReadDeclRecord");
+ llvm_unreachable("Record cannot be de-serialized with readDeclRecord");
case DECL_TYPEDEF:
D = TypedefDecl::CreateDeserialized(Context, ID);
break;
@@ -3750,9 +3813,12 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
case DECL_FUNCTION_TEMPLATE:
D = FunctionTemplateDecl::CreateDeserialized(Context, ID);
break;
- case DECL_TEMPLATE_TYPE_PARM:
- D = TemplateTypeParmDecl::CreateDeserialized(Context, ID);
+ case DECL_TEMPLATE_TYPE_PARM: {
+ bool HasTypeConstraint = Record.readInt();
+ D = TemplateTypeParmDecl::CreateDeserialized(Context, ID,
+ HasTypeConstraint);
break;
+ }
case DECL_NON_TYPE_TEMPLATE_PARM:
D = NonTypeTemplateParmDecl::CreateDeserialized(Context, ID);
break;
@@ -3884,6 +3950,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
case DECL_EMPTY:
D = EmptyDecl::CreateDeserialized(Context, ID);
break;
+ case DECL_LIFETIME_EXTENDED_TEMPORARY:
+ D = LifetimeExtendedTemporaryDecl::CreateDeserialized(Context, ID);
+ break;
case DECL_OBJC_TYPE_PARAM:
D = ObjCTypeParamDecl::CreateDeserialized(Context, ID);
break;
@@ -4254,11 +4323,11 @@ void ASTDeclReader::UpdateDecl(Decl *D,
case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
// It will be added to the template's lazy specialization set.
- PendingLazySpecializationIDs.push_back(ReadDeclID());
+ PendingLazySpecializationIDs.push_back(readDeclID());
break;
case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: {
- auto *Anon = ReadDeclAs<NamespaceDecl>();
+ auto *Anon = readDeclAs<NamespaceDecl>();
// Each module has its own anonymous namespace, which is disjoint from
// any other module's anonymous namespaces, so don't attach the anonymous
@@ -4354,7 +4423,7 @@ void ASTDeclReader::UpdateDecl(Decl *D,
FD->setImplicitlyInline();
});
}
- FD->setInnerLocStart(ReadSourceLocation());
+ FD->setInnerLocStart(readSourceLocation());
ReadFunctionDefinition(FD);
assert(Record.getIdx() == Record.size() && "lazy body must be last");
break;
@@ -4379,7 +4448,7 @@ void ASTDeclReader::UpdateDecl(Decl *D,
}
auto TSK = (TemplateSpecializationKind)Record.readInt();
- SourceLocation POI = ReadSourceLocation();
+ SourceLocation POI = readSourceLocation();
if (MemberSpecializationInfo *MSInfo =
RD->getMemberSpecializationInfo()) {
MSInfo->setTemplateSpecializationKind(TSK);
@@ -4391,7 +4460,7 @@ void ASTDeclReader::UpdateDecl(Decl *D,
if (Record.readInt()) {
auto *PartialSpec =
- ReadDeclAs<ClassTemplatePartialSpecializationDecl>();
+ readDeclAs<ClassTemplatePartialSpecializationDecl>();
SmallVector<TemplateArgument, 8> TemplArgs;
Record.readTemplateArgumentList(TemplArgs);
auto *TemplArgList = TemplateArgumentList::CreateCopy(
@@ -4406,9 +4475,9 @@ void ASTDeclReader::UpdateDecl(Decl *D,
}
RD->setTagKind((TagTypeKind)Record.readInt());
- RD->setLocation(ReadSourceLocation());
- RD->setLocStart(ReadSourceLocation());
- RD->setBraceRange(ReadSourceRange());
+ RD->setLocation(readSourceLocation());
+ RD->setLocStart(readSourceLocation());
+ RD->setBraceRange(readSourceRange());
if (Record.readInt()) {
AttrVec Attrs;
@@ -4424,7 +4493,7 @@ void ASTDeclReader::UpdateDecl(Decl *D,
case UPD_CXX_RESOLVED_DTOR_DELETE: {
// Set the 'operator delete' directly to avoid emitting another update
// record.
- auto *Del = ReadDeclAs<FunctionDecl>();
+ auto *Del = readDeclAs<FunctionDecl>();
auto *First = cast<CXXDestructorDecl>(D->getCanonicalDecl());
auto *ThisArg = Record.readExpr();
// FIXME: Check consistency if we have an old and new operator delete.
@@ -4436,9 +4505,8 @@ void ASTDeclReader::UpdateDecl(Decl *D,
}
case UPD_CXX_RESOLVED_EXCEPTION_SPEC: {
- FunctionProtoType::ExceptionSpecInfo ESI;
SmallVector<QualType, 8> ExceptionStorage;
- Record.readExceptionSpec(ExceptionStorage, ESI);
+ auto ESI = Record.readExceptionSpecInfo(ExceptionStorage);
// Update this declaration's exception specification, if needed.
auto *FD = cast<FunctionDecl>(D);
@@ -4483,7 +4551,7 @@ void ASTDeclReader::UpdateDecl(Decl *D,
case UPD_DECL_MARKED_OPENMP_THREADPRIVATE:
D->addAttr(OMPThreadPrivateDeclAttr::CreateImplicit(
- Reader.getContext(), ReadSourceRange(),
+ Reader.getContext(), readSourceRange(),
AttributeCommonInfo::AS_Pragma));
break;
@@ -4491,7 +4559,7 @@ void ASTDeclReader::UpdateDecl(Decl *D,
auto AllocatorKind =
static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(Record.readInt());
Expr *Allocator = Record.readExpr();
- SourceRange SR = ReadSourceRange();
+ SourceRange SR = readSourceRange();
D->addAttr(OMPAllocateDeclAttr::CreateImplicit(
Reader.getContext(), AllocatorKind, Allocator, SR,
AttributeCommonInfo::AS_Pragma));
@@ -4513,7 +4581,7 @@ void ASTDeclReader::UpdateDecl(Decl *D,
OMPDeclareTargetDeclAttr::DevTypeTy DevType =
static_cast<OMPDeclareTargetDeclAttr::DevTypeTy>(Record.readInt());
D->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit(
- Reader.getContext(), MapType, DevType, ReadSourceRange(),
+ Reader.getContext(), MapType, DevType, readSourceRange(),
AttributeCommonInfo::AS_Pragma));
break;
}
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index a275e0c30579..f558c26b5f1e 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -11,7 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Serialization/ASTReader.h"
+#include "clang/Serialization/ASTRecordReader.h"
+#include "clang/AST/ASTConcept.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/AttrIterator.h"
#include "clang/AST/Decl.h"
@@ -66,45 +67,34 @@ using namespace serialization;
namespace clang {
class ASTStmtReader : public StmtVisitor<ASTStmtReader> {
- friend class OMPClauseReader;
-
ASTRecordReader &Record;
llvm::BitstreamCursor &DeclsCursor;
- SourceLocation ReadSourceLocation() {
+ SourceLocation readSourceLocation() {
return Record.readSourceLocation();
}
- SourceRange ReadSourceRange() {
+ SourceRange readSourceRange() {
return Record.readSourceRange();
}
- std::string ReadString() {
+ std::string readString() {
return Record.readString();
}
- TypeSourceInfo *GetTypeSourceInfo() {
- return Record.getTypeSourceInfo();
+ TypeSourceInfo *readTypeSourceInfo() {
+ return Record.readTypeSourceInfo();
}
- Decl *ReadDecl() {
+ Decl *readDecl() {
return Record.readDecl();
}
template<typename T>
- T *ReadDeclAs() {
+ T *readDeclAs() {
return Record.readDeclAs<T>();
}
- void ReadDeclarationNameLoc(DeclarationNameLoc &DNLoc,
- DeclarationName Name) {
- Record.readDeclarationNameLoc(DNLoc, Name);
- }
-
- void ReadDeclarationNameInfo(DeclarationNameInfo &NameInfo) {
- Record.readDeclarationNameInfo(NameInfo);
- }
-
public:
ASTStmtReader(ASTRecordReader &Record, llvm::BitstreamCursor &Cursor)
: Record(Record), DeclsCursor(Cursor) {}
@@ -137,10 +127,10 @@ namespace clang {
void ASTStmtReader::ReadTemplateKWAndArgsInfo(ASTTemplateKWAndArgsInfo &Args,
TemplateArgumentLoc *ArgsLocArray,
unsigned NumTemplateArgs) {
- SourceLocation TemplateKWLoc = ReadSourceLocation();
+ SourceLocation TemplateKWLoc = readSourceLocation();
TemplateArgumentListInfo ArgInfo;
- ArgInfo.setLAngleLoc(ReadSourceLocation());
- ArgInfo.setRAngleLoc(ReadSourceLocation());
+ ArgInfo.setLAngleLoc(readSourceLocation());
+ ArgInfo.setRAngleLoc(readSourceLocation());
for (unsigned i = 0; i != NumTemplateArgs; ++i)
ArgInfo.addArgument(Record.readTemplateArgumentLoc());
Args.initializeFrom(TemplateKWLoc, ArgInfo, ArgsLocArray);
@@ -153,7 +143,7 @@ void ASTStmtReader::VisitStmt(Stmt *S) {
void ASTStmtReader::VisitNullStmt(NullStmt *S) {
VisitStmt(S);
- S->setSemiLoc(ReadSourceLocation());
+ S->setSemiLoc(readSourceLocation());
S->NullStmtBits.HasLeadingEmptyMacro = Record.readInt();
}
@@ -164,15 +154,15 @@ void ASTStmtReader::VisitCompoundStmt(CompoundStmt *S) {
while (NumStmts--)
Stmts.push_back(Record.readSubStmt());
S->setStmts(Stmts);
- S->CompoundStmtBits.LBraceLoc = ReadSourceLocation();
- S->RBraceLoc = ReadSourceLocation();
+ S->CompoundStmtBits.LBraceLoc = readSourceLocation();
+ S->RBraceLoc = readSourceLocation();
}
void ASTStmtReader::VisitSwitchCase(SwitchCase *S) {
VisitStmt(S);
Record.recordSwitchCaseID(S, Record.readInt());
- S->setKeywordLoc(ReadSourceLocation());
- S->setColonLoc(ReadSourceLocation());
+ S->setKeywordLoc(readSourceLocation());
+ S->setColonLoc(readSourceLocation());
}
void ASTStmtReader::VisitCaseStmt(CaseStmt *S) {
@@ -182,7 +172,7 @@ void ASTStmtReader::VisitCaseStmt(CaseStmt *S) {
S->setSubStmt(Record.readSubStmt());
if (CaseStmtIsGNURange) {
S->setRHS(Record.readSubExpr());
- S->setEllipsisLoc(ReadSourceLocation());
+ S->setEllipsisLoc(readSourceLocation());
}
}
@@ -193,11 +183,11 @@ void ASTStmtReader::VisitDefaultStmt(DefaultStmt *S) {
void ASTStmtReader::VisitLabelStmt(LabelStmt *S) {
VisitStmt(S);
- auto *LD = ReadDeclAs<LabelDecl>();
+ auto *LD = readDeclAs<LabelDecl>();
LD->setStmt(S);
S->setDecl(LD);
S->setSubStmt(Record.readSubStmt());
- S->setIdentLoc(ReadSourceLocation());
+ S->setIdentLoc(readSourceLocation());
}
void ASTStmtReader::VisitAttributedStmt(AttributedStmt *S) {
@@ -213,7 +203,7 @@ void ASTStmtReader::VisitAttributedStmt(AttributedStmt *S) {
assert(NumAttrs == Attrs.size());
std::copy(Attrs.begin(), Attrs.end(), S->getAttrArrayPtr());
S->SubStmt = Record.readSubStmt();
- S->AttributedStmtBits.AttrLoc = ReadSourceLocation();
+ S->AttributedStmtBits.AttrLoc = readSourceLocation();
}
void ASTStmtReader::VisitIfStmt(IfStmt *S) {
@@ -229,13 +219,13 @@ void ASTStmtReader::VisitIfStmt(IfStmt *S) {
if (HasElse)
S->setElse(Record.readSubStmt());
if (HasVar)
- S->setConditionVariable(Record.getContext(), ReadDeclAs<VarDecl>());
+ S->setConditionVariable(Record.getContext(), readDeclAs<VarDecl>());
if (HasInit)
S->setInit(Record.readSubStmt());
- S->setIfLoc(ReadSourceLocation());
+ S->setIfLoc(readSourceLocation());
if (HasElse)
- S->setElseLoc(ReadSourceLocation());
+ S->setElseLoc(readSourceLocation());
}
void ASTStmtReader::VisitSwitchStmt(SwitchStmt *S) {
@@ -252,9 +242,9 @@ void ASTStmtReader::VisitSwitchStmt(SwitchStmt *S) {
if (HasInit)
S->setInit(Record.readSubStmt());
if (HasVar)
- S->setConditionVariable(Record.getContext(), ReadDeclAs<VarDecl>());
+ S->setConditionVariable(Record.getContext(), readDeclAs<VarDecl>());
- S->setSwitchLoc(ReadSourceLocation());
+ S->setSwitchLoc(readSourceLocation());
SwitchCase *PrevSC = nullptr;
for (auto E = Record.size(); Record.getIdx() != E; ) {
@@ -276,54 +266,54 @@ void ASTStmtReader::VisitWhileStmt(WhileStmt *S) {
S->setCond(Record.readSubExpr());
S->setBody(Record.readSubStmt());
if (HasVar)
- S->setConditionVariable(Record.getContext(), ReadDeclAs<VarDecl>());
+ S->setConditionVariable(Record.getContext(), readDeclAs<VarDecl>());
- S->setWhileLoc(ReadSourceLocation());
+ S->setWhileLoc(readSourceLocation());
}
void ASTStmtReader::VisitDoStmt(DoStmt *S) {
VisitStmt(S);
S->setCond(Record.readSubExpr());
S->setBody(Record.readSubStmt());
- S->setDoLoc(ReadSourceLocation());
- S->setWhileLoc(ReadSourceLocation());
- S->setRParenLoc(ReadSourceLocation());
+ S->setDoLoc(readSourceLocation());
+ S->setWhileLoc(readSourceLocation());
+ S->setRParenLoc(readSourceLocation());
}
void ASTStmtReader::VisitForStmt(ForStmt *S) {
VisitStmt(S);
S->setInit(Record.readSubStmt());
S->setCond(Record.readSubExpr());
- S->setConditionVariable(Record.getContext(), ReadDeclAs<VarDecl>());
+ S->setConditionVariable(Record.getContext(), readDeclAs<VarDecl>());
S->setInc(Record.readSubExpr());
S->setBody(Record.readSubStmt());
- S->setForLoc(ReadSourceLocation());
- S->setLParenLoc(ReadSourceLocation());
- S->setRParenLoc(ReadSourceLocation());
+ S->setForLoc(readSourceLocation());
+ S->setLParenLoc(readSourceLocation());
+ S->setRParenLoc(readSourceLocation());
}
void ASTStmtReader::VisitGotoStmt(GotoStmt *S) {
VisitStmt(S);
- S->setLabel(ReadDeclAs<LabelDecl>());
- S->setGotoLoc(ReadSourceLocation());
- S->setLabelLoc(ReadSourceLocation());
+ S->setLabel(readDeclAs<LabelDecl>());
+ S->setGotoLoc(readSourceLocation());
+ S->setLabelLoc(readSourceLocation());
}
void ASTStmtReader::VisitIndirectGotoStmt(IndirectGotoStmt *S) {
VisitStmt(S);
- S->setGotoLoc(ReadSourceLocation());
- S->setStarLoc(ReadSourceLocation());
+ S->setGotoLoc(readSourceLocation());
+ S->setStarLoc(readSourceLocation());
S->setTarget(Record.readSubExpr());
}
void ASTStmtReader::VisitContinueStmt(ContinueStmt *S) {
VisitStmt(S);
- S->setContinueLoc(ReadSourceLocation());
+ S->setContinueLoc(readSourceLocation());
}
void ASTStmtReader::VisitBreakStmt(BreakStmt *S) {
VisitStmt(S);
- S->setBreakLoc(ReadSourceLocation());
+ S->setBreakLoc(readSourceLocation());
}
void ASTStmtReader::VisitReturnStmt(ReturnStmt *S) {
@@ -333,25 +323,25 @@ void ASTStmtReader::VisitReturnStmt(ReturnStmt *S) {
S->setRetValue(Record.readSubExpr());
if (HasNRVOCandidate)
- S->setNRVOCandidate(ReadDeclAs<VarDecl>());
+ S->setNRVOCandidate(readDeclAs<VarDecl>());
- S->setReturnLoc(ReadSourceLocation());
+ S->setReturnLoc(readSourceLocation());
}
void ASTStmtReader::VisitDeclStmt(DeclStmt *S) {
VisitStmt(S);
- S->setStartLoc(ReadSourceLocation());
- S->setEndLoc(ReadSourceLocation());
+ S->setStartLoc(readSourceLocation());
+ S->setEndLoc(readSourceLocation());
if (Record.size() - Record.getIdx() == 1) {
// Single declaration
- S->setDeclGroup(DeclGroupRef(ReadDecl()));
+ S->setDeclGroup(DeclGroupRef(readDecl()));
} else {
SmallVector<Decl *, 16> Decls;
int N = Record.size() - Record.getIdx();
Decls.reserve(N);
for (int I = 0; I < N; ++I)
- Decls.push_back(ReadDecl());
+ Decls.push_back(readDecl());
S->setDeclGroup(DeclGroupRef(DeclGroup::Create(Record.getContext(),
Decls.data(),
Decls.size())));
@@ -363,7 +353,7 @@ void ASTStmtReader::VisitAsmStmt(AsmStmt *S) {
S->NumOutputs = Record.readInt();
S->NumInputs = Record.readInt();
S->NumClobbers = Record.readInt();
- S->setAsmLoc(ReadSourceLocation());
+ S->setAsmLoc(readSourceLocation());
S->setVolatile(Record.readInt());
S->setSimple(Record.readInt());
}
@@ -371,7 +361,7 @@ void ASTStmtReader::VisitAsmStmt(AsmStmt *S) {
void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) {
VisitAsmStmt(S);
S->NumLabels = Record.readInt();
- S->setRParenLoc(ReadSourceLocation());
+ S->setRParenLoc(readSourceLocation());
S->setAsmString(cast_or_null<StringLiteral>(Record.readSubStmt()));
unsigned NumOutputs = S->getNumOutputs();
@@ -384,7 +374,7 @@ void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) {
SmallVector<StringLiteral*, 16> Constraints;
SmallVector<Stmt*, 16> Exprs;
for (unsigned I = 0, N = NumOutputs + NumInputs; I != N; ++I) {
- Names.push_back(Record.getIdentifierInfo());
+ Names.push_back(Record.readIdentifier());
Constraints.push_back(cast_or_null<StringLiteral>(Record.readSubStmt()));
Exprs.push_back(Record.readSubStmt());
}
@@ -407,10 +397,10 @@ void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) {
void ASTStmtReader::VisitMSAsmStmt(MSAsmStmt *S) {
VisitAsmStmt(S);
- S->LBraceLoc = ReadSourceLocation();
- S->EndLoc = ReadSourceLocation();
+ S->LBraceLoc = readSourceLocation();
+ S->EndLoc = readSourceLocation();
S->NumAsmToks = Record.readInt();
- std::string AsmStr = ReadString();
+ std::string AsmStr = readString();
// Read the tokens.
SmallVector<Token, 16> AsmToks;
@@ -428,7 +418,7 @@ void ASTStmtReader::VisitMSAsmStmt(MSAsmStmt *S) {
ClobbersData.reserve(S->NumClobbers);
Clobbers.reserve(S->NumClobbers);
for (unsigned i = 0, e = S->NumClobbers; i != e; ++i) {
- ClobbersData.push_back(ReadString());
+ ClobbersData.push_back(readString());
Clobbers.push_back(ClobbersData.back());
}
@@ -442,7 +432,7 @@ void ASTStmtReader::VisitMSAsmStmt(MSAsmStmt *S) {
Constraints.reserve(NumOperands);
for (unsigned i = 0; i != NumOperands; ++i) {
Exprs.push_back(cast<Expr>(Record.readSubStmt()));
- ConstraintsData.push_back(ReadString());
+ ConstraintsData.push_back(readString());
Constraints.push_back(ConstraintsData.back());
}
@@ -470,7 +460,7 @@ void ASTStmtReader::VisitCoreturnStmt(CoreturnStmt *S) {
void ASTStmtReader::VisitCoawaitExpr(CoawaitExpr *E) {
VisitExpr(E);
- E->KeywordLoc = ReadSourceLocation();
+ E->KeywordLoc = readSourceLocation();
for (auto &SubExpr: E->SubExprs)
SubExpr = Record.readSubStmt();
E->OpaqueValue = cast_or_null<OpaqueValueExpr>(Record.readSubStmt());
@@ -479,7 +469,7 @@ void ASTStmtReader::VisitCoawaitExpr(CoawaitExpr *E) {
void ASTStmtReader::VisitCoyieldExpr(CoyieldExpr *E) {
VisitExpr(E);
- E->KeywordLoc = ReadSourceLocation();
+ E->KeywordLoc = readSourceLocation();
for (auto &SubExpr: E->SubExprs)
SubExpr = Record.readSubStmt();
E->OpaqueValue = cast_or_null<OpaqueValueExpr>(Record.readSubStmt());
@@ -487,7 +477,7 @@ void ASTStmtReader::VisitCoyieldExpr(CoyieldExpr *E) {
void ASTStmtReader::VisitDependentCoawaitExpr(DependentCoawaitExpr *E) {
VisitExpr(E);
- E->KeywordLoc = ReadSourceLocation();
+ E->KeywordLoc = readSourceLocation();
for (auto &SubExpr: E->SubExprs)
SubExpr = Record.readSubStmt();
}
@@ -495,9 +485,9 @@ void ASTStmtReader::VisitDependentCoawaitExpr(DependentCoawaitExpr *E) {
void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) {
VisitStmt(S);
Record.skipInts(1);
- S->setCapturedDecl(ReadDeclAs<CapturedDecl>());
+ S->setCapturedDecl(readDeclAs<CapturedDecl>());
S->setCapturedRegionKind(static_cast<CapturedRegionKind>(Record.readInt()));
- S->setCapturedRecordDecl(ReadDeclAs<RecordDecl>());
+ S->setCapturedRecordDecl(readDeclAs<RecordDecl>());
// Capture inits
for (CapturedStmt::capture_init_iterator I = S->capture_init_begin(),
@@ -511,10 +501,10 @@ void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) {
// Captures
for (auto &I : S->captures()) {
- I.VarAndKind.setPointer(ReadDeclAs<VarDecl>());
+ I.VarAndKind.setPointer(readDeclAs<VarDecl>());
I.VarAndKind.setInt(
static_cast<CapturedStmt::VariableCaptureKind>(Record.readInt()));
- I.Loc = ReadSourceLocation();
+ I.Loc = readSourceLocation();
}
}
@@ -553,7 +543,7 @@ void ASTStmtReader::VisitPredefinedExpr(PredefinedExpr *E) {
bool HasFunctionName = Record.readInt();
E->PredefinedExprBits.HasFunctionName = HasFunctionName;
E->PredefinedExprBits.Kind = Record.readInt();
- E->setLocation(ReadSourceLocation());
+ E->setLocation(readSourceLocation());
if (HasFunctionName)
E->setFunctionName(cast<StringLiteral>(Record.readSubExpr()));
}
@@ -576,27 +566,27 @@ void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) {
NestedNameSpecifierLoc(Record.readNestedNameSpecifierLoc());
if (E->hasFoundDecl())
- *E->getTrailingObjects<NamedDecl *>() = ReadDeclAs<NamedDecl>();
+ *E->getTrailingObjects<NamedDecl *>() = readDeclAs<NamedDecl>();
if (E->hasTemplateKWAndArgsInfo())
ReadTemplateKWAndArgsInfo(
*E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(),
E->getTrailingObjects<TemplateArgumentLoc>(), NumTemplateArgs);
- E->setDecl(ReadDeclAs<ValueDecl>());
- E->setLocation(ReadSourceLocation());
- ReadDeclarationNameLoc(E->DNLoc, E->getDecl()->getDeclName());
+ E->setDecl(readDeclAs<ValueDecl>());
+ E->setLocation(readSourceLocation());
+ E->DNLoc = Record.readDeclarationNameLoc(E->getDecl()->getDeclName());
}
void ASTStmtReader::VisitIntegerLiteral(IntegerLiteral *E) {
VisitExpr(E);
- E->setLocation(ReadSourceLocation());
+ E->setLocation(readSourceLocation());
E->setValue(Record.getContext(), Record.readAPInt());
}
void ASTStmtReader::VisitFixedPointLiteral(FixedPointLiteral *E) {
VisitExpr(E);
- E->setLocation(ReadSourceLocation());
+ E->setLocation(readSourceLocation());
E->setValue(Record.getContext(), Record.readAPInt());
}
@@ -606,7 +596,7 @@ void ASTStmtReader::VisitFloatingLiteral(FloatingLiteral *E) {
static_cast<llvm::APFloatBase::Semantics>(Record.readInt()));
E->setExact(Record.readInt());
E->setValue(Record.getContext(), Record.readAPFloat(E->getSemantics()));
- E->setLocation(ReadSourceLocation());
+ E->setLocation(readSourceLocation());
}
void ASTStmtReader::VisitImaginaryLiteral(ImaginaryLiteral *E) {
@@ -639,7 +629,7 @@ void ASTStmtReader::VisitStringLiteral(StringLiteral *E) {
// Deserialize the trailing array of SourceLocation.
for (unsigned I = 0; I < NumConcatenated; ++I)
- E->setStrTokenLoc(I, ReadSourceLocation());
+ E->setStrTokenLoc(I, readSourceLocation());
// Deserialize the trailing array of char holding the string data.
char *StrData = E->getStrDataAsChar();
@@ -650,14 +640,14 @@ void ASTStmtReader::VisitStringLiteral(StringLiteral *E) {
void ASTStmtReader::VisitCharacterLiteral(CharacterLiteral *E) {
VisitExpr(E);
E->setValue(Record.readInt());
- E->setLocation(ReadSourceLocation());
+ E->setLocation(readSourceLocation());
E->setKind(static_cast<CharacterLiteral::CharacterKind>(Record.readInt()));
}
void ASTStmtReader::VisitParenExpr(ParenExpr *E) {
VisitExpr(E);
- E->setLParen(ReadSourceLocation());
- E->setRParen(ReadSourceLocation());
+ E->setLParen(readSourceLocation());
+ E->setRParen(readSourceLocation());
E->setSubExpr(Record.readSubExpr());
}
@@ -667,15 +657,15 @@ void ASTStmtReader::VisitParenListExpr(ParenListExpr *E) {
assert((NumExprs == E->getNumExprs()) && "Wrong NumExprs!");
for (unsigned I = 0; I != NumExprs; ++I)
E->getTrailingObjects<Stmt *>()[I] = Record.readSubStmt();
- E->LParenLoc = ReadSourceLocation();
- E->RParenLoc = ReadSourceLocation();
+ E->LParenLoc = readSourceLocation();
+ E->RParenLoc = readSourceLocation();
}
void ASTStmtReader::VisitUnaryOperator(UnaryOperator *E) {
VisitExpr(E);
E->setSubExpr(Record.readSubExpr());
E->setOpcode((UnaryOperator::Opcode)Record.readInt());
- E->setOperatorLoc(ReadSourceLocation());
+ E->setOperatorLoc(readSourceLocation());
E->setCanOverflow(Record.readInt());
}
@@ -685,13 +675,13 @@ void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) {
Record.skipInts(1);
assert(E->getNumExpressions() == Record.peekInt());
Record.skipInts(1);
- E->setOperatorLoc(ReadSourceLocation());
- E->setRParenLoc(ReadSourceLocation());
- E->setTypeSourceInfo(GetTypeSourceInfo());
+ E->setOperatorLoc(readSourceLocation());
+ E->setRParenLoc(readSourceLocation());
+ E->setTypeSourceInfo(readTypeSourceInfo());
for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) {
auto Kind = static_cast<OffsetOfNode::Kind>(Record.readInt());
- SourceLocation Start = ReadSourceLocation();
- SourceLocation End = ReadSourceLocation();
+ SourceLocation Start = readSourceLocation();
+ SourceLocation End = readSourceLocation();
switch (Kind) {
case OffsetOfNode::Array:
E->setComponent(I, OffsetOfNode(Start, Record.readInt(), End));
@@ -699,13 +689,13 @@ void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) {
case OffsetOfNode::Field:
E->setComponent(
- I, OffsetOfNode(Start, ReadDeclAs<FieldDecl>(), End));
+ I, OffsetOfNode(Start, readDeclAs<FieldDecl>(), End));
break;
case OffsetOfNode::Identifier:
E->setComponent(
I,
- OffsetOfNode(Start, Record.getIdentifierInfo(), End));
+ OffsetOfNode(Start, Record.readIdentifier(), End));
break;
case OffsetOfNode::Base: {
@@ -728,10 +718,10 @@ void ASTStmtReader::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) {
E->setArgument(Record.readSubExpr());
Record.skipInts(1);
} else {
- E->setArgument(GetTypeSourceInfo());
+ E->setArgument(readTypeSourceInfo());
}
- E->setOperatorLoc(ReadSourceLocation());
- E->setRParenLoc(ReadSourceLocation());
+ E->setOperatorLoc(readSourceLocation());
+ E->setRParenLoc(readSourceLocation());
}
void ASTStmtReader::VisitConceptSpecializationExpr(
@@ -740,23 +730,40 @@ void ASTStmtReader::VisitConceptSpecializationExpr(
unsigned NumTemplateArgs = Record.readInt();
E->NestedNameSpec = Record.readNestedNameSpecifierLoc();
E->TemplateKWLoc = Record.readSourceLocation();
- E->ConceptNameLoc = Record.readSourceLocation();
- E->FoundDecl = ReadDeclAs<NamedDecl>();
- E->NamedConcept.setPointer(ReadDeclAs<ConceptDecl>());
- const ASTTemplateArgumentListInfo *ArgsAsWritten =
- Record.readASTTemplateArgumentListInfo();
+ E->ConceptName = Record.readDeclarationNameInfo();
+ E->NamedConcept = readDeclAs<ConceptDecl>();
+ E->ArgsAsWritten = Record.readASTTemplateArgumentListInfo();
llvm::SmallVector<TemplateArgument, 4> Args;
for (unsigned I = 0; I < NumTemplateArgs; ++I)
Args.push_back(Record.readTemplateArgument());
- E->setTemplateArguments(ArgsAsWritten, Args);
- E->NamedConcept.setInt(Record.readInt() == 1);
+ E->setTemplateArguments(Args);
+ ConstraintSatisfaction Satisfaction;
+ Satisfaction.IsSatisfied = Record.readInt();
+ if (!Satisfaction.IsSatisfied) {
+ unsigned NumDetailRecords = Record.readInt();
+ for (unsigned i = 0; i != NumDetailRecords; ++i) {
+ Expr *ConstraintExpr = Record.readExpr();
+ bool IsDiagnostic = Record.readInt();
+ if (IsDiagnostic) {
+ SourceLocation DiagLocation = Record.readSourceLocation();
+ std::string DiagMessage = Record.readString();
+ Satisfaction.Details.emplace_back(
+ ConstraintExpr, new (Record.getContext())
+ ConstraintSatisfaction::SubstitutionDiagnostic{
+ DiagLocation, DiagMessage});
+ } else
+ Satisfaction.Details.emplace_back(ConstraintExpr, Record.readExpr());
+ }
+ }
+ E->Satisfaction = ASTConstraintSatisfaction::Create(Record.getContext(),
+ Satisfaction);
}
void ASTStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
VisitExpr(E);
E->setLHS(Record.readSubExpr());
E->setRHS(Record.readSubExpr());
- E->setRBracketLoc(ReadSourceLocation());
+ E->setRBracketLoc(readSourceLocation());
}
void ASTStmtReader::VisitOMPArraySectionExpr(OMPArraySectionExpr *E) {
@@ -764,15 +771,15 @@ void ASTStmtReader::VisitOMPArraySectionExpr(OMPArraySectionExpr *E) {
E->setBase(Record.readSubExpr());
E->setLowerBound(Record.readSubExpr());
E->setLength(Record.readSubExpr());
- E->setColonLoc(ReadSourceLocation());
- E->setRBracketLoc(ReadSourceLocation());
+ E->setColonLoc(readSourceLocation());
+ E->setRBracketLoc(readSourceLocation());
}
void ASTStmtReader::VisitCallExpr(CallExpr *E) {
VisitExpr(E);
unsigned NumArgs = Record.readInt();
assert((NumArgs == E->getNumArgs()) && "Wrong NumArgs!");
- E->setRParenLoc(ReadSourceLocation());
+ E->setRParenLoc(readSourceLocation());
E->setCallee(Record.readSubExpr());
for (unsigned I = 0; I != NumArgs; ++I)
E->setArg(I, Record.readSubExpr());
@@ -793,7 +800,7 @@ void ASTStmtReader::VisitMemberExpr(MemberExpr *E) {
E->Base = Record.readSubExpr();
E->MemberDecl = Record.readDeclAs<ValueDecl>();
- Record.readDeclarationNameLoc(E->MemberDNLoc, E->MemberDecl->getDeclName());
+ E->MemberDNLoc = Record.readDeclarationNameLoc(E->MemberDecl->getDeclName());
E->MemberLoc = Record.readSourceLocation();
E->MemberExprBits.IsArrow = Record.readInt();
E->MemberExprBits.HasQualifierOrFoundDecl = HasQualifier || HasFoundDecl;
@@ -830,8 +837,8 @@ void ASTStmtReader::VisitMemberExpr(MemberExpr *E) {
void ASTStmtReader::VisitObjCIsaExpr(ObjCIsaExpr *E) {
VisitExpr(E);
E->setBase(Record.readSubExpr());
- E->setIsaMemberLoc(ReadSourceLocation());
- E->setOpLoc(ReadSourceLocation());
+ E->setIsaMemberLoc(readSourceLocation());
+ E->setOpLoc(readSourceLocation());
E->setArrow(Record.readInt());
}
@@ -844,8 +851,8 @@ VisitObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) {
void ASTStmtReader::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
VisitExplicitCastExpr(E);
- E->LParenLoc = ReadSourceLocation();
- E->BridgeKeywordLoc = ReadSourceLocation();
+ E->LParenLoc = readSourceLocation();
+ E->BridgeKeywordLoc = readSourceLocation();
E->Kind = Record.readInt();
}
@@ -868,7 +875,7 @@ void ASTStmtReader::VisitBinaryOperator(BinaryOperator *E) {
E->setLHS(Record.readSubExpr());
E->setRHS(Record.readSubExpr());
E->setOpcode((BinaryOperator::Opcode)Record.readInt());
- E->setOperatorLoc(ReadSourceLocation());
+ E->setOperatorLoc(readSourceLocation());
E->setFPFeatures(FPOptions(Record.readInt()));
}
@@ -883,8 +890,8 @@ void ASTStmtReader::VisitConditionalOperator(ConditionalOperator *E) {
E->SubExprs[ConditionalOperator::COND] = Record.readSubExpr();
E->SubExprs[ConditionalOperator::LHS] = Record.readSubExpr();
E->SubExprs[ConditionalOperator::RHS] = Record.readSubExpr();
- E->QuestionLoc = ReadSourceLocation();
- E->ColonLoc = ReadSourceLocation();
+ E->QuestionLoc = readSourceLocation();
+ E->ColonLoc = readSourceLocation();
}
void
@@ -895,8 +902,8 @@ ASTStmtReader::VisitBinaryConditionalOperator(BinaryConditionalOperator *E) {
E->SubExprs[BinaryConditionalOperator::COND] = Record.readSubExpr();
E->SubExprs[BinaryConditionalOperator::LHS] = Record.readSubExpr();
E->SubExprs[BinaryConditionalOperator::RHS] = Record.readSubExpr();
- E->QuestionLoc = ReadSourceLocation();
- E->ColonLoc = ReadSourceLocation();
+ E->QuestionLoc = readSourceLocation();
+ E->ColonLoc = readSourceLocation();
}
void ASTStmtReader::VisitImplicitCastExpr(ImplicitCastExpr *E) {
@@ -906,19 +913,19 @@ void ASTStmtReader::VisitImplicitCastExpr(ImplicitCastExpr *E) {
void ASTStmtReader::VisitExplicitCastExpr(ExplicitCastExpr *E) {
VisitCastExpr(E);
- E->setTypeInfoAsWritten(GetTypeSourceInfo());
+ E->setTypeInfoAsWritten(readTypeSourceInfo());
}
void ASTStmtReader::VisitCStyleCastExpr(CStyleCastExpr *E) {
VisitExplicitCastExpr(E);
- E->setLParenLoc(ReadSourceLocation());
- E->setRParenLoc(ReadSourceLocation());
+ E->setLParenLoc(readSourceLocation());
+ E->setRParenLoc(readSourceLocation());
}
void ASTStmtReader::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
VisitExpr(E);
- E->setLParenLoc(ReadSourceLocation());
- E->setTypeSourceInfo(GetTypeSourceInfo());
+ E->setLParenLoc(readSourceLocation());
+ E->setTypeSourceInfo(readTypeSourceInfo());
E->setInitializer(Record.readSubExpr());
E->setFileScope(Record.readInt());
}
@@ -926,23 +933,23 @@ void ASTStmtReader::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
void ASTStmtReader::VisitExtVectorElementExpr(ExtVectorElementExpr *E) {
VisitExpr(E);
E->setBase(Record.readSubExpr());
- E->setAccessor(Record.getIdentifierInfo());
- E->setAccessorLoc(ReadSourceLocation());
+ E->setAccessor(Record.readIdentifier());
+ E->setAccessorLoc(readSourceLocation());
}
void ASTStmtReader::VisitInitListExpr(InitListExpr *E) {
VisitExpr(E);
if (auto *SyntForm = cast_or_null<InitListExpr>(Record.readSubStmt()))
E->setSyntacticForm(SyntForm);
- E->setLBraceLoc(ReadSourceLocation());
- E->setRBraceLoc(ReadSourceLocation());
+ E->setLBraceLoc(readSourceLocation());
+ E->setRBraceLoc(readSourceLocation());
bool isArrayFiller = Record.readInt();
Expr *filler = nullptr;
if (isArrayFiller) {
filler = Record.readSubExpr();
E->ArrayFillerOrUnionFieldInit = filler;
} else
- E->ArrayFillerOrUnionFieldInit = ReadDeclAs<FieldDecl>();
+ E->ArrayFillerOrUnionFieldInit = readDeclAs<FieldDecl>();
E->sawArrayRangeDesignator(Record.readInt());
unsigned NumInits = Record.readInt();
E->reserveInits(Record.getContext(), NumInits);
@@ -965,16 +972,16 @@ void ASTStmtReader::VisitDesignatedInitExpr(DesignatedInitExpr *E) {
assert(NumSubExprs == E->getNumSubExprs() && "Wrong number of subexprs");
for (unsigned I = 0; I != NumSubExprs; ++I)
E->setSubExpr(I, Record.readSubExpr());
- E->setEqualOrColonLoc(ReadSourceLocation());
+ E->setEqualOrColonLoc(readSourceLocation());
E->setGNUSyntax(Record.readInt());
SmallVector<Designator, 4> Designators;
while (Record.getIdx() < Record.size()) {
switch ((DesignatorTypes)Record.readInt()) {
case DESIG_FIELD_DECL: {
- auto *Field = ReadDeclAs<FieldDecl>();
- SourceLocation DotLoc = ReadSourceLocation();
- SourceLocation FieldLoc = ReadSourceLocation();
+ auto *Field = readDeclAs<FieldDecl>();
+ SourceLocation DotLoc = readSourceLocation();
+ SourceLocation FieldLoc = readSourceLocation();
Designators.push_back(Designator(Field->getIdentifier(), DotLoc,
FieldLoc));
Designators.back().setField(Field);
@@ -982,26 +989,26 @@ void ASTStmtReader::VisitDesignatedInitExpr(DesignatedInitExpr *E) {
}
case DESIG_FIELD_NAME: {
- const IdentifierInfo *Name = Record.getIdentifierInfo();
- SourceLocation DotLoc = ReadSourceLocation();
- SourceLocation FieldLoc = ReadSourceLocation();
+ const IdentifierInfo *Name = Record.readIdentifier();
+ SourceLocation DotLoc = readSourceLocation();
+ SourceLocation FieldLoc = readSourceLocation();
Designators.push_back(Designator(Name, DotLoc, FieldLoc));
break;
}
case DESIG_ARRAY: {
unsigned Index = Record.readInt();
- SourceLocation LBracketLoc = ReadSourceLocation();
- SourceLocation RBracketLoc = ReadSourceLocation();
+ SourceLocation LBracketLoc = readSourceLocation();
+ SourceLocation RBracketLoc = readSourceLocation();
Designators.push_back(Designator(Index, LBracketLoc, RBracketLoc));
break;
}
case DESIG_ARRAY_RANGE: {
unsigned Index = Record.readInt();
- SourceLocation LBracketLoc = ReadSourceLocation();
- SourceLocation EllipsisLoc = ReadSourceLocation();
- SourceLocation RBracketLoc = ReadSourceLocation();
+ SourceLocation LBracketLoc = readSourceLocation();
+ SourceLocation EllipsisLoc = readSourceLocation();
+ SourceLocation RBracketLoc = readSourceLocation();
Designators.push_back(Designator(Index, LBracketLoc, EllipsisLoc,
RBracketLoc));
break;
@@ -1039,32 +1046,32 @@ void ASTStmtReader::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
void ASTStmtReader::VisitVAArgExpr(VAArgExpr *E) {
VisitExpr(E);
E->setSubExpr(Record.readSubExpr());
- E->setWrittenTypeInfo(GetTypeSourceInfo());
- E->setBuiltinLoc(ReadSourceLocation());
- E->setRParenLoc(ReadSourceLocation());
+ E->setWrittenTypeInfo(readTypeSourceInfo());
+ E->setBuiltinLoc(readSourceLocation());
+ E->setRParenLoc(readSourceLocation());
E->setIsMicrosoftABI(Record.readInt());
}
void ASTStmtReader::VisitSourceLocExpr(SourceLocExpr *E) {
VisitExpr(E);
- E->ParentContext = ReadDeclAs<DeclContext>();
- E->BuiltinLoc = ReadSourceLocation();
- E->RParenLoc = ReadSourceLocation();
+ E->ParentContext = readDeclAs<DeclContext>();
+ E->BuiltinLoc = readSourceLocation();
+ E->RParenLoc = readSourceLocation();
E->SourceLocExprBits.Kind =
static_cast<SourceLocExpr::IdentKind>(Record.readInt());
}
void ASTStmtReader::VisitAddrLabelExpr(AddrLabelExpr *E) {
VisitExpr(E);
- E->setAmpAmpLoc(ReadSourceLocation());
- E->setLabelLoc(ReadSourceLocation());
- E->setLabel(ReadDeclAs<LabelDecl>());
+ E->setAmpAmpLoc(readSourceLocation());
+ E->setLabelLoc(readSourceLocation());
+ E->setLabel(readDeclAs<LabelDecl>());
}
void ASTStmtReader::VisitStmtExpr(StmtExpr *E) {
VisitExpr(E);
- E->setLParenLoc(ReadSourceLocation());
- E->setRParenLoc(ReadSourceLocation());
+ E->setLParenLoc(readSourceLocation());
+ E->setRParenLoc(readSourceLocation());
E->setSubStmt(cast_or_null<CompoundStmt>(Record.readSubStmt()));
}
@@ -1073,14 +1080,14 @@ void ASTStmtReader::VisitChooseExpr(ChooseExpr *E) {
E->setCond(Record.readSubExpr());
E->setLHS(Record.readSubExpr());
E->setRHS(Record.readSubExpr());
- E->setBuiltinLoc(ReadSourceLocation());
- E->setRParenLoc(ReadSourceLocation());
+ E->setBuiltinLoc(readSourceLocation());
+ E->setRParenLoc(readSourceLocation());
E->setIsConditionTrue(Record.readInt());
}
void ASTStmtReader::VisitGNUNullExpr(GNUNullExpr *E) {
VisitExpr(E);
- E->setTokenLocation(ReadSourceLocation());
+ E->setTokenLocation(readSourceLocation());
}
void ASTStmtReader::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
@@ -1090,21 +1097,21 @@ void ASTStmtReader::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
while (NumExprs--)
Exprs.push_back(Record.readSubExpr());
E->setExprs(Record.getContext(), Exprs);
- E->setBuiltinLoc(ReadSourceLocation());
- E->setRParenLoc(ReadSourceLocation());
+ E->setBuiltinLoc(readSourceLocation());
+ E->setRParenLoc(readSourceLocation());
}
void ASTStmtReader::VisitConvertVectorExpr(ConvertVectorExpr *E) {
VisitExpr(E);
- E->BuiltinLoc = ReadSourceLocation();
- E->RParenLoc = ReadSourceLocation();
- E->TInfo = GetTypeSourceInfo();
+ E->BuiltinLoc = readSourceLocation();
+ E->RParenLoc = readSourceLocation();
+ E->TInfo = readTypeSourceInfo();
E->SrcExpr = Record.readSubExpr();
}
void ASTStmtReader::VisitBlockExpr(BlockExpr *E) {
VisitExpr(E);
- E->setBlockDecl(ReadDeclAs<BlockDecl>());
+ E->setBlockDecl(readDeclAs<BlockDecl>());
}
void ASTStmtReader::VisitGenericSelectionExpr(GenericSelectionExpr *E) {
@@ -1113,9 +1120,9 @@ void ASTStmtReader::VisitGenericSelectionExpr(GenericSelectionExpr *E) {
unsigned NumAssocs = Record.readInt();
assert(NumAssocs == E->getNumAssocs() && "Wrong NumAssocs!");
E->ResultIndex = Record.readInt();
- E->GenericSelectionExprBits.GenericLoc = ReadSourceLocation();
- E->DefaultLoc = ReadSourceLocation();
- E->RParenLoc = ReadSourceLocation();
+ E->GenericSelectionExprBits.GenericLoc = readSourceLocation();
+ E->DefaultLoc = readSourceLocation();
+ E->RParenLoc = readSourceLocation();
Stmt **Stmts = E->getTrailingObjects<Stmt *>();
// Add 1 to account for the controlling expression which is the first
@@ -1126,7 +1133,7 @@ void ASTStmtReader::VisitGenericSelectionExpr(GenericSelectionExpr *E) {
TypeSourceInfo **TSIs = E->getTrailingObjects<TypeSourceInfo *>();
for (unsigned I = 0, N = NumAssocs; I < N; ++I)
- TSIs[I] = GetTypeSourceInfo();
+ TSIs[I] = readTypeSourceInfo();
}
void ASTStmtReader::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
@@ -1151,8 +1158,8 @@ void ASTStmtReader::VisitAtomicExpr(AtomicExpr *E) {
E->NumSubExprs = AtomicExpr::getNumSubExprs(E->Op);
for (unsigned I = 0; I != E->NumSubExprs; ++I)
E->SubExprs[I] = Record.readSubExpr();
- E->BuiltinLoc = ReadSourceLocation();
- E->RParenLoc = ReadSourceLocation();
+ E->BuiltinLoc = readSourceLocation();
+ E->RParenLoc = readSourceLocation();
}
//===----------------------------------------------------------------------===//
@@ -1161,15 +1168,15 @@ void ASTStmtReader::VisitAtomicExpr(AtomicExpr *E) {
void ASTStmtReader::VisitObjCStringLiteral(ObjCStringLiteral *E) {
VisitExpr(E);
E->setString(cast<StringLiteral>(Record.readSubStmt()));
- E->setAtLoc(ReadSourceLocation());
+ E->setAtLoc(readSourceLocation());
}
void ASTStmtReader::VisitObjCBoxedExpr(ObjCBoxedExpr *E) {
VisitExpr(E);
// could be one of several IntegerLiteral, FloatLiteral, etc.
E->SubExpr = Record.readSubStmt();
- E->BoxingMethod = ReadDeclAs<ObjCMethodDecl>();
- E->Range = ReadSourceRange();
+ E->BoxingMethod = readDeclAs<ObjCMethodDecl>();
+ E->Range = readSourceRange();
}
void ASTStmtReader::VisitObjCArrayLiteral(ObjCArrayLiteral *E) {
@@ -1179,8 +1186,8 @@ void ASTStmtReader::VisitObjCArrayLiteral(ObjCArrayLiteral *E) {
Expr **Elements = E->getElements();
for (unsigned I = 0, N = NumElements; I != N; ++I)
Elements[I] = Record.readSubExpr();
- E->ArrayWithObjectsMethod = ReadDeclAs<ObjCMethodDecl>();
- E->Range = ReadSourceRange();
+ E->ArrayWithObjectsMethod = readDeclAs<ObjCMethodDecl>();
+ E->Range = readSourceRange();
}
void ASTStmtReader::VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {
@@ -1197,41 +1204,41 @@ void ASTStmtReader::VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {
KeyValues[I].Key = Record.readSubExpr();
KeyValues[I].Value = Record.readSubExpr();
if (HasPackExpansions) {
- Expansions[I].EllipsisLoc = ReadSourceLocation();
+ Expansions[I].EllipsisLoc = readSourceLocation();
Expansions[I].NumExpansionsPlusOne = Record.readInt();
}
}
- E->DictWithObjectsMethod = ReadDeclAs<ObjCMethodDecl>();
- E->Range = ReadSourceRange();
+ E->DictWithObjectsMethod = readDeclAs<ObjCMethodDecl>();
+ E->Range = readSourceRange();
}
void ASTStmtReader::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
VisitExpr(E);
- E->setEncodedTypeSourceInfo(GetTypeSourceInfo());
- E->setAtLoc(ReadSourceLocation());
- E->setRParenLoc(ReadSourceLocation());
+ E->setEncodedTypeSourceInfo(readTypeSourceInfo());
+ E->setAtLoc(readSourceLocation());
+ E->setRParenLoc(readSourceLocation());
}
void ASTStmtReader::VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
VisitExpr(E);
E->setSelector(Record.readSelector());
- E->setAtLoc(ReadSourceLocation());
- E->setRParenLoc(ReadSourceLocation());
+ E->setAtLoc(readSourceLocation());
+ E->setRParenLoc(readSourceLocation());
}
void ASTStmtReader::VisitObjCProtocolExpr(ObjCProtocolExpr *E) {
VisitExpr(E);
- E->setProtocol(ReadDeclAs<ObjCProtocolDecl>());
- E->setAtLoc(ReadSourceLocation());
- E->ProtoLoc = ReadSourceLocation();
- E->setRParenLoc(ReadSourceLocation());
+ E->setProtocol(readDeclAs<ObjCProtocolDecl>());
+ E->setAtLoc(readSourceLocation());
+ E->ProtoLoc = readSourceLocation();
+ E->setRParenLoc(readSourceLocation());
}
void ASTStmtReader::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
VisitExpr(E);
- E->setDecl(ReadDeclAs<ObjCIvarDecl>());
- E->setLocation(ReadSourceLocation());
- E->setOpLoc(ReadSourceLocation());
+ E->setDecl(readDeclAs<ObjCIvarDecl>());
+ E->setLocation(readSourceLocation());
+ E->setOpLoc(readSourceLocation());
E->setBase(Record.readSubExpr());
E->setIsArrow(Record.readInt());
E->setIsFreeIvar(Record.readInt());
@@ -1242,14 +1249,14 @@ void ASTStmtReader::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
unsigned MethodRefFlags = Record.readInt();
bool Implicit = Record.readInt() != 0;
if (Implicit) {
- auto *Getter = ReadDeclAs<ObjCMethodDecl>();
- auto *Setter = ReadDeclAs<ObjCMethodDecl>();
+ auto *Getter = readDeclAs<ObjCMethodDecl>();
+ auto *Setter = readDeclAs<ObjCMethodDecl>();
E->setImplicitProperty(Getter, Setter, MethodRefFlags);
} else {
- E->setExplicitProperty(ReadDeclAs<ObjCPropertyDecl>(), MethodRefFlags);
+ E->setExplicitProperty(readDeclAs<ObjCPropertyDecl>(), MethodRefFlags);
}
- E->setLocation(ReadSourceLocation());
- E->setReceiverLocation(ReadSourceLocation());
+ E->setLocation(readSourceLocation());
+ E->setReceiverLocation(readSourceLocation());
switch (Record.readInt()) {
case 0:
E->setBase(Record.readSubExpr());
@@ -1258,18 +1265,18 @@ void ASTStmtReader::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
E->setSuperReceiver(Record.readType());
break;
case 2:
- E->setClassReceiver(ReadDeclAs<ObjCInterfaceDecl>());
+ E->setClassReceiver(readDeclAs<ObjCInterfaceDecl>());
break;
}
}
void ASTStmtReader::VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *E) {
VisitExpr(E);
- E->setRBracket(ReadSourceLocation());
+ E->setRBracket(readSourceLocation());
E->setBaseExpr(Record.readSubExpr());
E->setKeyExpr(Record.readSubExpr());
- E->GetAtIndexMethodDecl = ReadDeclAs<ObjCMethodDecl>();
- E->SetAtIndexMethodDecl = ReadDeclAs<ObjCMethodDecl>();
+ E->GetAtIndexMethodDecl = readDeclAs<ObjCMethodDecl>();
+ E->SetAtIndexMethodDecl = readDeclAs<ObjCMethodDecl>();
}
void ASTStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) {
@@ -1287,13 +1294,13 @@ void ASTStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) {
break;
case ObjCMessageExpr::Class:
- E->setClassReceiver(GetTypeSourceInfo());
+ E->setClassReceiver(readTypeSourceInfo());
break;
case ObjCMessageExpr::SuperClass:
case ObjCMessageExpr::SuperInstance: {
QualType T = Record.readType();
- SourceLocation SuperLoc = ReadSourceLocation();
+ SourceLocation SuperLoc = readSourceLocation();
E->setSuper(SuperLoc, T, Kind == ObjCMessageExpr::SuperInstance);
break;
}
@@ -1302,19 +1309,19 @@ void ASTStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) {
assert(Kind == E->getReceiverKind());
if (Record.readInt())
- E->setMethodDecl(ReadDeclAs<ObjCMethodDecl>());
+ E->setMethodDecl(readDeclAs<ObjCMethodDecl>());
else
E->setSelector(Record.readSelector());
- E->LBracLoc = ReadSourceLocation();
- E->RBracLoc = ReadSourceLocation();
+ E->LBracLoc = readSourceLocation();
+ E->RBracLoc = readSourceLocation();
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
E->setArg(I, Record.readSubExpr());
SourceLocation *Locs = E->getStoredSelLocs();
for (unsigned I = 0; I != NumStoredSelLocs; ++I)
- Locs[I] = ReadSourceLocation();
+ Locs[I] = readSourceLocation();
}
void ASTStmtReader::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
@@ -1322,28 +1329,28 @@ void ASTStmtReader::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
S->setElement(Record.readSubStmt());
S->setCollection(Record.readSubExpr());
S->setBody(Record.readSubStmt());
- S->setForLoc(ReadSourceLocation());
- S->setRParenLoc(ReadSourceLocation());
+ S->setForLoc(readSourceLocation());
+ S->setRParenLoc(readSourceLocation());
}
void ASTStmtReader::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) {
VisitStmt(S);
S->setCatchBody(Record.readSubStmt());
- S->setCatchParamDecl(ReadDeclAs<VarDecl>());
- S->setAtCatchLoc(ReadSourceLocation());
- S->setRParenLoc(ReadSourceLocation());
+ S->setCatchParamDecl(readDeclAs<VarDecl>());
+ S->setAtCatchLoc(readSourceLocation());
+ S->setRParenLoc(readSourceLocation());
}
void ASTStmtReader::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
VisitStmt(S);
S->setFinallyBody(Record.readSubStmt());
- S->setAtFinallyLoc(ReadSourceLocation());
+ S->setAtFinallyLoc(readSourceLocation());
}
void ASTStmtReader::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
VisitStmt(S); // FIXME: no test coverage.
S->setSubStmt(Record.readSubStmt());
- S->setAtLoc(ReadSourceLocation());
+ S->setAtLoc(readSourceLocation());
}
void ASTStmtReader::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
@@ -1357,26 +1364,26 @@ void ASTStmtReader::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
if (HasFinally)
S->setFinallyStmt(Record.readSubStmt());
- S->setAtTryLoc(ReadSourceLocation());
+ S->setAtTryLoc(readSourceLocation());
}
void ASTStmtReader::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
VisitStmt(S); // FIXME: no test coverage.
S->setSynchExpr(Record.readSubStmt());
S->setSynchBody(Record.readSubStmt());
- S->setAtSynchronizedLoc(ReadSourceLocation());
+ S->setAtSynchronizedLoc(readSourceLocation());
}
void ASTStmtReader::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
VisitStmt(S); // FIXME: no test coverage.
S->setThrowExpr(Record.readSubStmt());
- S->setThrowLoc(ReadSourceLocation());
+ S->setThrowLoc(readSourceLocation());
}
void ASTStmtReader::VisitObjCBoolLiteralExpr(ObjCBoolLiteralExpr *E) {
VisitExpr(E);
E->setValue(Record.readInt());
- E->setLocation(ReadSourceLocation());
+ E->setLocation(readSourceLocation());
}
void ASTStmtReader::VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) {
@@ -1393,8 +1400,8 @@ void ASTStmtReader::VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E)
void ASTStmtReader::VisitCXXCatchStmt(CXXCatchStmt *S) {
VisitStmt(S);
- S->CatchLoc = ReadSourceLocation();
- S->ExceptionDecl = ReadDeclAs<VarDecl>();
+ S->CatchLoc = readSourceLocation();
+ S->ExceptionDecl = readDeclAs<VarDecl>();
S->HandlerBlock = Record.readSubStmt();
}
@@ -1402,7 +1409,7 @@ void ASTStmtReader::VisitCXXTryStmt(CXXTryStmt *S) {
VisitStmt(S);
assert(Record.peekInt() == S->getNumHandlers() && "NumStmtFields is wrong ?");
Record.skipInts(1);
- S->TryLoc = ReadSourceLocation();
+ S->TryLoc = readSourceLocation();
S->getStmts()[0] = Record.readSubStmt();
for (unsigned i = 0, e = S->getNumHandlers(); i != e; ++i)
S->getStmts()[i + 1] = Record.readSubStmt();
@@ -1410,10 +1417,10 @@ void ASTStmtReader::VisitCXXTryStmt(CXXTryStmt *S) {
void ASTStmtReader::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
VisitStmt(S);
- S->ForLoc = ReadSourceLocation();
- S->CoawaitLoc = ReadSourceLocation();
- S->ColonLoc = ReadSourceLocation();
- S->RParenLoc = ReadSourceLocation();
+ S->ForLoc = readSourceLocation();
+ S->CoawaitLoc = readSourceLocation();
+ S->ColonLoc = readSourceLocation();
+ S->RParenLoc = readSourceLocation();
S->setInit(Record.readSubStmt());
S->setRangeStmt(Record.readSubStmt());
S->setBeginStmt(Record.readSubStmt());
@@ -1426,10 +1433,10 @@ void ASTStmtReader::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
void ASTStmtReader::VisitMSDependentExistsStmt(MSDependentExistsStmt *S) {
VisitStmt(S);
- S->KeywordLoc = ReadSourceLocation();
+ S->KeywordLoc = readSourceLocation();
S->IsIfExists = Record.readInt();
S->QualifierLoc = Record.readNestedNameSpecifierLoc();
- ReadDeclarationNameInfo(S->NameInfo);
+ S->NameInfo = Record.readDeclarationNameInfo();
S->SubStmt = Record.readSubStmt();
}
@@ -1459,9 +1466,9 @@ void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) {
E->CXXConstructExprBits.StdInitListInitialization = Record.readInt();
E->CXXConstructExprBits.ZeroInitialization = Record.readInt();
E->CXXConstructExprBits.ConstructionKind = Record.readInt();
- E->CXXConstructExprBits.Loc = ReadSourceLocation();
- E->Constructor = ReadDeclAs<CXXConstructorDecl>();
- E->ParenOrBraceRange = ReadSourceRange();
+ E->CXXConstructExprBits.Loc = readSourceLocation();
+ E->Constructor = readDeclAs<CXXConstructorDecl>();
+ E->ParenOrBraceRange = readSourceRange();
for (unsigned I = 0; I != NumArgs; ++I)
E->setArg(I, Record.readSubExpr());
@@ -1469,27 +1476,27 @@ void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) {
void ASTStmtReader::VisitCXXInheritedCtorInitExpr(CXXInheritedCtorInitExpr *E) {
VisitExpr(E);
- E->Constructor = ReadDeclAs<CXXConstructorDecl>();
- E->Loc = ReadSourceLocation();
+ E->Constructor = readDeclAs<CXXConstructorDecl>();
+ E->Loc = readSourceLocation();
E->ConstructsVirtualBase = Record.readInt();
E->InheritedFromVirtualBase = Record.readInt();
}
void ASTStmtReader::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) {
VisitCXXConstructExpr(E);
- E->TSI = GetTypeSourceInfo();
+ E->TSI = readTypeSourceInfo();
}
void ASTStmtReader::VisitLambdaExpr(LambdaExpr *E) {
VisitExpr(E);
unsigned NumCaptures = Record.readInt();
assert(NumCaptures == E->NumCaptures);(void)NumCaptures;
- E->IntroducerRange = ReadSourceRange();
+ E->IntroducerRange = readSourceRange();
E->CaptureDefault = static_cast<LambdaCaptureDefault>(Record.readInt());
- E->CaptureDefaultLoc = ReadSourceLocation();
+ E->CaptureDefaultLoc = readSourceLocation();
E->ExplicitParams = Record.readInt();
E->ExplicitResultType = Record.readInt();
- E->ClosingBrace = ReadSourceLocation();
+ E->ClosingBrace = readSourceLocation();
// Read capture initializers.
for (LambdaExpr::capture_init_iterator C = E->capture_init_begin(),
@@ -1506,10 +1513,10 @@ ASTStmtReader::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
void ASTStmtReader::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
VisitExplicitCastExpr(E);
- SourceRange R = ReadSourceRange();
+ SourceRange R = readSourceRange();
E->Loc = R.getBegin();
E->RParenLoc = R.getEnd();
- R = ReadSourceRange();
+ R = readSourceRange();
E->AngleBrackets = R;
}
@@ -1531,38 +1538,38 @@ void ASTStmtReader::VisitCXXConstCastExpr(CXXConstCastExpr *E) {
void ASTStmtReader::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) {
VisitExplicitCastExpr(E);
- E->setLParenLoc(ReadSourceLocation());
- E->setRParenLoc(ReadSourceLocation());
+ E->setLParenLoc(readSourceLocation());
+ E->setRParenLoc(readSourceLocation());
}
void ASTStmtReader::VisitBuiltinBitCastExpr(BuiltinBitCastExpr *E) {
VisitExplicitCastExpr(E);
- E->KWLoc = ReadSourceLocation();
- E->RParenLoc = ReadSourceLocation();
+ E->KWLoc = readSourceLocation();
+ E->RParenLoc = readSourceLocation();
}
void ASTStmtReader::VisitUserDefinedLiteral(UserDefinedLiteral *E) {
VisitCallExpr(E);
- E->UDSuffixLoc = ReadSourceLocation();
+ E->UDSuffixLoc = readSourceLocation();
}
void ASTStmtReader::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) {
VisitExpr(E);
E->setValue(Record.readInt());
- E->setLocation(ReadSourceLocation());
+ E->setLocation(readSourceLocation());
}
void ASTStmtReader::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) {
VisitExpr(E);
- E->setLocation(ReadSourceLocation());
+ E->setLocation(readSourceLocation());
}
void ASTStmtReader::VisitCXXTypeidExpr(CXXTypeidExpr *E) {
VisitExpr(E);
- E->setSourceRange(ReadSourceRange());
+ E->setSourceRange(readSourceRange());
if (E->isTypeOperand()) { // typeid(int)
E->setTypeOperandSourceInfo(
- GetTypeSourceInfo());
+ readTypeSourceInfo());
return;
}
@@ -1572,29 +1579,29 @@ void ASTStmtReader::VisitCXXTypeidExpr(CXXTypeidExpr *E) {
void ASTStmtReader::VisitCXXThisExpr(CXXThisExpr *E) {
VisitExpr(E);
- E->setLocation(ReadSourceLocation());
+ E->setLocation(readSourceLocation());
E->setImplicit(Record.readInt());
}
void ASTStmtReader::VisitCXXThrowExpr(CXXThrowExpr *E) {
VisitExpr(E);
- E->CXXThrowExprBits.ThrowLoc = ReadSourceLocation();
+ E->CXXThrowExprBits.ThrowLoc = readSourceLocation();
E->Operand = Record.readSubExpr();
E->CXXThrowExprBits.IsThrownVariableInScope = Record.readInt();
}
void ASTStmtReader::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
VisitExpr(E);
- E->Param = ReadDeclAs<ParmVarDecl>();
- E->UsedContext = ReadDeclAs<DeclContext>();
- E->CXXDefaultArgExprBits.Loc = ReadSourceLocation();
+ E->Param = readDeclAs<ParmVarDecl>();
+ E->UsedContext = readDeclAs<DeclContext>();
+ E->CXXDefaultArgExprBits.Loc = readSourceLocation();
}
void ASTStmtReader::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
VisitExpr(E);
- E->Field = ReadDeclAs<FieldDecl>();
- E->UsedContext = ReadDeclAs<DeclContext>();
- E->CXXDefaultInitExprBits.Loc = ReadSourceLocation();
+ E->Field = readDeclAs<FieldDecl>();
+ E->UsedContext = readDeclAs<DeclContext>();
+ E->CXXDefaultInitExprBits.Loc = readSourceLocation();
}
void ASTStmtReader::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
@@ -1605,8 +1612,8 @@ void ASTStmtReader::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
void ASTStmtReader::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
VisitExpr(E);
- E->TypeInfo = GetTypeSourceInfo();
- E->CXXScalarValueInitExprBits.RParenLoc = ReadSourceLocation();
+ E->TypeInfo = readTypeSourceInfo();
+ E->CXXScalarValueInitExprBits.RParenLoc = readSourceLocation();
}
void ASTStmtReader::VisitCXXNewExpr(CXXNewExpr *E) {
@@ -1631,13 +1638,13 @@ void ASTStmtReader::VisitCXXNewExpr(CXXNewExpr *E) {
(void)HasInit;
(void)NumPlacementArgs;
- E->setOperatorNew(ReadDeclAs<FunctionDecl>());
- E->setOperatorDelete(ReadDeclAs<FunctionDecl>());
- E->AllocatedTypeInfo = GetTypeSourceInfo();
+ E->setOperatorNew(readDeclAs<FunctionDecl>());
+ E->setOperatorDelete(readDeclAs<FunctionDecl>());
+ E->AllocatedTypeInfo = readTypeSourceInfo();
if (IsParenTypeId)
- E->getTrailingObjects<SourceRange>()[0] = ReadSourceRange();
- E->Range = ReadSourceRange();
- E->DirectInitRange = ReadSourceRange();
+ E->getTrailingObjects<SourceRange>()[0] = readSourceRange();
+ E->Range = readSourceRange();
+ E->DirectInitRange = readSourceRange();
// Install all the subexpressions.
for (CXXNewExpr::raw_arg_iterator I = E->raw_arg_begin(),
@@ -1652,9 +1659,9 @@ void ASTStmtReader::VisitCXXDeleteExpr(CXXDeleteExpr *E) {
E->CXXDeleteExprBits.ArrayForm = Record.readInt();
E->CXXDeleteExprBits.ArrayFormAsWritten = Record.readInt();
E->CXXDeleteExprBits.UsualArrayDeleteWantsSize = Record.readInt();
- E->OperatorDelete = ReadDeclAs<FunctionDecl>();
+ E->OperatorDelete = readDeclAs<FunctionDecl>();
E->Argument = Record.readSubExpr();
- E->CXXDeleteExprBits.Loc = ReadSourceLocation();
+ E->CXXDeleteExprBits.Loc = readSourceLocation();
}
void ASTStmtReader::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
@@ -1662,17 +1669,17 @@ void ASTStmtReader::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
E->Base = Record.readSubExpr();
E->IsArrow = Record.readInt();
- E->OperatorLoc = ReadSourceLocation();
+ E->OperatorLoc = readSourceLocation();
E->QualifierLoc = Record.readNestedNameSpecifierLoc();
- E->ScopeType = GetTypeSourceInfo();
- E->ColonColonLoc = ReadSourceLocation();
- E->TildeLoc = ReadSourceLocation();
+ E->ScopeType = readTypeSourceInfo();
+ E->ColonColonLoc = readSourceLocation();
+ E->TildeLoc = readSourceLocation();
- IdentifierInfo *II = Record.getIdentifierInfo();
+ IdentifierInfo *II = Record.readIdentifier();
if (II)
- E->setDestroyedType(II, ReadSourceLocation());
+ E->setDestroyedType(II, readSourceLocation());
else
- E->setDestroyedType(GetTypeSourceInfo());
+ E->setDestroyedType(readTypeSourceInfo());
}
void ASTStmtReader::VisitExprWithCleanups(ExprWithCleanups *E) {
@@ -1682,7 +1689,7 @@ void ASTStmtReader::VisitExprWithCleanups(ExprWithCleanups *E) {
assert(NumObjects == E->getNumObjects());
for (unsigned i = 0; i != NumObjects; ++i)
E->getTrailingObjects<BlockDecl *>()[i] =
- ReadDeclAs<BlockDecl>();
+ readDeclAs<BlockDecl>();
E->ExprWithCleanupsBits.CleanupsHaveSideEffects = Record.readInt();
E->SubExpr = Record.readSubExpr();
@@ -1711,15 +1718,15 @@ void ASTStmtReader::VisitCXXDependentScopeMemberExpr(
"Wrong NumTemplateArgs!");
E->CXXDependentScopeMemberExprBits.IsArrow = Record.readInt();
- E->CXXDependentScopeMemberExprBits.OperatorLoc = ReadSourceLocation();
+ E->CXXDependentScopeMemberExprBits.OperatorLoc = readSourceLocation();
E->BaseType = Record.readType();
E->QualifierLoc = Record.readNestedNameSpecifierLoc();
E->Base = Record.readSubExpr();
if (HasFirstQualifierFoundInScope)
- *E->getTrailingObjects<NamedDecl *>() = ReadDeclAs<NamedDecl>();
+ *E->getTrailingObjects<NamedDecl *>() = readDeclAs<NamedDecl>();
- ReadDeclarationNameInfo(E->MemberNameInfo);
+ E->MemberNameInfo = Record.readDeclarationNameInfo();
}
void
@@ -1733,7 +1740,7 @@ ASTStmtReader::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
/*NumTemplateArgs=*/Record.readInt());
E->QualifierLoc = Record.readNestedNameSpecifierLoc();
- ReadDeclarationNameInfo(E->NameInfo);
+ E->NameInfo = Record.readDeclarationNameInfo();
}
void
@@ -1744,9 +1751,9 @@ ASTStmtReader::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E) {
Record.skipInts(1);
for (unsigned I = 0, N = E->arg_size(); I != N; ++I)
E->setArg(I, Record.readSubExpr());
- E->TSI = GetTypeSourceInfo();
- E->setLParenLoc(ReadSourceLocation());
- E->setRParenLoc(ReadSourceLocation());
+ E->TSI = readTypeSourceInfo();
+ E->setLParenLoc(readSourceLocation());
+ E->setRParenLoc(readSourceLocation());
}
void ASTStmtReader::VisitOverloadExpr(OverloadExpr *E) {
@@ -1769,7 +1776,7 @@ void ASTStmtReader::VisitOverloadExpr(OverloadExpr *E) {
UnresolvedSet<8> Decls;
for (unsigned I = 0; I != NumResults; ++I) {
- auto *D = ReadDeclAs<NamedDecl>();
+ auto *D = readDeclAs<NamedDecl>();
auto AS = (AccessSpecifier)Record.readInt();
Decls.addDecl(D, AS);
}
@@ -1780,7 +1787,7 @@ void ASTStmtReader::VisitOverloadExpr(OverloadExpr *E) {
Results[I] = (Iter + I).getPair();
}
- ReadDeclarationNameInfo(E->NameInfo);
+ E->NameInfo = Record.readDeclarationNameInfo();
E->QualifierLoc = Record.readNestedNameSpecifierLoc();
}
@@ -1790,14 +1797,14 @@ void ASTStmtReader::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
E->UnresolvedMemberExprBits.HasUnresolvedUsing = Record.readInt();
E->Base = Record.readSubExpr();
E->BaseType = Record.readType();
- E->OperatorLoc = ReadSourceLocation();
+ E->OperatorLoc = readSourceLocation();
}
void ASTStmtReader::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
VisitOverloadExpr(E);
E->UnresolvedLookupExprBits.RequiresADL = Record.readInt();
E->UnresolvedLookupExprBits.Overloaded = Record.readInt();
- E->NamingClass = ReadDeclAs<CXXRecordDecl>();
+ E->NamingClass = readDeclAs<CXXRecordDecl>();
}
void ASTStmtReader::VisitTypeTraitExpr(TypeTraitExpr *E) {
@@ -1805,23 +1812,23 @@ void ASTStmtReader::VisitTypeTraitExpr(TypeTraitExpr *E) {
E->TypeTraitExprBits.NumArgs = Record.readInt();
E->TypeTraitExprBits.Kind = Record.readInt();
E->TypeTraitExprBits.Value = Record.readInt();
- SourceRange Range = ReadSourceRange();
+ SourceRange Range = readSourceRange();
E->Loc = Range.getBegin();
E->RParenLoc = Range.getEnd();
auto **Args = E->getTrailingObjects<TypeSourceInfo *>();
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
- Args[I] = GetTypeSourceInfo();
+ Args[I] = readTypeSourceInfo();
}
void ASTStmtReader::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
VisitExpr(E);
E->ATT = (ArrayTypeTrait)Record.readInt();
E->Value = (unsigned int)Record.readInt();
- SourceRange Range = ReadSourceRange();
+ SourceRange Range = readSourceRange();
E->Loc = Range.getBegin();
E->RParen = Range.getEnd();
- E->QueriedType = GetTypeSourceInfo();
+ E->QueriedType = readTypeSourceInfo();
E->Dimension = Record.readSubExpr();
}
@@ -1829,7 +1836,7 @@ void ASTStmtReader::VisitExpressionTraitExpr(ExpressionTraitExpr *E) {
VisitExpr(E);
E->ET = (ExpressionTrait)Record.readInt();
E->Value = (bool)Record.readInt();
- SourceRange Range = ReadSourceRange();
+ SourceRange Range = readSourceRange();
E->QueriedExpression = Record.readSubExpr();
E->Loc = Range.getBegin();
E->RParen = Range.getEnd();
@@ -1838,13 +1845,13 @@ void ASTStmtReader::VisitExpressionTraitExpr(ExpressionTraitExpr *E) {
void ASTStmtReader::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) {
VisitExpr(E);
E->CXXNoexceptExprBits.Value = Record.readInt();
- E->Range = ReadSourceRange();
+ E->Range = readSourceRange();
E->Operand = Record.readSubExpr();
}
void ASTStmtReader::VisitPackExpansionExpr(PackExpansionExpr *E) {
VisitExpr(E);
- E->EllipsisLoc = ReadSourceLocation();
+ E->EllipsisLoc = readSourceLocation();
E->NumExpansions = Record.readInt();
E->Pattern = Record.readSubExpr();
}
@@ -1852,9 +1859,9 @@ void ASTStmtReader::VisitPackExpansionExpr(PackExpansionExpr *E) {
void ASTStmtReader::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
VisitExpr(E);
unsigned NumPartialArgs = Record.readInt();
- E->OperatorLoc = ReadSourceLocation();
- E->PackLoc = ReadSourceLocation();
- E->RParenLoc = ReadSourceLocation();
+ E->OperatorLoc = readSourceLocation();
+ E->PackLoc = readSourceLocation();
+ E->RParenLoc = readSourceLocation();
E->Pack = Record.readDeclAs<NamedDecl>();
if (E->isPartiallySubstituted()) {
assert(E->Length == NumPartialArgs);
@@ -1870,47 +1877,48 @@ void ASTStmtReader::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
void ASTStmtReader::VisitSubstNonTypeTemplateParmExpr(
SubstNonTypeTemplateParmExpr *E) {
VisitExpr(E);
- E->Param = ReadDeclAs<NonTypeTemplateParmDecl>();
- E->SubstNonTypeTemplateParmExprBits.NameLoc = ReadSourceLocation();
+ E->Param = readDeclAs<NonTypeTemplateParmDecl>();
+ E->SubstNonTypeTemplateParmExprBits.NameLoc = readSourceLocation();
E->Replacement = Record.readSubExpr();
}
void ASTStmtReader::VisitSubstNonTypeTemplateParmPackExpr(
SubstNonTypeTemplateParmPackExpr *E) {
VisitExpr(E);
- E->Param = ReadDeclAs<NonTypeTemplateParmDecl>();
+ E->Param = readDeclAs<NonTypeTemplateParmDecl>();
TemplateArgument ArgPack = Record.readTemplateArgument();
if (ArgPack.getKind() != TemplateArgument::Pack)
return;
E->Arguments = ArgPack.pack_begin();
E->NumArguments = ArgPack.pack_size();
- E->NameLoc = ReadSourceLocation();
+ E->NameLoc = readSourceLocation();
}
void ASTStmtReader::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) {
VisitExpr(E);
E->NumParameters = Record.readInt();
- E->ParamPack = ReadDeclAs<ParmVarDecl>();
- E->NameLoc = ReadSourceLocation();
+ E->ParamPack = readDeclAs<ParmVarDecl>();
+ E->NameLoc = readSourceLocation();
auto **Parms = E->getTrailingObjects<VarDecl *>();
for (unsigned i = 0, n = E->NumParameters; i != n; ++i)
- Parms[i] = ReadDeclAs<VarDecl>();
+ Parms[i] = readDeclAs<VarDecl>();
}
void ASTStmtReader::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
VisitExpr(E);
- E->State = Record.readSubExpr();
- auto *VD = ReadDeclAs<ValueDecl>();
- unsigned ManglingNumber = Record.readInt();
- E->setExtendingDecl(VD, ManglingNumber);
+ bool HasMaterialzedDecl = Record.readInt();
+ if (HasMaterialzedDecl)
+ E->State = cast<LifetimeExtendedTemporaryDecl>(Record.readDecl());
+ else
+ E->State = Record.readSubExpr();
}
void ASTStmtReader::VisitCXXFoldExpr(CXXFoldExpr *E) {
VisitExpr(E);
- E->LParenLoc = ReadSourceLocation();
- E->EllipsisLoc = ReadSourceLocation();
- E->RParenLoc = ReadSourceLocation();
+ E->LParenLoc = readSourceLocation();
+ E->EllipsisLoc = readSourceLocation();
+ E->RParenLoc = readSourceLocation();
E->NumExpansions = Record.readInt();
E->SubExprs[0] = Record.readSubExpr();
E->SubExprs[1] = Record.readSubExpr();
@@ -1920,7 +1928,7 @@ void ASTStmtReader::VisitCXXFoldExpr(CXXFoldExpr *E) {
void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
VisitExpr(E);
E->SourceExpr = Record.readSubExpr();
- E->OpaqueValueExprBits.Loc = ReadSourceLocation();
+ E->OpaqueValueExprBits.Loc = readSourceLocation();
E->setIsUnique(Record.readInt());
}
@@ -1936,25 +1944,25 @@ void ASTStmtReader::VisitMSPropertyRefExpr(MSPropertyRefExpr *E) {
E->IsArrow = (Record.readInt() != 0);
E->BaseExpr = Record.readSubExpr();
E->QualifierLoc = Record.readNestedNameSpecifierLoc();
- E->MemberLoc = ReadSourceLocation();
- E->TheDecl = ReadDeclAs<MSPropertyDecl>();
+ E->MemberLoc = readSourceLocation();
+ E->TheDecl = readDeclAs<MSPropertyDecl>();
}
void ASTStmtReader::VisitMSPropertySubscriptExpr(MSPropertySubscriptExpr *E) {
VisitExpr(E);
E->setBase(Record.readSubExpr());
E->setIdx(Record.readSubExpr());
- E->setRBracketLoc(ReadSourceLocation());
+ E->setRBracketLoc(readSourceLocation());
}
void ASTStmtReader::VisitCXXUuidofExpr(CXXUuidofExpr *E) {
VisitExpr(E);
- E->setSourceRange(ReadSourceRange());
- std::string UuidStr = ReadString();
+ E->setSourceRange(readSourceRange());
+ std::string UuidStr = readString();
E->setUuidStr(StringRef(UuidStr).copy(Record.getContext()));
if (E->isTypeOperand()) { // __uuidof(ComType)
E->setTypeOperandSourceInfo(
- GetTypeSourceInfo());
+ readTypeSourceInfo());
return;
}
@@ -1964,26 +1972,26 @@ void ASTStmtReader::VisitCXXUuidofExpr(CXXUuidofExpr *E) {
void ASTStmtReader::VisitSEHLeaveStmt(SEHLeaveStmt *S) {
VisitStmt(S);
- S->setLeaveLoc(ReadSourceLocation());
+ S->setLeaveLoc(readSourceLocation());
}
void ASTStmtReader::VisitSEHExceptStmt(SEHExceptStmt *S) {
VisitStmt(S);
- S->Loc = ReadSourceLocation();
+ S->Loc = readSourceLocation();
S->Children[SEHExceptStmt::FILTER_EXPR] = Record.readSubStmt();
S->Children[SEHExceptStmt::BLOCK] = Record.readSubStmt();
}
void ASTStmtReader::VisitSEHFinallyStmt(SEHFinallyStmt *S) {
VisitStmt(S);
- S->Loc = ReadSourceLocation();
+ S->Loc = readSourceLocation();
S->Block = Record.readSubStmt();
}
void ASTStmtReader::VisitSEHTryStmt(SEHTryStmt *S) {
VisitStmt(S);
S->IsCXXTry = Record.readInt();
- S->TryLoc = ReadSourceLocation();
+ S->TryLoc = readSourceLocation();
S->Children[SEHTryStmt::TRY] = Record.readSubStmt();
S->Children[SEHTryStmt::HANDLER] = Record.readSubStmt();
}
@@ -2002,8 +2010,8 @@ void ASTStmtReader::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E) {
//===----------------------------------------------------------------------===//
void ASTStmtReader::VisitAsTypeExpr(AsTypeExpr *E) {
VisitExpr(E);
- E->BuiltinLoc = ReadSourceLocation();
- E->RParenLoc = ReadSourceLocation();
+ E->BuiltinLoc = readSourceLocation();
+ E->RParenLoc = readSourceLocation();
E->SrcExpr = Record.readSubExpr();
}
@@ -2012,12 +2020,11 @@ void ASTStmtReader::VisitAsTypeExpr(AsTypeExpr *E) {
//===----------------------------------------------------------------------===//
void ASTStmtReader::VisitOMPExecutableDirective(OMPExecutableDirective *E) {
- E->setLocStart(ReadSourceLocation());
- E->setLocEnd(ReadSourceLocation());
- OMPClauseReader ClauseReader(Record);
+ E->setLocStart(readSourceLocation());
+ E->setLocEnd(readSourceLocation());
SmallVector<OMPClause *, 5> Clauses;
for (unsigned i = 0; i < E->getNumClauses(); ++i)
- Clauses.push_back(ClauseReader.readClause());
+ Clauses.push_back(Record.readOMPClause());
E->setClauses(Clauses);
if (E->hasAssociatedStmt())
E->setAssociatedStmt(Record.readSubStmt());
@@ -2151,7 +2158,7 @@ void ASTStmtReader::VisitOMPCriticalDirective(OMPCriticalDirective *D) {
// The NumClauses field was read in ReadStmtFromStream.
Record.skipInts(1);
VisitOMPExecutableDirective(D);
- ReadDeclarationNameInfo(D->DirName);
+ D->DirName = Record.readDeclarationNameInfo();
}
void ASTStmtReader::VisitOMPParallelForDirective(OMPParallelForDirective *D) {
@@ -2164,6 +2171,14 @@ void ASTStmtReader::VisitOMPParallelForSimdDirective(
VisitOMPLoopDirective(D);
}
+void ASTStmtReader::VisitOMPParallelMasterDirective(
+ OMPParallelMasterDirective *D) {
+ VisitStmt(D);
+ // The NumClauses field was read in ReadStmtFromStream.
+ Record.skipInts(1);
+ VisitOMPExecutableDirective(D);
+}
+
void ASTStmtReader::VisitOMPParallelSectionsDirective(
OMPParallelSectionsDirective *D) {
VisitStmt(D);
@@ -2316,6 +2331,11 @@ void ASTStmtReader::VisitOMPParallelMasterTaskLoopDirective(
VisitOMPLoopDirective(D);
}
+void ASTStmtReader::VisitOMPParallelMasterTaskLoopSimdDirective(
+ OMPParallelMasterTaskLoopSimdDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
void ASTStmtReader::VisitOMPDistributeDirective(OMPDistributeDirective *D) {
VisitOMPLoopDirective(D);
}
@@ -2997,6 +3017,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
}
+ case STMT_OMP_PARALLEL_MASTER_DIRECTIVE:
+ S = OMPParallelMasterDirective::CreateEmpty(
+ Context, Record[ASTStmtReader::NumStmtFields], Empty);
+ break;
+
case STMT_OMP_PARALLEL_SECTIONS_DIRECTIVE:
S = OMPParallelSectionsDirective::CreateEmpty(
Context, Record[ASTStmtReader::NumStmtFields], Empty);
@@ -3131,6 +3156,14 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
}
+ case STMT_OMP_PARALLEL_MASTER_TASKLOOP_SIMD_DIRECTIVE: {
+ unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
+ unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1];
+ S = OMPParallelMasterTaskLoopSimdDirective::CreateEmpty(
+ Context, NumClauses, CollapsedNum, Empty);
+ break;
+ }
+
case STMT_OMP_DISTRIBUTE_DIRECTIVE: {
unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1];
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 28affedbbb30..6eba48a1abe9 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -10,10 +10,12 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Serialization/ASTWriter.h"
+#include "clang/AST/OpenMPClause.h"
+#include "clang/Serialization/ASTRecordWriter.h"
#include "ASTCommon.h"
#include "ASTReaderInternals.h"
#include "MultiOnDiskHashTable.h"
+#include "clang/AST/AbstractTypeWriter.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTUnresolvedSet.h"
#include "clang/AST/Attr.h"
@@ -65,7 +67,7 @@
#include "clang/Sema/Weak.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/InMemoryModuleCache.h"
-#include "clang/Serialization/Module.h"
+#include "clang/Serialization/ModuleFile.h"
#include "clang/Serialization/ModuleFileExtension.h"
#include "clang/Serialization/SerializationDiagnostic.h"
#include "llvm/ADT/APFloat.h"
@@ -132,457 +134,43 @@ static StringRef bytes(const SmallVectorImpl<T> &v) {
// Type serialization
//===----------------------------------------------------------------------===//
-namespace clang {
-
- class ASTTypeWriter {
- ASTWriter &Writer;
- ASTRecordWriter Record;
-
- /// Type code that corresponds to the record generated.
- TypeCode Code = static_cast<TypeCode>(0);
-
- /// Abbreviation to use for the record, if any.
- unsigned AbbrevToUse = 0;
-
- public:
- ASTTypeWriter(ASTWriter &Writer, ASTWriter::RecordDataImpl &Record)
- : Writer(Writer), Record(Writer, Record) {}
-
- uint64_t Emit() {
- return Record.Emit(Code, AbbrevToUse);
- }
-
- void Visit(QualType T) {
- if (T.hasLocalNonFastQualifiers()) {
- Qualifiers Qs = T.getLocalQualifiers();
- Record.AddTypeRef(T.getLocalUnqualifiedType());
- Record.push_back(Qs.getAsOpaqueValue());
- Code = TYPE_EXT_QUAL;
- AbbrevToUse = Writer.TypeExtQualAbbrev;
- } else {
- switch (T->getTypeClass()) {
- // For all of the concrete, non-dependent types, call the
- // appropriate visitor function.
-#define TYPE(Class, Base) \
- case Type::Class: Visit##Class##Type(cast<Class##Type>(T)); break;
-#define ABSTRACT_TYPE(Class, Base)
-#include "clang/AST/TypeNodes.inc"
- }
- }
- }
-
- void VisitArrayType(const ArrayType *T);
- void VisitFunctionType(const FunctionType *T);
- void VisitTagType(const TagType *T);
-
-#define TYPE(Class, Base) void Visit##Class##Type(const Class##Type *T);
-#define ABSTRACT_TYPE(Class, Base)
-#include "clang/AST/TypeNodes.inc"
- };
-
-} // namespace clang
-
-void ASTTypeWriter::VisitBuiltinType(const BuiltinType *T) {
- llvm_unreachable("Built-in types are never serialized");
-}
-
-void ASTTypeWriter::VisitComplexType(const ComplexType *T) {
- Record.AddTypeRef(T->getElementType());
- Code = TYPE_COMPLEX;
-}
-
-void ASTTypeWriter::VisitPointerType(const PointerType *T) {
- Record.AddTypeRef(T->getPointeeType());
- Code = TYPE_POINTER;
-}
-
-void ASTTypeWriter::VisitDecayedType(const DecayedType *T) {
- Record.AddTypeRef(T->getOriginalType());
- Code = TYPE_DECAYED;
-}
-
-void ASTTypeWriter::VisitAdjustedType(const AdjustedType *T) {
- Record.AddTypeRef(T->getOriginalType());
- Record.AddTypeRef(T->getAdjustedType());
- Code = TYPE_ADJUSTED;
-}
-
-void ASTTypeWriter::VisitBlockPointerType(const BlockPointerType *T) {
- Record.AddTypeRef(T->getPointeeType());
- Code = TYPE_BLOCK_POINTER;
-}
-
-void ASTTypeWriter::VisitLValueReferenceType(const LValueReferenceType *T) {
- Record.AddTypeRef(T->getPointeeTypeAsWritten());
- Record.push_back(T->isSpelledAsLValue());
- Code = TYPE_LVALUE_REFERENCE;
-}
-
-void ASTTypeWriter::VisitRValueReferenceType(const RValueReferenceType *T) {
- Record.AddTypeRef(T->getPointeeTypeAsWritten());
- Code = TYPE_RVALUE_REFERENCE;
-}
-
-void ASTTypeWriter::VisitMemberPointerType(const MemberPointerType *T) {
- Record.AddTypeRef(T->getPointeeType());
- Record.AddTypeRef(QualType(T->getClass(), 0));
- Code = TYPE_MEMBER_POINTER;
-}
-
-void ASTTypeWriter::VisitArrayType(const ArrayType *T) {
- Record.AddTypeRef(T->getElementType());
- Record.push_back(T->getSizeModifier()); // FIXME: stable values
- Record.push_back(T->getIndexTypeCVRQualifiers()); // FIXME: stable values
-}
-
-void ASTTypeWriter::VisitConstantArrayType(const ConstantArrayType *T) {
- VisitArrayType(T);
- Record.AddAPInt(T->getSize());
- Record.AddStmt(const_cast<Expr*>(T->getSizeExpr()));
- Code = TYPE_CONSTANT_ARRAY;
-}
-
-void ASTTypeWriter::VisitIncompleteArrayType(const IncompleteArrayType *T) {
- VisitArrayType(T);
- Code = TYPE_INCOMPLETE_ARRAY;
-}
-
-void ASTTypeWriter::VisitVariableArrayType(const VariableArrayType *T) {
- VisitArrayType(T);
- Record.AddSourceLocation(T->getLBracketLoc());
- Record.AddSourceLocation(T->getRBracketLoc());
- Record.AddStmt(T->getSizeExpr());
- Code = TYPE_VARIABLE_ARRAY;
-}
-
-void ASTTypeWriter::VisitVectorType(const VectorType *T) {
- Record.AddTypeRef(T->getElementType());
- Record.push_back(T->getNumElements());
- Record.push_back(T->getVectorKind());
- Code = TYPE_VECTOR;
-}
-
-void ASTTypeWriter::VisitExtVectorType(const ExtVectorType *T) {
- VisitVectorType(T);
- Code = TYPE_EXT_VECTOR;
-}
-
-void ASTTypeWriter::VisitFunctionType(const FunctionType *T) {
- Record.AddTypeRef(T->getReturnType());
- FunctionType::ExtInfo C = T->getExtInfo();
- Record.push_back(C.getNoReturn());
- Record.push_back(C.getHasRegParm());
- Record.push_back(C.getRegParm());
- // FIXME: need to stabilize encoding of calling convention...
- Record.push_back(C.getCC());
- Record.push_back(C.getProducesResult());
- Record.push_back(C.getNoCallerSavedRegs());
- Record.push_back(C.getNoCfCheck());
-
- if (C.getHasRegParm() || C.getRegParm() || C.getProducesResult())
- AbbrevToUse = 0;
-}
-
-void ASTTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
- VisitFunctionType(T);
- Code = TYPE_FUNCTION_NO_PROTO;
-}
-
-static void addExceptionSpec(const FunctionProtoType *T,
- ASTRecordWriter &Record) {
- Record.push_back(T->getExceptionSpecType());
- if (T->getExceptionSpecType() == EST_Dynamic) {
- Record.push_back(T->getNumExceptions());
- for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I)
- Record.AddTypeRef(T->getExceptionType(I));
- } else if (isComputedNoexcept(T->getExceptionSpecType())) {
- Record.AddStmt(T->getNoexceptExpr());
- } else if (T->getExceptionSpecType() == EST_Uninstantiated) {
- Record.AddDeclRef(T->getExceptionSpecDecl());
- Record.AddDeclRef(T->getExceptionSpecTemplate());
- } else if (T->getExceptionSpecType() == EST_Unevaluated) {
- Record.AddDeclRef(T->getExceptionSpecDecl());
+static TypeCode getTypeCodeForTypeClass(Type::TypeClass id) {
+ switch (id) {
+#define TYPE_BIT_CODE(CLASS_ID, CODE_ID, CODE_VALUE) \
+ case Type::CLASS_ID: return TYPE_##CODE_ID;
+#include "clang/Serialization/TypeBitCodes.def"
+ case Type::Builtin:
+ llvm_unreachable("shouldn't be serializing a builtin type this way");
}
+ llvm_unreachable("bad type kind");
}
-void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) {
- VisitFunctionType(T);
-
- Record.push_back(T->isVariadic());
- Record.push_back(T->hasTrailingReturn());
- Record.push_back(T->getMethodQuals().getAsOpaqueValue());
- Record.push_back(static_cast<unsigned>(T->getRefQualifier()));
- addExceptionSpec(T, Record);
-
- Record.push_back(T->getNumParams());
- for (unsigned I = 0, N = T->getNumParams(); I != N; ++I)
- Record.AddTypeRef(T->getParamType(I));
-
- if (T->hasExtParameterInfos()) {
- for (unsigned I = 0, N = T->getNumParams(); I != N; ++I)
- Record.push_back(T->getExtParameterInfo(I).getOpaqueValue());
- }
-
- if (T->isVariadic() || T->hasTrailingReturn() || T->getMethodQuals() ||
- T->getRefQualifier() || T->getExceptionSpecType() != EST_None ||
- T->hasExtParameterInfos())
- AbbrevToUse = 0;
-
- Code = TYPE_FUNCTION_PROTO;
-}
-
-void ASTTypeWriter::VisitUnresolvedUsingType(const UnresolvedUsingType *T) {
- Record.AddDeclRef(T->getDecl());
- Code = TYPE_UNRESOLVED_USING;
-}
-
-void ASTTypeWriter::VisitTypedefType(const TypedefType *T) {
- Record.AddDeclRef(T->getDecl());
- assert(!T->isCanonicalUnqualified() && "Invalid typedef ?");
- Record.AddTypeRef(T->getCanonicalTypeInternal());
- Code = TYPE_TYPEDEF;
-}
-
-void ASTTypeWriter::VisitTypeOfExprType(const TypeOfExprType *T) {
- Record.AddStmt(T->getUnderlyingExpr());
- Code = TYPE_TYPEOF_EXPR;
-}
-
-void ASTTypeWriter::VisitTypeOfType(const TypeOfType *T) {
- Record.AddTypeRef(T->getUnderlyingType());
- Code = TYPE_TYPEOF;
-}
-
-void ASTTypeWriter::VisitDecltypeType(const DecltypeType *T) {
- Record.AddTypeRef(T->getUnderlyingType());
- Record.AddStmt(T->getUnderlyingExpr());
- Code = TYPE_DECLTYPE;
-}
-
-void ASTTypeWriter::VisitUnaryTransformType(const UnaryTransformType *T) {
- Record.AddTypeRef(T->getBaseType());
- Record.AddTypeRef(T->getUnderlyingType());
- Record.push_back(T->getUTTKind());
- Code = TYPE_UNARY_TRANSFORM;
-}
-
-void ASTTypeWriter::VisitAutoType(const AutoType *T) {
- Record.AddTypeRef(T->getDeducedType());
- Record.push_back((unsigned)T->getKeyword());
- if (T->getDeducedType().isNull())
- Record.push_back(T->containsUnexpandedParameterPack() ? 2 :
- T->isDependentType() ? 1 : 0);
- Code = TYPE_AUTO;
-}
-
-void ASTTypeWriter::VisitDeducedTemplateSpecializationType(
- const DeducedTemplateSpecializationType *T) {
- Record.AddTemplateName(T->getTemplateName());
- Record.AddTypeRef(T->getDeducedType());
- if (T->getDeducedType().isNull())
- Record.push_back(T->isDependentType());
- Code = TYPE_DEDUCED_TEMPLATE_SPECIALIZATION;
-}
-
-void ASTTypeWriter::VisitTagType(const TagType *T) {
- Record.push_back(T->isDependentType());
- Record.AddDeclRef(T->getDecl()->getCanonicalDecl());
- assert(!T->isBeingDefined() &&
- "Cannot serialize in the middle of a type definition");
-}
-
-void ASTTypeWriter::VisitRecordType(const RecordType *T) {
- VisitTagType(T);
- Code = TYPE_RECORD;
-}
-
-void ASTTypeWriter::VisitEnumType(const EnumType *T) {
- VisitTagType(T);
- Code = TYPE_ENUM;
-}
-
-void ASTTypeWriter::VisitAttributedType(const AttributedType *T) {
- Record.AddTypeRef(T->getModifiedType());
- Record.AddTypeRef(T->getEquivalentType());
- Record.push_back(T->getAttrKind());
- Code = TYPE_ATTRIBUTED;
-}
-
-void
-ASTTypeWriter::VisitSubstTemplateTypeParmType(
- const SubstTemplateTypeParmType *T) {
- Record.AddTypeRef(QualType(T->getReplacedParameter(), 0));
- Record.AddTypeRef(T->getReplacementType());
- Code = TYPE_SUBST_TEMPLATE_TYPE_PARM;
-}
-
-void
-ASTTypeWriter::VisitSubstTemplateTypeParmPackType(
- const SubstTemplateTypeParmPackType *T) {
- Record.AddTypeRef(QualType(T->getReplacedParameter(), 0));
- Record.AddTemplateArgument(T->getArgumentPack());
- Code = TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK;
-}
-
-void
-ASTTypeWriter::VisitTemplateSpecializationType(
- const TemplateSpecializationType *T) {
- Record.push_back(T->isDependentType());
- Record.AddTemplateName(T->getTemplateName());
- Record.push_back(T->getNumArgs());
- for (const auto &ArgI : *T)
- Record.AddTemplateArgument(ArgI);
- Record.AddTypeRef(T->isTypeAlias() ? T->getAliasedType()
- : T->isCanonicalUnqualified()
- ? QualType()
- : T->getCanonicalTypeInternal());
- Code = TYPE_TEMPLATE_SPECIALIZATION;
-}
-
-void
-ASTTypeWriter::VisitDependentSizedArrayType(const DependentSizedArrayType *T) {
- VisitArrayType(T);
- Record.AddStmt(T->getSizeExpr());
- Record.AddSourceRange(T->getBracketsRange());
- Code = TYPE_DEPENDENT_SIZED_ARRAY;
-}
-
-void
-ASTTypeWriter::VisitDependentSizedExtVectorType(
- const DependentSizedExtVectorType *T) {
- Record.AddTypeRef(T->getElementType());
- Record.AddStmt(T->getSizeExpr());
- Record.AddSourceLocation(T->getAttributeLoc());
- Code = TYPE_DEPENDENT_SIZED_EXT_VECTOR;
-}
-
-void ASTTypeWriter::VisitDependentVectorType(const DependentVectorType *T) {
- Record.AddTypeRef(T->getElementType());
- Record.AddStmt(const_cast<Expr*>(T->getSizeExpr()));
- Record.AddSourceLocation(T->getAttributeLoc());
- Record.push_back(T->getVectorKind());
- Code = TYPE_DEPENDENT_SIZED_VECTOR;
-}
-
-void
-ASTTypeWriter::VisitDependentAddressSpaceType(
- const DependentAddressSpaceType *T) {
- Record.AddTypeRef(T->getPointeeType());
- Record.AddStmt(T->getAddrSpaceExpr());
- Record.AddSourceLocation(T->getAttributeLoc());
- Code = TYPE_DEPENDENT_ADDRESS_SPACE;
-}
-
-void
-ASTTypeWriter::VisitTemplateTypeParmType(const TemplateTypeParmType *T) {
- Record.push_back(T->getDepth());
- Record.push_back(T->getIndex());
- Record.push_back(T->isParameterPack());
- Record.AddDeclRef(T->getDecl());
- Code = TYPE_TEMPLATE_TYPE_PARM;
-}
-
-void
-ASTTypeWriter::VisitDependentNameType(const DependentNameType *T) {
- Record.push_back(T->getKeyword());
- Record.AddNestedNameSpecifier(T->getQualifier());
- Record.AddIdentifierRef(T->getIdentifier());
- Record.AddTypeRef(
- T->isCanonicalUnqualified() ? QualType() : T->getCanonicalTypeInternal());
- Code = TYPE_DEPENDENT_NAME;
-}
-
-void
-ASTTypeWriter::VisitDependentTemplateSpecializationType(
- const DependentTemplateSpecializationType *T) {
- Record.push_back(T->getKeyword());
- Record.AddNestedNameSpecifier(T->getQualifier());
- Record.AddIdentifierRef(T->getIdentifier());
- Record.push_back(T->getNumArgs());
- for (const auto &I : *T)
- Record.AddTemplateArgument(I);
- Code = TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION;
-}
-
-void ASTTypeWriter::VisitPackExpansionType(const PackExpansionType *T) {
- Record.AddTypeRef(T->getPattern());
- if (Optional<unsigned> NumExpansions = T->getNumExpansions())
- Record.push_back(*NumExpansions + 1);
- else
- Record.push_back(0);
- Code = TYPE_PACK_EXPANSION;
-}
-
-void ASTTypeWriter::VisitParenType(const ParenType *T) {
- Record.AddTypeRef(T->getInnerType());
- Code = TYPE_PAREN;
-}
-
-void ASTTypeWriter::VisitMacroQualifiedType(const MacroQualifiedType *T) {
- Record.AddTypeRef(T->getUnderlyingType());
- Record.AddIdentifierRef(T->getMacroIdentifier());
- Code = TYPE_MACRO_QUALIFIED;
-}
-
-void ASTTypeWriter::VisitElaboratedType(const ElaboratedType *T) {
- Record.push_back(T->getKeyword());
- Record.AddNestedNameSpecifier(T->getQualifier());
- Record.AddTypeRef(T->getNamedType());
- Record.AddDeclRef(T->getOwnedTagDecl());
- Code = TYPE_ELABORATED;
-}
-
-void ASTTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) {
- Record.AddDeclRef(T->getDecl()->getCanonicalDecl());
- Record.AddTypeRef(T->getInjectedSpecializationType());
- Code = TYPE_INJECTED_CLASS_NAME;
-}
-
-void ASTTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) {
- Record.AddDeclRef(T->getDecl()->getCanonicalDecl());
- Code = TYPE_OBJC_INTERFACE;
-}
-
-void ASTTypeWriter::VisitObjCTypeParamType(const ObjCTypeParamType *T) {
- Record.AddDeclRef(T->getDecl());
- Record.push_back(T->getNumProtocols());
- for (const auto *I : T->quals())
- Record.AddDeclRef(I);
- Code = TYPE_OBJC_TYPE_PARAM;
-}
-
-void ASTTypeWriter::VisitObjCObjectType(const ObjCObjectType *T) {
- Record.AddTypeRef(T->getBaseType());
- Record.push_back(T->getTypeArgsAsWritten().size());
- for (auto TypeArg : T->getTypeArgsAsWritten())
- Record.AddTypeRef(TypeArg);
- Record.push_back(T->getNumProtocols());
- for (const auto *I : T->quals())
- Record.AddDeclRef(I);
- Record.push_back(T->isKindOfTypeAsWritten());
- Code = TYPE_OBJC_OBJECT;
-}
+namespace {
-void
-ASTTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) {
- Record.AddTypeRef(T->getPointeeType());
- Code = TYPE_OBJC_OBJECT_POINTER;
-}
+class ASTTypeWriter {
+ ASTWriter &Writer;
+ ASTWriter::RecordData Record;
+ ASTRecordWriter BasicWriter;
-void
-ASTTypeWriter::VisitAtomicType(const AtomicType *T) {
- Record.AddTypeRef(T->getValueType());
- Code = TYPE_ATOMIC;
-}
+public:
+ ASTTypeWriter(ASTWriter &Writer)
+ : Writer(Writer), BasicWriter(Writer, Record) {}
-void
-ASTTypeWriter::VisitPipeType(const PipeType *T) {
- Record.AddTypeRef(T->getElementType());
- Record.push_back(T->isReadOnly());
- Code = TYPE_PIPE;
-}
+ uint64_t write(QualType T) {
+ if (T.hasLocalNonFastQualifiers()) {
+ Qualifiers Qs = T.getLocalQualifiers();
+ BasicWriter.writeQualType(T.getLocalUnqualifiedType());
+ BasicWriter.writeQualifiers(Qs);
+ return BasicWriter.Emit(TYPE_EXT_QUAL, Writer.getTypeExtQualAbbrev());
+ }
-namespace {
+ const Type *typePtr = T.getTypePtr();
+ serialization::AbstractTypeWriter<ASTRecordWriter> atw(BasicWriter);
+ atw.write(typePtr);
+ return BasicWriter.Emit(getTypeCodeForTypeClass(typePtr->getTypeClass()),
+ /*abbrev*/ 0);
+ }
+};
class TypeLocWriter : public TypeLocVisitor<TypeLocWriter> {
ASTRecordWriter &Record;
@@ -3198,12 +2786,8 @@ void ASTWriter::WriteType(QualType T) {
assert(Idx.getIndex() >= FirstTypeID && "Re-writing a type from a prior AST");
- RecordData Record;
-
// Emit the type's representation.
- ASTTypeWriter W(*this, Record);
- W.Visit(T);
- uint64_t Offset = W.Emit();
+ uint64_t Offset = ASTTypeWriter(*this).write(T);
// Record the offset for this type.
unsigned Index = Idx.getIndex() - FirstTypeID;
@@ -5364,11 +4948,12 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
Record.AddStmt(cast<CXXDestructorDecl>(D)->getOperatorDeleteThisArg());
break;
- case UPD_CXX_RESOLVED_EXCEPTION_SPEC:
- addExceptionSpec(
- cast<FunctionDecl>(D)->getType()->castAs<FunctionProtoType>(),
- Record);
+ case UPD_CXX_RESOLVED_EXCEPTION_SPEC: {
+ auto prototype =
+ cast<FunctionDecl>(D)->getType()->castAs<FunctionProtoType>();
+ Record.writeExceptionSpecInfo(prototype->getExceptionSpecInfo());
break;
+ }
case UPD_CXX_DEDUCED_RETURN_TYPE:
Record.push_back(GetOrCreateTypeID(Update.getType()));
@@ -5434,17 +5019,6 @@ void ASTWriter::AddSourceRange(SourceRange Range, RecordDataImpl &Record) {
AddSourceLocation(Range.getEnd(), Record);
}
-void ASTRecordWriter::AddAPInt(const llvm::APInt &Value) {
- Record->push_back(Value.getBitWidth());
- const uint64_t *Words = Value.getRawData();
- Record->append(Words, Words + Value.getNumWords());
-}
-
-void ASTRecordWriter::AddAPSInt(const llvm::APSInt &Value) {
- Record->push_back(Value.isUnsigned());
- AddAPInt(Value);
-}
-
void ASTRecordWriter::AddAPFloat(const llvm::APFloat &Value) {
AddAPInt(Value.bitcastToAPInt());
}
@@ -5762,44 +5336,6 @@ void ASTWriter::associateDeclWithFile(const Decl *D, DeclID ID) {
Decls.insert(I, LocDecl);
}
-void ASTRecordWriter::AddDeclarationName(DeclarationName Name) {
- // FIXME: Emit a stable enum for NameKind. 0 = Identifier etc.
- Record->push_back(Name.getNameKind());
- switch (Name.getNameKind()) {
- case DeclarationName::Identifier:
- AddIdentifierRef(Name.getAsIdentifierInfo());
- break;
-
- case DeclarationName::ObjCZeroArgSelector:
- case DeclarationName::ObjCOneArgSelector:
- case DeclarationName::ObjCMultiArgSelector:
- AddSelectorRef(Name.getObjCSelector());
- break;
-
- case DeclarationName::CXXConstructorName:
- case DeclarationName::CXXDestructorName:
- case DeclarationName::CXXConversionFunctionName:
- AddTypeRef(Name.getCXXNameType());
- break;
-
- case DeclarationName::CXXDeductionGuideName:
- AddDeclRef(Name.getCXXDeductionGuideTemplate());
- break;
-
- case DeclarationName::CXXOperatorName:
- Record->push_back(Name.getCXXOverloadedOperator());
- break;
-
- case DeclarationName::CXXLiteralOperatorName:
- AddIdentifierRef(Name.getCXXLiteralIdentifier());
- break;
-
- case DeclarationName::CXXUsingDirective:
- // No extra data to emit
- break;
- }
-}
-
unsigned ASTWriter::getAnonymousDeclarationNumber(const NamedDecl *D) {
assert(needsAnonymousDeclarationNumber(D) &&
"expected an anonymous declaration");
@@ -5866,52 +5402,6 @@ void ASTRecordWriter::AddQualifierInfo(const QualifierInfo &Info) {
AddTemplateParameterList(Info.TemplParamLists[i]);
}
-void ASTRecordWriter::AddNestedNameSpecifier(NestedNameSpecifier *NNS) {
- // Nested name specifiers usually aren't too long. I think that 8 would
- // typically accommodate the vast majority.
- SmallVector<NestedNameSpecifier *, 8> NestedNames;
-
- // Push each of the NNS's onto a stack for serialization in reverse order.
- while (NNS) {
- NestedNames.push_back(NNS);
- NNS = NNS->getPrefix();
- }
-
- Record->push_back(NestedNames.size());
- while(!NestedNames.empty()) {
- NNS = NestedNames.pop_back_val();
- NestedNameSpecifier::SpecifierKind Kind = NNS->getKind();
- Record->push_back(Kind);
- switch (Kind) {
- case NestedNameSpecifier::Identifier:
- AddIdentifierRef(NNS->getAsIdentifier());
- break;
-
- case NestedNameSpecifier::Namespace:
- AddDeclRef(NNS->getAsNamespace());
- break;
-
- case NestedNameSpecifier::NamespaceAlias:
- AddDeclRef(NNS->getAsNamespaceAlias());
- break;
-
- case NestedNameSpecifier::TypeSpec:
- case NestedNameSpecifier::TypeSpecWithTemplate:
- AddTypeRef(QualType(NNS->getAsType(), 0));
- Record->push_back(Kind == NestedNameSpecifier::TypeSpecWithTemplate);
- break;
-
- case NestedNameSpecifier::Global:
- // Don't need to write an associated value.
- break;
-
- case NestedNameSpecifier::Super:
- AddDeclRef(NNS->getAsRecordDecl());
- break;
- }
- }
-}
-
void ASTRecordWriter::AddNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
// Nested name specifiers usually aren't too long. I think that 8 would
// typically accommodate the vast majority.
@@ -5966,105 +5456,6 @@ void ASTRecordWriter::AddNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
}
}
-void ASTRecordWriter::AddTemplateName(TemplateName Name) {
- TemplateName::NameKind Kind = Name.getKind();
- Record->push_back(Kind);
- switch (Kind) {
- case TemplateName::Template:
- AddDeclRef(Name.getAsTemplateDecl());
- break;
-
- case TemplateName::OverloadedTemplate: {
- OverloadedTemplateStorage *OvT = Name.getAsOverloadedTemplate();
- Record->push_back(OvT->size());
- for (const auto &I : *OvT)
- AddDeclRef(I);
- break;
- }
-
- case TemplateName::AssumedTemplate: {
- AssumedTemplateStorage *ADLT = Name.getAsAssumedTemplateName();
- AddDeclarationName(ADLT->getDeclName());
- break;
- }
-
- case TemplateName::QualifiedTemplate: {
- QualifiedTemplateName *QualT = Name.getAsQualifiedTemplateName();
- AddNestedNameSpecifier(QualT->getQualifier());
- Record->push_back(QualT->hasTemplateKeyword());
- AddDeclRef(QualT->getTemplateDecl());
- break;
- }
-
- case TemplateName::DependentTemplate: {
- DependentTemplateName *DepT = Name.getAsDependentTemplateName();
- AddNestedNameSpecifier(DepT->getQualifier());
- Record->push_back(DepT->isIdentifier());
- if (DepT->isIdentifier())
- AddIdentifierRef(DepT->getIdentifier());
- else
- Record->push_back(DepT->getOperator());
- break;
- }
-
- case TemplateName::SubstTemplateTemplateParm: {
- SubstTemplateTemplateParmStorage *subst
- = Name.getAsSubstTemplateTemplateParm();
- AddDeclRef(subst->getParameter());
- AddTemplateName(subst->getReplacement());
- break;
- }
-
- case TemplateName::SubstTemplateTemplateParmPack: {
- SubstTemplateTemplateParmPackStorage *SubstPack
- = Name.getAsSubstTemplateTemplateParmPack();
- AddDeclRef(SubstPack->getParameterPack());
- AddTemplateArgument(SubstPack->getArgumentPack());
- break;
- }
- }
-}
-
-void ASTRecordWriter::AddTemplateArgument(const TemplateArgument &Arg) {
- Record->push_back(Arg.getKind());
- switch (Arg.getKind()) {
- case TemplateArgument::Null:
- break;
- case TemplateArgument::Type:
- AddTypeRef(Arg.getAsType());
- break;
- case TemplateArgument::Declaration:
- AddDeclRef(Arg.getAsDecl());
- AddTypeRef(Arg.getParamTypeForDecl());
- break;
- case TemplateArgument::NullPtr:
- AddTypeRef(Arg.getNullPtrType());
- break;
- case TemplateArgument::Integral:
- AddAPSInt(Arg.getAsIntegral());
- AddTypeRef(Arg.getIntegralType());
- break;
- case TemplateArgument::Template:
- AddTemplateName(Arg.getAsTemplateOrTemplatePattern());
- break;
- case TemplateArgument::TemplateExpansion:
- AddTemplateName(Arg.getAsTemplateOrTemplatePattern());
- if (Optional<unsigned> NumExpansions = Arg.getNumTemplateExpansions())
- Record->push_back(*NumExpansions + 1);
- else
- Record->push_back(0);
- break;
- case TemplateArgument::Expression:
- AddStmt(Arg.getAsExpr());
- break;
- case TemplateArgument::Pack:
- Record->push_back(Arg.pack_size());
- for (const auto &P : Arg.pack_elements())
- AddTemplateArgument(P);
- break;
- }
-}
-
void ASTRecordWriter::AddTemplateParameterList(
const TemplateParameterList *TemplateParams) {
assert(TemplateParams && "No TemplateParams!");
@@ -6192,8 +5583,8 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
// getODRHash will compute the ODRHash if it has not been previously computed.
Record->push_back(D->getODRHash());
- bool ModulesDebugInfo = Writer->Context->getLangOpts().ModulesDebugInfo &&
- Writer->WritingModule && !D->isDependentType();
+ bool ModulesDebugInfo =
+ Writer->Context->getLangOpts().ModulesDebugInfo && !D->isDependentType();
Record->push_back(ModulesDebugInfo);
if (ModulesDebugInfo)
Writer->ModularCodegenDecls.push_back(Writer->GetDeclRef(D));
@@ -6614,6 +6005,26 @@ void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
//// OMPClause Serialization
////===----------------------------------------------------------------------===//
+namespace {
+
+class OMPClauseWriter : public OMPClauseVisitor<OMPClauseWriter> {
+ ASTRecordWriter &Record;
+
+public:
+ OMPClauseWriter(ASTRecordWriter &Record) : Record(Record) {}
+#define OPENMP_CLAUSE(Name, Class) void Visit##Class(Class *S);
+#include "clang/Basic/OpenMPKinds.def"
+ void writeClause(OMPClause *C);
+ void VisitOMPClauseWithPreInit(OMPClauseWithPreInit *C);
+ void VisitOMPClauseWithPostUpdate(OMPClauseWithPostUpdate *C);
+};
+
+}
+
+void ASTRecordWriter::writeOMPClause(OMPClause *C) {
+ OMPClauseWriter(*this).writeClause(C);
+}
+
void OMPClauseWriter::writeClause(OMPClause *C) {
Record.push_back(C->getClauseKind());
Visit(C);
@@ -6622,7 +6033,7 @@ void OMPClauseWriter::writeClause(OMPClause *C) {
}
void OMPClauseWriter::VisitOMPClauseWithPreInit(OMPClauseWithPreInit *C) {
- Record.push_back(C->getCaptureRegion());
+ Record.push_back(uint64_t(C->getCaptureRegion()));
Record.AddStmt(C->getPreInitStmt());
}
@@ -6633,7 +6044,7 @@ void OMPClauseWriter::VisitOMPClauseWithPostUpdate(OMPClauseWithPostUpdate *C) {
void OMPClauseWriter::VisitOMPIfClause(OMPIfClause *C) {
VisitOMPClauseWithPreInit(C);
- Record.push_back(C->getNameModifier());
+ Record.push_back(uint64_t(C->getNameModifier()));
Record.AddSourceLocation(C->getNameModifierLoc());
Record.AddSourceLocation(C->getColonLoc());
Record.AddStmt(C->getCondition());
@@ -6679,7 +6090,7 @@ void OMPClauseWriter::VisitOMPDefaultClause(OMPDefaultClause *C) {
}
void OMPClauseWriter::VisitOMPProcBindClause(OMPProcBindClause *C) {
- Record.push_back(C->getProcBindKind());
+ Record.push_back(unsigned(C->getProcBindKind()));
Record.AddSourceLocation(C->getLParenLoc());
Record.AddSourceLocation(C->getProcBindKindKwLoc());
}
@@ -6759,6 +6170,9 @@ void OMPClauseWriter::VisitOMPLastprivateClause(OMPLastprivateClause *C) {
Record.push_back(C->varlist_size());
VisitOMPClauseWithPostUpdate(C);
Record.AddSourceLocation(C->getLParenLoc());
+ Record.writeEnum(C->getKind());
+ Record.AddSourceLocation(C->getKindLoc());
+ Record.AddSourceLocation(C->getColonLoc());
for (auto *VE : C->varlists())
Record.AddStmt(VE);
for (auto *E : C->private_copies())
@@ -7127,3 +6541,12 @@ void OMPClauseWriter::VisitOMPAtomicDefaultMemOrderClause(
Record.AddSourceLocation(C->getLParenLoc());
Record.AddSourceLocation(C->getAtomicDefaultMemOrderKindKwLoc());
}
+
+void OMPClauseWriter::VisitOMPNontemporalClause(OMPNontemporalClause *C) {
+ Record.push_back(C->varlist_size());
+ Record.AddSourceLocation(C->getLParenLoc());
+ for (auto *VE : C->varlists())
+ Record.AddStmt(VE);
+ for (auto *E : C->private_refs())
+ Record.AddStmt(E);
+}
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 039b57f88e73..b2a8c118d401 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "ASTCommon.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclContextInternals.h"
#include "clang/AST/DeclTemplate.h"
@@ -20,7 +21,7 @@
#include "clang/AST/PrettyDeclStackTrace.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Serialization/ASTReader.h"
-#include "clang/Serialization/ASTWriter.h"
+#include "clang/Serialization/ASTRecordWriter.h"
#include "llvm/Bitstream/BitstreamWriter.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
@@ -124,6 +125,7 @@ namespace clang {
void VisitBlockDecl(BlockDecl *D);
void VisitCapturedDecl(CapturedDecl *D);
void VisitEmptyDecl(EmptyDecl *D);
+ void VisitLifetimeExtendedTemporaryDecl(LifetimeExtendedTemporaryDecl *D);
void VisitDeclContext(DeclContext *DC);
template <typename T> void VisitRedeclarable(Redeclarable<T> *D);
@@ -521,8 +523,11 @@ void ASTDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) {
VisitValueDecl(D);
Record.AddSourceLocation(D->getInnerLocStart());
Record.push_back(D->hasExtInfo());
- if (D->hasExtInfo())
- Record.AddQualifierInfo(*D->getExtInfo());
+ if (D->hasExtInfo()) {
+ DeclaratorDecl::ExtInfo *Info = D->getExtInfo();
+ Record.AddQualifierInfo(*Info);
+ Record.AddStmt(Info->TrailingRequiresClause);
+ }
// The location information is deferred until the end of the record.
Record.AddTypeRef(D->getTypeSourceInfo() ? D->getTypeSourceInfo()->getType()
: QualType());
@@ -558,6 +563,19 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
Record.AddSourceLocation(D->getEndLoc());
Record.push_back(D->getODRHash());
+ Record.push_back(D->usesFPIntrin());
+
+ 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()) {
@@ -662,17 +680,17 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
VisitNamedDecl(D);
// FIXME: convert to LazyStmtPtr?
// Unlike C/C++, method bodies will never be in header files.
- bool HasBodyStuff = D->getBody() != nullptr ||
- D->getSelfDecl() != nullptr || D->getCmdDecl() != nullptr;
+ bool HasBodyStuff = D->getBody() != nullptr;
Record.push_back(HasBodyStuff);
if (HasBodyStuff) {
Record.AddStmt(D->getBody());
- Record.AddDeclRef(D->getSelfDecl());
- Record.AddDeclRef(D->getCmdDecl());
}
+ Record.AddDeclRef(D->getSelfDecl());
+ Record.AddDeclRef(D->getCmdDecl());
Record.push_back(D->isInstanceMethod());
Record.push_back(D->isVariadic());
Record.push_back(D->isPropertyAccessor());
+ Record.push_back(D->isSynthesizedAccessorStub());
Record.push_back(D->isDefined());
Record.push_back(D->isOverriding());
Record.push_back(D->hasSkippedBody());
@@ -884,6 +902,8 @@ void ASTDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
Record.AddDeclRef(D->getPropertyDecl());
Record.AddDeclRef(D->getPropertyIvarDecl());
Record.AddSourceLocation(D->getPropertyIvarDeclLoc());
+ Record.AddDeclRef(D->getGetterMethodDecl());
+ Record.AddDeclRef(D->getSetterMethodDecl());
Record.AddStmt(D->getGetterCXXConstructor());
Record.AddStmt(D->getSetterCXXAssignment());
Code = serialization::DECL_OBJC_PROPERTY_IMPL;
@@ -982,7 +1002,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
}
if (D->hasAttr<BlocksAttr>() && D->getType()->getAsCXXRecordDecl()) {
- ASTContext::BlockVarCopyInit Init = Writer.Context->getBlockVarCopyInit(D);
+ BlockVarCopyInit Init = Writer.Context->getBlockVarCopyInit(D);
Record.AddStmt(Init.getCopyExpr());
if (Init.getCopyExpr())
Record.push_back(Init.canThrow());
@@ -990,15 +1010,16 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
if (D->getStorageDuration() == SD_Static) {
bool ModulesCodegen = false;
- if (Writer.WritingModule &&
- !D->getDescribedVarTemplate() && !D->getMemberSpecializationInfo() &&
+ if (!D->getDescribedVarTemplate() && !D->getMemberSpecializationInfo() &&
!isa<VarTemplateSpecializationDecl>(D)) {
// When building a C++ Modules TS module interface unit, a strong
// definition in the module interface is provided by the compilation of
// that module interface unit, not by its users. (Inline variables are
// still emitted in module users.)
ModulesCodegen =
- (Writer.WritingModule->Kind == Module::ModuleInterfaceUnit &&
+ (((Writer.WritingModule &&
+ Writer.WritingModule->Kind == Module::ModuleInterfaceUnit) ||
+ Writer.Context->getLangOpts().BuildingPCHWithObjectFile) &&
Writer.Context->GetGVALinkageForVariable(D) == GVA_StrongExternal);
}
Record.push_back(ModulesCodegen);
@@ -1131,6 +1152,17 @@ void ASTDeclWriter::VisitEmptyDecl(EmptyDecl *D) {
Code = serialization::DECL_EMPTY;
}
+void ASTDeclWriter::VisitLifetimeExtendedTemporaryDecl(
+ LifetimeExtendedTemporaryDecl *D) {
+ VisitDecl(D);
+ Record.AddDeclRef(D->getExtendingDecl());
+ Record.AddStmt(D->getTemporaryExpr());
+ Record.push_back(static_cast<bool>(D->getValue()));
+ if (D->getValue())
+ Record.AddAPValue(*D->getValue());
+ Record.push_back(D->getManglingNumber());
+ Code = serialization::DECL_LIFETIME_EXTENDED_TEMPORARY;
+}
void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) {
VisitDecl(D);
Record.AddStmt(D->getBody());
@@ -1511,11 +1543,11 @@ void ASTDeclWriter::VisitClassTemplateSpecializationDecl(
void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *D) {
- VisitClassTemplateSpecializationDecl(D);
-
Record.AddTemplateParameterList(D->getTemplateParameters());
Record.AddASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten());
+ VisitClassTemplateSpecializationDecl(D);
+
// These are read/set from/to the first declaration.
if (D->getPreviousDecl() == nullptr) {
Record.AddDeclRef(D->getInstantiatedFromMember());
@@ -1571,11 +1603,11 @@ void ASTDeclWriter::VisitVarTemplateSpecializationDecl(
void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl(
VarTemplatePartialSpecializationDecl *D) {
- VisitVarTemplateSpecializationDecl(D);
-
Record.AddTemplateParameterList(D->getTemplateParameters());
Record.AddASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten());
+ VisitVarTemplateSpecializationDecl(D);
+
// These are read/set from/to the first declaration.
if (D->getPreviousDecl() == nullptr) {
Record.AddDeclRef(D->getInstantiatedFromMember());
@@ -1605,10 +1637,26 @@ void ASTDeclWriter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
}
void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
+ Record.push_back(D->hasTypeConstraint());
VisitTypeDecl(D);
Record.push_back(D->wasDeclaredWithTypename());
- // TODO: Concepts - constrained parameters.
+
+ const TypeConstraint *TC = D->getTypeConstraint();
+ Record.push_back(TC != nullptr);
+ if (TC) {
+ Record.AddNestedNameSpecifierLoc(TC->getNestedNameSpecifierLoc());
+ Record.AddDeclarationNameInfo(TC->getConceptNameInfo());
+ Record.AddDeclRef(TC->getNamedConcept());
+ Record.push_back(TC->getTemplateArgsAsWritten() != nullptr);
+ if (TC->getTemplateArgsAsWritten())
+ Record.AddASTTemplateArgumentListInfo(TC->getTemplateArgsAsWritten());
+ Record.AddStmt(TC->getImmediatelyDeclaredConstraint());
+ Record.push_back(D->isExpandedParameterPack());
+ if (D->isExpandedParameterPack())
+ Record.push_back(D->getNumExpansionParameters());
+ }
+
bool OwnsDefaultArg = D->hasDefaultArgument() &&
!D->defaultArgumentWasInherited();
Record.push_back(OwnsDefaultArg);
@@ -1638,7 +1686,6 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
Code = serialization::DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK;
} else {
- // TODO: Concepts - constrained parameters.
// Rest of NonTypeTemplateParmDecl.
Record.push_back(D->isParameterPack());
bool OwnsDefaultArg = D->hasDefaultArgument() &&
@@ -1668,7 +1715,6 @@ void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
Record.AddTemplateParameterList(D->getExpansionTemplateParameters(I));
Code = serialization::DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK;
} else {
- // TODO: Concepts - constrained parameters.
// Rest of TemplateTemplateParmDecl.
Record.push_back(D->isParameterPack());
bool OwnsDefaultArg = D->hasDefaultArgument() &&
@@ -1790,18 +1836,16 @@ void ASTDeclWriter::VisitOMPAllocateDecl(OMPAllocateDecl *D) {
VisitDecl(D);
for (auto *I : D->varlists())
Record.AddStmt(I);
- OMPClauseWriter ClauseWriter(Record);
for (OMPClause *C : D->clauselists())
- ClauseWriter.writeClause(C);
+ Record.writeOMPClause(C);
Code = serialization::DECL_OMP_ALLOCATE;
}
void ASTDeclWriter::VisitOMPRequiresDecl(OMPRequiresDecl *D) {
Record.push_back(D->clauselist_size());
VisitDecl(D);
- OMPClauseWriter ClauseWriter(Record);
for (OMPClause *C : D->clauselists())
- ClauseWriter.writeClause(C);
+ Record.writeOMPClause(C);
Code = serialization::DECL_OMP_REQUIRES;
}
@@ -1826,9 +1870,8 @@ void ASTDeclWriter::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) {
Record.AddStmt(D->getMapperVarRef());
Record.AddDeclarationName(D->getVarName());
Record.AddDeclRef(D->getPrevDeclInScope());
- OMPClauseWriter ClauseWriter(Record);
for (OMPClause *C : D->clauselists())
- ClauseWriter.writeClause(C);
+ Record.writeOMPClause(C);
Code = serialization::DECL_OMP_DECLARE_MAPPER;
}
@@ -2397,9 +2440,11 @@ void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) {
assert(FD->doesThisDeclarationHaveABody());
bool ModulesCodegen = false;
- if (Writer->WritingModule && !FD->isDependentContext()) {
+ if (!FD->isDependentContext()) {
Optional<GVALinkage> Linkage;
- if (Writer->WritingModule->Kind == Module::ModuleInterfaceUnit) {
+ if ((Writer->WritingModule &&
+ Writer->WritingModule->Kind == Module::ModuleInterfaceUnit) ||
+ Writer->Context->getLangOpts().BuildingPCHWithObjectFile) {
// When building a C++ Modules TS module interface unit, a strong
// definition in the module interface is provided by the compilation of
// that module interface unit, not by its users. (Inline functions are
@@ -2409,11 +2454,12 @@ void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) {
}
if (Writer->Context->getLangOpts().ModulesCodegen) {
// Under -fmodules-codegen, codegen is performed for all non-internal,
- // non-always_inline functions.
+ // non-always_inline functions, unless they are available elsewhere.
if (!FD->hasAttr<AlwaysInlineAttr>()) {
if (!Linkage)
Linkage = Writer->Context->GetGVALinkageForFunction(FD);
- ModulesCodegen = *Linkage != GVA_Internal;
+ ModulesCodegen =
+ *Linkage != GVA_Internal && *Linkage != GVA_AvailableExternally;
}
}
}
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index c39d4d39bcdf..9231f3b2b9ba 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -11,7 +11,7 @@
///
//===----------------------------------------------------------------------===//
-#include "clang/Serialization/ASTWriter.h"
+#include "clang/Serialization/ASTRecordWriter.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -395,13 +395,30 @@ void ASTStmtWriter::VisitConceptSpecializationExpr(
Record.push_back(TemplateArgs.size());
Record.AddNestedNameSpecifierLoc(E->getNestedNameSpecifierLoc());
Record.AddSourceLocation(E->getTemplateKWLoc());
- Record.AddSourceLocation(E->getConceptNameLoc());
- Record.AddDeclRef(E->getFoundDecl());
+ Record.AddDeclarationNameInfo(E->getConceptNameInfo());
Record.AddDeclRef(E->getNamedConcept());
Record.AddASTTemplateArgumentListInfo(E->getTemplateArgsAsWritten());
for (const TemplateArgument &Arg : TemplateArgs)
Record.AddTemplateArgument(Arg);
- Record.push_back(E->isSatisfied());
+ const ASTConstraintSatisfaction &Satisfaction = E->getSatisfaction();
+ Record.push_back(Satisfaction.IsSatisfied);
+ if (!Satisfaction.IsSatisfied) {
+ Record.push_back(Satisfaction.NumRecords);
+ for (const auto &DetailRecord : Satisfaction) {
+ Record.AddStmt(const_cast<Expr *>(DetailRecord.first));
+ auto *E = DetailRecord.second.dyn_cast<Expr *>();
+ Record.push_back(E == nullptr);
+ if (E)
+ Record.AddStmt(E);
+ else {
+ auto *Diag = DetailRecord.second.get<std::pair<SourceLocation,
+ StringRef> *>();
+ Record.AddSourceLocation(Diag->first);
+ Record.AddString(Diag->second);
+ }
+ }
+ }
+
Code = serialization::EXPR_CONCEPT_SPECIALIZATION;
}
@@ -1835,9 +1852,11 @@ void ASTStmtWriter::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) {
void ASTStmtWriter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
VisitExpr(E);
- Record.AddStmt(E->getTemporary());
- Record.AddDeclRef(E->getExtendingDecl());
- Record.push_back(E->getManglingNumber());
+ Record.push_back(static_cast<bool>(E->getLifetimeExtendedTemporaryDecl()));
+ if (E->getLifetimeExtendedTemporaryDecl())
+ Record.AddDeclRef(E->getLifetimeExtendedTemporaryDecl());
+ else
+ Record.AddStmt(E->getSubExpr());
Code = serialization::EXPR_MATERIALIZE_TEMPORARY;
}
@@ -1958,9 +1977,8 @@ void ASTStmtWriter::VisitSEHLeaveStmt(SEHLeaveStmt *S) {
void ASTStmtWriter::VisitOMPExecutableDirective(OMPExecutableDirective *E) {
Record.AddSourceLocation(E->getBeginLoc());
Record.AddSourceLocation(E->getEndLoc());
- OMPClauseWriter ClauseWriter(Record);
for (unsigned i = 0; i < E->getNumClauses(); ++i) {
- ClauseWriter.writeClause(E->getClause(i));
+ Record.writeOMPClause(E->getClause(i));
}
if (E->hasAssociatedStmt())
Record.AddStmt(E->getAssociatedStmt());
@@ -2101,6 +2119,14 @@ void ASTStmtWriter::VisitOMPParallelForSimdDirective(
Code = serialization::STMT_OMP_PARALLEL_FOR_SIMD_DIRECTIVE;
}
+void ASTStmtWriter::VisitOMPParallelMasterDirective(
+ OMPParallelMasterDirective *D) {
+ VisitStmt(D);
+ Record.push_back(D->getNumClauses());
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_PARALLEL_MASTER_DIRECTIVE;
+}
+
void ASTStmtWriter::VisitOMPParallelSectionsDirective(
OMPParallelSectionsDirective *D) {
VisitStmt(D);
@@ -2227,7 +2253,7 @@ void ASTStmtWriter::VisitOMPCancellationPointDirective(
OMPCancellationPointDirective *D) {
VisitStmt(D);
VisitOMPExecutableDirective(D);
- Record.push_back(D->getCancelRegion());
+ Record.push_back(uint64_t(D->getCancelRegion()));
Code = serialization::STMT_OMP_CANCELLATION_POINT_DIRECTIVE;
}
@@ -2235,7 +2261,7 @@ void ASTStmtWriter::VisitOMPCancelDirective(OMPCancelDirective *D) {
VisitStmt(D);
Record.push_back(D->getNumClauses());
VisitOMPExecutableDirective(D);
- Record.push_back(D->getCancelRegion());
+ Record.push_back(uint64_t(D->getCancelRegion()));
Code = serialization::STMT_OMP_CANCEL_DIRECTIVE;
}
@@ -2267,6 +2293,12 @@ void ASTStmtWriter::VisitOMPParallelMasterTaskLoopDirective(
Code = serialization::STMT_OMP_PARALLEL_MASTER_TASKLOOP_DIRECTIVE;
}
+void ASTStmtWriter::VisitOMPParallelMasterTaskLoopSimdDirective(
+ OMPParallelMasterTaskLoopSimdDirective *D) {
+ VisitOMPLoopDirective(D);
+ Code = serialization::STMT_OMP_PARALLEL_MASTER_TASKLOOP_SIMD_DIRECTIVE;
+}
+
void ASTStmtWriter::VisitOMPDistributeDirective(OMPDistributeDirective *D) {
VisitOMPLoopDirective(D);
Code = serialization::STMT_OMP_DISTRIBUTE_DIRECTIVE;
diff --git a/clang/lib/Serialization/GlobalModuleIndex.cpp b/clang/lib/Serialization/GlobalModuleIndex.cpp
index 54ab17681ee9..462d29c2a0f1 100644
--- a/clang/lib/Serialization/GlobalModuleIndex.cpp
+++ b/clang/lib/Serialization/GlobalModuleIndex.cpp
@@ -10,12 +10,12 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Serialization/GlobalModuleIndex.h"
#include "ASTReaderInternals.h"
#include "clang/Basic/FileManager.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Serialization/ASTBitCodes.h"
-#include "clang/Serialization/GlobalModuleIndex.h"
-#include "clang/Serialization/Module.h"
+#include "clang/Serialization/ModuleFile.h"
#include "clang/Serialization/PCHContainerOperations.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/MapVector.h"
@@ -125,16 +125,17 @@ typedef llvm::OnDiskIterableChainedHashTable<IdentifierIndexReaderTrait>
}
-GlobalModuleIndex::GlobalModuleIndex(std::unique_ptr<llvm::MemoryBuffer> Buffer,
- llvm::BitstreamCursor Cursor)
- : Buffer(std::move(Buffer)), IdentifierIndex(), NumIdentifierLookups(),
+GlobalModuleIndex::GlobalModuleIndex(
+ std::unique_ptr<llvm::MemoryBuffer> IndexBuffer,
+ llvm::BitstreamCursor Cursor)
+ : Buffer(std::move(IndexBuffer)), IdentifierIndex(), NumIdentifierLookups(),
NumIdentifierLookupHits() {
- auto Fail = [&Buffer](llvm::Error &&Err) {
+ auto Fail = [&](llvm::Error &&Err) {
report_fatal_error("Module index '" + Buffer->getBufferIdentifier() +
"' failed: " + toString(std::move(Err)));
};
- llvm::TimeTraceScope TimeScope("Module LoadIndex", StringRef(""));
+ llvm::TimeTraceScope TimeScope("Module LoadIndex");
// Read the global index.
bool InGlobalIndexBlock = false;
bool Done = false;
@@ -770,7 +771,7 @@ bool GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) {
}
using namespace llvm;
- llvm::TimeTraceScope TimeScope("Module WriteIndex", StringRef(""));
+ llvm::TimeTraceScope TimeScope("Module WriteIndex");
// Emit the file header.
Stream.Emit((unsigned)'B', 8);
diff --git a/clang/lib/Serialization/Module.cpp b/clang/lib/Serialization/ModuleFile.cpp
index 2b6c9211beaf..db896fd36115 100644
--- a/clang/lib/Serialization/Module.cpp
+++ b/clang/lib/Serialization/ModuleFile.cpp
@@ -1,4 +1,4 @@
-//===- Module.cpp - Module description ------------------------------------===//
+//===- ModuleFile.cpp - Module description --------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -6,12 +6,12 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements the Module class, which describes a module that has
-// been loaded from an AST file.
+// This file implements the ModuleFile class, which describes a module that
+// has been loaded from an AST file.
//
//===----------------------------------------------------------------------===//
-#include "clang/Serialization/Module.h"
+#include "clang/Serialization/ModuleFile.h"
#include "ASTReaderInternals.h"
#include "clang/Serialization/ContinuousRangeMap.h"
#include "llvm/ADT/StringRef.h"
diff --git a/clang/lib/Serialization/ModuleManager.cpp b/clang/lib/Serialization/ModuleManager.cpp
index 4b9f20fca4f8..daef502cdcb5 100644
--- a/clang/lib/Serialization/ModuleManager.cpp
+++ b/clang/lib/Serialization/ModuleManager.cpp
@@ -18,7 +18,7 @@
#include "clang/Lex/ModuleMap.h"
#include "clang/Serialization/GlobalModuleIndex.h"
#include "clang/Serialization/InMemoryModuleCache.h"
-#include "clang/Serialization/Module.h"
+#include "clang/Serialization/ModuleFile.h"
#include "clang/Serialization/PCHContainerOperations.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
@@ -219,10 +219,7 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
return NewlyLoaded;
}
-void ModuleManager::removeModules(
- ModuleIterator First,
- llvm::SmallPtrSetImpl<ModuleFile *> &LoadedSuccessfully,
- ModuleMap *modMap) {
+void ModuleManager::removeModules(ModuleIterator First, ModuleMap *modMap) {
auto Last = end();
if (First == Last)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
index d0def6918932..2ef50a727ece 100644
--- a/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
@@ -40,6 +40,7 @@ class AnalysisOrderChecker
check::EndFunction,
check::NewAllocator,
check::Bind,
+ check::PointerEscape,
check::RegionChanges,
check::LiveSymbols> {
@@ -165,6 +166,15 @@ public:
llvm::errs() << "RegionChanges\n";
return State;
}
+
+ ProgramStateRef checkPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind) const {
+ if (isCallbackEnabled(State, "PointerEscape"))
+ llvm::errs() << "PointerEscape\n";
+ return State;
+ }
};
} // end anonymous namespace
diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 503c451670b8..21c4bbc60264 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -28,6 +28,7 @@ using namespace clang;
using namespace ento;
namespace {
+enum class ConcatFnKind { none = 0, strcat = 1, strlcat = 2 };
class CStringChecker : public Checker< eval::Call,
check::PreStmt<DeclStmt>,
check::LiveSymbols,
@@ -129,11 +130,8 @@ public:
void evalStrncpy(CheckerContext &C, const CallExpr *CE) const;
void evalStpcpy(CheckerContext &C, const CallExpr *CE) const;
void evalStrlcpy(CheckerContext &C, const CallExpr *CE) const;
- void evalStrcpyCommon(CheckerContext &C,
- const CallExpr *CE,
- bool returnEnd,
- bool isBounded,
- bool isAppending,
+ void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool ReturnEnd,
+ bool IsBounded, ConcatFnKind appendK,
bool returnPtr = true) const;
void evalStrcat(CheckerContext &C, const CallExpr *CE) const;
@@ -146,8 +144,8 @@ public:
void evalStrncasecmp(CheckerContext &C, const CallExpr *CE) const;
void evalStrcmpCommon(CheckerContext &C,
const CallExpr *CE,
- bool isBounded = false,
- bool ignoreCase = false) const;
+ bool IsBounded = false,
+ bool IgnoreCase = false) const;
void evalStrsep(CheckerContext &C, const CallExpr *CE) const;
@@ -292,9 +290,9 @@ ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C,
SmallString<80> buf;
llvm::raw_svector_ostream OS(buf);
assert(CurrentFunctionDescription);
- OS << "Null pointer argument in call to " << CurrentFunctionDescription
- << ' ' << IdxOfArg << llvm::getOrdinalSuffix(IdxOfArg)
- << " parameter";
+ OS << "Null pointer passed as " << IdxOfArg
+ << llvm::getOrdinalSuffix(IdxOfArg) << " argument to "
+ << CurrentFunctionDescription;
emitNullArgBug(C, stateNull, S, OS.str());
}
@@ -1008,12 +1006,9 @@ ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C,
bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
const MemRegion *MR) {
- const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(MR);
-
switch (MR->getKind()) {
case MemRegion::FunctionCodeRegionKind: {
- const NamedDecl *FD = cast<FunctionCodeRegion>(MR)->getDecl();
- if (FD)
+ if (const auto *FD = cast<FunctionCodeRegion>(MR)->getDecl())
os << "the address of the function '" << *FD << '\'';
else
os << "the address of a function";
@@ -1027,16 +1022,20 @@ bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
return true;
case MemRegion::CXXThisRegionKind:
case MemRegion::CXXTempObjectRegionKind:
- os << "a C++ temp object of type " << TVR->getValueType().getAsString();
+ os << "a C++ temp object of type "
+ << cast<TypedValueRegion>(MR)->getValueType().getAsString();
return true;
case MemRegion::VarRegionKind:
- os << "a variable of type" << TVR->getValueType().getAsString();
+ os << "a variable of type"
+ << cast<TypedValueRegion>(MR)->getValueType().getAsString();
return true;
case MemRegion::FieldRegionKind:
- os << "a field of type " << TVR->getValueType().getAsString();
+ os << "a field of type "
+ << cast<TypedValueRegion>(MR)->getValueType().getAsString();
return true;
case MemRegion::ObjCIvarRegionKind:
- os << "an instance variable of type " << TVR->getValueType().getAsString();
+ os << "an instance variable of type "
+ << cast<TypedValueRegion>(MR)->getValueType().getAsString();
return true;
default:
return false;
@@ -1315,9 +1314,9 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
ProgramStateRef StSameBuf, StNotSameBuf;
std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
- // If the two arguments might be the same buffer, we know the result is 0,
+ // If the two arguments are the same buffer, we know the result is 0,
// and we only need to check one size.
- if (StSameBuf) {
+ if (StSameBuf && !StNotSameBuf) {
state = StSameBuf;
state = CheckBufferAccess(C, state, Size, Left);
if (state) {
@@ -1325,20 +1324,19 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
svalBuilder.makeZeroVal(CE->getType()));
C.addTransition(state);
}
+ return;
}
- // If the two arguments might be different buffers, we have to check the
- // size of both of them.
- if (StNotSameBuf) {
- state = StNotSameBuf;
- state = CheckBufferAccess(C, state, Size, Left, Right);
- if (state) {
- // The return value is the comparison result, which we don't know.
- SVal CmpV = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx,
- C.blockCount());
- state = state->BindExpr(CE, LCtx, CmpV);
- C.addTransition(state);
- }
+ // If the two arguments might be different buffers, we have to check
+ // the size of both of them.
+ assert(StNotSameBuf);
+ state = CheckBufferAccess(C, state, Size, Left, Right);
+ if (state) {
+ // The return value is the comparison result, which we don't know.
+ SVal CmpV =
+ svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount());
+ state = state->BindExpr(CE, LCtx, CmpV);
+ C.addTransition(state);
}
}
}
@@ -1477,69 +1475,71 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) const {
// char *strcpy(char *restrict dst, const char *restrict src);
evalStrcpyCommon(C, CE,
- /* returnEnd = */ false,
- /* isBounded = */ false,
- /* isAppending = */ false);
+ /* ReturnEnd = */ false,
+ /* IsBounded = */ false,
+ /* appendK = */ ConcatFnKind::none);
}
void CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) const {
// char *strncpy(char *restrict dst, const char *restrict src, size_t n);
evalStrcpyCommon(C, CE,
- /* returnEnd = */ false,
- /* isBounded = */ true,
- /* isAppending = */ false);
+ /* ReturnEnd = */ false,
+ /* IsBounded = */ true,
+ /* appendK = */ ConcatFnKind::none);
}
void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) const {
// char *stpcpy(char *restrict dst, const char *restrict src);
evalStrcpyCommon(C, CE,
- /* returnEnd = */ true,
- /* isBounded = */ false,
- /* isAppending = */ false);
+ /* ReturnEnd = */ true,
+ /* IsBounded = */ false,
+ /* appendK = */ ConcatFnKind::none);
}
void CStringChecker::evalStrlcpy(CheckerContext &C, const CallExpr *CE) const {
- // char *strlcpy(char *dst, const char *src, size_t n);
+ // size_t strlcpy(char *dest, const char *src, size_t size);
evalStrcpyCommon(C, CE,
- /* returnEnd = */ true,
- /* isBounded = */ true,
- /* isAppending = */ false,
+ /* ReturnEnd = */ true,
+ /* IsBounded = */ true,
+ /* appendK = */ ConcatFnKind::none,
/* returnPtr = */ false);
}
void CStringChecker::evalStrcat(CheckerContext &C, const CallExpr *CE) const {
- //char *strcat(char *restrict s1, const char *restrict s2);
+ // char *strcat(char *restrict s1, const char *restrict s2);
evalStrcpyCommon(C, CE,
- /* returnEnd = */ false,
- /* isBounded = */ false,
- /* isAppending = */ true);
+ /* ReturnEnd = */ false,
+ /* IsBounded = */ false,
+ /* appendK = */ ConcatFnKind::strcat);
}
void CStringChecker::evalStrncat(CheckerContext &C, const CallExpr *CE) const {
//char *strncat(char *restrict s1, const char *restrict s2, size_t n);
evalStrcpyCommon(C, CE,
- /* returnEnd = */ false,
- /* isBounded = */ true,
- /* isAppending = */ true);
+ /* ReturnEnd = */ false,
+ /* IsBounded = */ true,
+ /* appendK = */ ConcatFnKind::strcat);
}
void CStringChecker::evalStrlcat(CheckerContext &C, const CallExpr *CE) const {
- // FIXME: strlcat() uses a different rule for bound checking, i.e. 'n' means
- // a different thing as compared to strncat(). This currently causes
- // false positives in the alpha string bound checker.
-
- //char *strlcat(char *s1, const char *s2, size_t n);
+ // size_t strlcat(char *dst, const char *src, size_t size);
+ // It will append at most size - strlen(dst) - 1 bytes,
+ // NULL-terminating the result.
evalStrcpyCommon(C, CE,
- /* returnEnd = */ false,
- /* isBounded = */ true,
- /* isAppending = */ true,
+ /* ReturnEnd = */ false,
+ /* IsBounded = */ true,
+ /* appendK = */ ConcatFnKind::strlcat,
/* returnPtr = */ false);
}
void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
- bool returnEnd, bool isBounded,
- bool isAppending, bool returnPtr) const {
- CurrentFunctionDescription = "string copy function";
+ bool ReturnEnd, bool IsBounded,
+ ConcatFnKind appendK,
+ bool returnPtr) const {
+ if (appendK == ConcatFnKind::none)
+ CurrentFunctionDescription = "string copy function";
+ else
+ CurrentFunctionDescription = "string concatenation function";
ProgramStateRef state = C.getState();
const LocationContext *LCtx = C.getLocationContext();
@@ -1560,6 +1560,11 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// Get the string length of the source.
SVal strLength = getCStringLength(C, state, srcExpr, srcVal);
+ Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>();
+
+ // Get the string length of the destination buffer.
+ SVal dstStrLength = getCStringLength(C, state, Dst, DstVal);
+ Optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>();
// If the source isn't a valid C string, give up.
if (strLength.isUndef())
@@ -1576,13 +1581,14 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
SVal maxLastElementIndex = UnknownVal();
const char *boundWarning = nullptr;
- state = CheckOverlap(C, state, isBounded ? CE->getArg(2) : CE->getArg(1), Dst, srcExpr);
+ state = CheckOverlap(C, state, IsBounded ? CE->getArg(2) : CE->getArg(1), Dst,
+ srcExpr);
if (!state)
return;
// If the function is strncpy, strncat, etc... it is bounded.
- if (isBounded) {
+ if (IsBounded) {
// Get the max number of characters to copy.
const Expr *lenExpr = CE->getArg(2);
SVal lenVal = state->getSVal(lenExpr, LCtx);
@@ -1590,57 +1596,100 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// Protect against misdeclared strncpy().
lenVal = svalBuilder.evalCast(lenVal, sizeTy, lenExpr->getType());
- Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>();
Optional<NonLoc> lenValNL = lenVal.getAs<NonLoc>();
// If we know both values, we might be able to figure out how much
// we're copying.
if (strLengthNL && lenValNL) {
- ProgramStateRef stateSourceTooLong, stateSourceNotTooLong;
+ switch (appendK) {
+ case ConcatFnKind::none:
+ case ConcatFnKind::strcat: {
+ ProgramStateRef stateSourceTooLong, stateSourceNotTooLong;
+ // Check if the max number to copy is less than the length of the src.
+ // If the bound is equal to the source length, strncpy won't null-
+ // terminate the result!
+ std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
+ svalBuilder
+ .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
+ .castAs<DefinedOrUnknownSVal>());
- // Check if the max number to copy is less than the length of the src.
- // If the bound is equal to the source length, strncpy won't null-
- // terminate the result!
- std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
- svalBuilder.evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
- .castAs<DefinedOrUnknownSVal>());
+ if (stateSourceTooLong && !stateSourceNotTooLong) {
+ // Max number to copy is less than the length of the src, so the
+ // actual strLength copied is the max number arg.
+ state = stateSourceTooLong;
+ amountCopied = lenVal;
+
+ } else if (!stateSourceTooLong && stateSourceNotTooLong) {
+ // The source buffer entirely fits in the bound.
+ state = stateSourceNotTooLong;
+ amountCopied = strLength;
+ }
+ break;
+ }
+ case ConcatFnKind::strlcat:
+ if (!dstStrLengthNL)
+ return;
- if (stateSourceTooLong && !stateSourceNotTooLong) {
- // Max number to copy is less than the length of the src, so the actual
- // strLength copied is the max number arg.
- state = stateSourceTooLong;
- amountCopied = lenVal;
+ // amountCopied = min (size - dstLen - 1 , srcLen)
+ SVal freeSpace = svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL,
+ *dstStrLengthNL, sizeTy);
+ if (!freeSpace.getAs<NonLoc>())
+ return;
+ freeSpace =
+ svalBuilder.evalBinOp(state, BO_Sub, freeSpace,
+ svalBuilder.makeIntVal(1, sizeTy), sizeTy);
+ Optional<NonLoc> freeSpaceNL = freeSpace.getAs<NonLoc>();
- } else if (!stateSourceTooLong && stateSourceNotTooLong) {
- // The source buffer entirely fits in the bound.
- state = stateSourceNotTooLong;
- amountCopied = strLength;
+ // While unlikely, it is possible that the subtraction is
+ // too complex to compute, let's check whether it succeeded.
+ if (!freeSpaceNL)
+ return;
+ SVal hasEnoughSpace = svalBuilder.evalBinOpNN(
+ state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy);
+
+ ProgramStateRef TrueState, FalseState;
+ std::tie(TrueState, FalseState) =
+ state->assume(hasEnoughSpace.castAs<DefinedOrUnknownSVal>());
+
+ // srcStrLength <= size - dstStrLength -1
+ if (TrueState && !FalseState) {
+ amountCopied = strLength;
+ }
+
+ // srcStrLength > size - dstStrLength -1
+ if (!TrueState && FalseState) {
+ amountCopied = freeSpace;
+ }
+
+ if (TrueState && FalseState)
+ amountCopied = UnknownVal();
+ break;
}
}
-
// We still want to know if the bound is known to be too large.
if (lenValNL) {
- if (isAppending) {
+ switch (appendK) {
+ case ConcatFnKind::strcat:
// For strncat, the check is strlen(dst) + lenVal < sizeof(dst)
// Get the string length of the destination. If the destination is
// memory that can't have a string length, we shouldn't be copying
// into it anyway.
- SVal dstStrLength = getCStringLength(C, state, Dst, DstVal);
if (dstStrLength.isUndef())
return;
- if (Optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>()) {
- maxLastElementIndex = svalBuilder.evalBinOpNN(state, BO_Add,
- *lenValNL,
- *dstStrLengthNL,
- sizeTy);
+ if (dstStrLengthNL) {
+ maxLastElementIndex = svalBuilder.evalBinOpNN(
+ state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy);
+
boundWarning = "Size argument is greater than the free space in the "
"destination buffer";
}
-
- } else {
- // For strncpy, this is just checking that lenVal <= sizeof(dst)
+ break;
+ case ConcatFnKind::none:
+ case ConcatFnKind::strlcat:
+ // For strncpy and strlcat, this is just checking
+ // that lenVal <= sizeof(dst).
// (Yes, strncpy and strncat differ in how they treat termination.
// strncat ALWAYS terminates, but strncpy doesn't.)
@@ -1649,14 +1698,22 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// as the last element accessed, so n == 0 is problematic.
ProgramStateRef StateZeroSize, StateNonZeroSize;
std::tie(StateZeroSize, StateNonZeroSize) =
- assumeZero(C, state, *lenValNL, sizeTy);
+ assumeZero(C, state, *lenValNL, sizeTy);
// If the size is known to be zero, we're done.
if (StateZeroSize && !StateNonZeroSize) {
if (returnPtr) {
StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, DstVal);
} else {
- StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, *lenValNL);
+ if (appendK == ConcatFnKind::none) {
+ // strlcpy returns strlen(src)
+ StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, strLength);
+ } else {
+ // strlcat returns strlen(src) + strlen(dst)
+ SVal retSize = svalBuilder.evalBinOp(
+ state, BO_Add, strLength, dstStrLength, sizeTy);
+ StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, retSize);
+ }
}
C.addTransition(StateZeroSize);
return;
@@ -1666,50 +1723,13 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// We don't record the non-zero assumption here because we can't
// be sure. We won't warn on a possible zero.
NonLoc one = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>();
- maxLastElementIndex = svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL,
- one, sizeTy);
+ maxLastElementIndex =
+ svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy);
boundWarning = "Size argument is greater than the length of the "
"destination buffer";
+ break;
}
}
-
- // If we couldn't pin down the copy length, at least bound it.
- // FIXME: We should actually run this code path for append as well, but
- // right now it creates problems with constraints (since we can end up
- // trying to pass constraints from symbol to symbol).
- if (amountCopied.isUnknown() && !isAppending) {
- // Try to get a "hypothetical" string length symbol, which we can later
- // set as a real value if that turns out to be the case.
- amountCopied = getCStringLength(C, state, lenExpr, srcVal, true);
- assert(!amountCopied.isUndef());
-
- if (Optional<NonLoc> amountCopiedNL = amountCopied.getAs<NonLoc>()) {
- if (lenValNL) {
- // amountCopied <= lenVal
- SVal copiedLessThanBound = svalBuilder.evalBinOpNN(state, BO_LE,
- *amountCopiedNL,
- *lenValNL,
- cmpTy);
- state = state->assume(
- copiedLessThanBound.castAs<DefinedOrUnknownSVal>(), true);
- if (!state)
- return;
- }
-
- if (strLengthNL) {
- // amountCopied <= strlen(source)
- SVal copiedLessThanSrc = svalBuilder.evalBinOpNN(state, BO_LE,
- *amountCopiedNL,
- *strLengthNL,
- cmpTy);
- state = state->assume(
- copiedLessThanSrc.castAs<DefinedOrUnknownSVal>(), true);
- if (!state)
- return;
- }
- }
- }
-
} else {
// The function isn't bounded. The amount copied should match the length
// of the source buffer.
@@ -1722,28 +1742,37 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// buffer. (It may not actually be the strlen if the destination buffer
// is not terminated.)
SVal finalStrLength = UnknownVal();
+ SVal strlRetVal = UnknownVal();
+
+ if (appendK == ConcatFnKind::none && !returnPtr) {
+ // strlcpy returns the sizeof(src)
+ strlRetVal = strLength;
+ }
// If this is an appending function (strcat, strncat...) then set the
// string length to strlen(src) + strlen(dst) since the buffer will
// ultimately contain both.
- if (isAppending) {
+ if (appendK != ConcatFnKind::none) {
// Get the string length of the destination. If the destination is memory
// that can't have a string length, we shouldn't be copying into it anyway.
- SVal dstStrLength = getCStringLength(C, state, Dst, DstVal);
if (dstStrLength.isUndef())
return;
- Optional<NonLoc> srcStrLengthNL = amountCopied.getAs<NonLoc>();
- Optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>();
+ if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) {
+ strlRetVal = svalBuilder.evalBinOpNN(state, BO_Add, *strLengthNL,
+ *dstStrLengthNL, sizeTy);
+ }
+
+ Optional<NonLoc> amountCopiedNL = amountCopied.getAs<NonLoc>();
// If we know both string lengths, we might know the final string length.
- if (srcStrLengthNL && dstStrLengthNL) {
+ if (amountCopiedNL && dstStrLengthNL) {
// Make sure the two lengths together don't overflow a size_t.
- state = checkAdditionOverflow(C, state, *srcStrLengthNL, *dstStrLengthNL);
+ state = checkAdditionOverflow(C, state, *amountCopiedNL, *dstStrLengthNL);
if (!state)
return;
- finalStrLength = svalBuilder.evalBinOpNN(state, BO_Add, *srcStrLengthNL,
+ finalStrLength = svalBuilder.evalBinOpNN(state, BO_Add, *amountCopiedNL,
*dstStrLengthNL, sizeTy);
}
@@ -1756,19 +1785,19 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
assert(!finalStrLength.isUndef());
if (Optional<NonLoc> finalStrLengthNL = finalStrLength.getAs<NonLoc>()) {
- if (srcStrLengthNL) {
+ if (amountCopiedNL && appendK == ConcatFnKind::none) {
+ // we overwrite dst string with the src
// finalStrLength >= srcStrLength
- SVal sourceInResult = svalBuilder.evalBinOpNN(state, BO_GE,
- *finalStrLengthNL,
- *srcStrLengthNL,
- cmpTy);
+ SVal sourceInResult = svalBuilder.evalBinOpNN(
+ state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy);
state = state->assume(sourceInResult.castAs<DefinedOrUnknownSVal>(),
true);
if (!state)
return;
}
- if (dstStrLengthNL) {
+ if (dstStrLengthNL && appendK != ConcatFnKind::none) {
+ // we extend the dst string with the src
// finalStrLength >= dstStrLength
SVal destInResult = svalBuilder.evalBinOpNN(state, BO_GE,
*finalStrLengthNL,
@@ -1793,9 +1822,13 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
if (returnPtr) {
// The final result of the function will either be a pointer past the last
// copied element, or a pointer to the start of the destination buffer.
- Result = (returnEnd ? UnknownVal() : DstVal);
+ Result = (ReturnEnd ? UnknownVal() : DstVal);
} else {
- Result = finalStrLength;
+ if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none)
+ //strlcpy, strlcat
+ Result = strlRetVal;
+ else
+ Result = finalStrLength;
}
assert(state);
@@ -1834,7 +1867,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
}
// If this is a stpcpy-style copy, the last element is the return value.
- if (returnPtr && returnEnd)
+ if (returnPtr && ReturnEnd)
Result = lastElement;
}
@@ -1854,7 +1887,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
nullptr);
// Set the C string length of the destination, if we know it.
- if (isBounded && !isAppending) {
+ if (IsBounded && (appendK == ConcatFnKind::none)) {
// strncpy is annoying in that it doesn't guarantee to null-terminate
// the result string. If the original string didn't fit entirely inside
// the bound (including the null-terminator), we don't know how long the
@@ -1870,7 +1903,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
if (returnPtr) {
// If this is a stpcpy-style copy, but we were unable to check for a buffer
// overflow, we still need a result. Conjure a return value.
- if (returnEnd && Result.isUnknown()) {
+ if (ReturnEnd && Result.isUnknown()) {
Result = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount());
}
}
@@ -1881,28 +1914,28 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
void CStringChecker::evalStrcmp(CheckerContext &C, const CallExpr *CE) const {
//int strcmp(const char *s1, const char *s2);
- evalStrcmpCommon(C, CE, /* isBounded = */ false, /* ignoreCase = */ false);
+ evalStrcmpCommon(C, CE, /* IsBounded = */ false, /* IgnoreCase = */ false);
}
void CStringChecker::evalStrncmp(CheckerContext &C, const CallExpr *CE) const {
//int strncmp(const char *s1, const char *s2, size_t n);
- evalStrcmpCommon(C, CE, /* isBounded = */ true, /* ignoreCase = */ false);
+ evalStrcmpCommon(C, CE, /* IsBounded = */ true, /* IgnoreCase = */ false);
}
void CStringChecker::evalStrcasecmp(CheckerContext &C,
const CallExpr *CE) const {
//int strcasecmp(const char *s1, const char *s2);
- evalStrcmpCommon(C, CE, /* isBounded = */ false, /* ignoreCase = */ true);
+ evalStrcmpCommon(C, CE, /* IsBounded = */ false, /* IgnoreCase = */ true);
}
void CStringChecker::evalStrncasecmp(CheckerContext &C,
const CallExpr *CE) const {
//int strncasecmp(const char *s1, const char *s2, size_t n);
- evalStrcmpCommon(C, CE, /* isBounded = */ true, /* ignoreCase = */ true);
+ evalStrcmpCommon(C, CE, /* IsBounded = */ true, /* IgnoreCase = */ true);
}
void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
- bool isBounded, bool ignoreCase) const {
+ bool IsBounded, bool IgnoreCase) const {
CurrentFunctionDescription = "string comparison function";
ProgramStateRef state = C.getState();
const LocationContext *LCtx = C.getLocationContext();
@@ -1972,7 +2005,7 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
StringRef s1StrRef = s1StrLiteral->getString();
StringRef s2StrRef = s2StrLiteral->getString();
- if (isBounded) {
+ if (IsBounded) {
// Get the max number of characters to compare.
const Expr *lenExpr = CE->getArg(2);
SVal lenVal = state->getSVal(lenExpr, LCtx);
@@ -2000,7 +2033,7 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
s2StrRef = s2StrRef.substr(0, s2Term);
// Use StringRef's comparison methods to compute the actual result.
- int compareRes = ignoreCase ? s1StrRef.compare_lower(s2StrRef)
+ int compareRes = IgnoreCase ? s1StrRef.compare_lower(s2StrRef)
: s1StrRef.compare(s2StrRef);
// The strcmp function returns an integer greater than, equal to, or less
@@ -2180,7 +2213,7 @@ void CStringChecker::evalBzero(CheckerContext &C, const CallExpr *CE) const {
SVal Zero = C.getSValBuilder().makeZeroVal(C.getASTContext().IntTy);
ProgramStateRef State = C.getState();
-
+
// See if the size argument is zero.
SVal SizeVal = C.getSVal(Size);
QualType SizeTy = Size->getType();
diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp
new file mode 100644
index 000000000000..48fee4a0ffb7
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp
@@ -0,0 +1,121 @@
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class PlacementNewChecker : public Checker<check::PreStmt<CXXNewExpr>> {
+public:
+ void checkPreStmt(const CXXNewExpr *NE, CheckerContext &C) const;
+
+private:
+ // Returns the size of the target in a placement new expression.
+ // E.g. in "new (&s) long" it returns the size of `long`.
+ SVal getExtentSizeOfNewTarget(const CXXNewExpr *NE, ProgramStateRef State,
+ CheckerContext &C) const;
+ // Returns the size of the place in a placement new expression.
+ // E.g. in "new (&s) long" it returns the size of `s`.
+ SVal getExtentSizeOfPlace(const Expr *NE, ProgramStateRef State,
+ CheckerContext &C) const;
+ BugType BT{this, "Insufficient storage for placement new",
+ categories::MemoryError};
+};
+} // namespace
+
+SVal PlacementNewChecker::getExtentSizeOfPlace(const Expr *Place,
+ ProgramStateRef State,
+ CheckerContext &C) const {
+ const MemRegion *MRegion = C.getSVal(Place).getAsRegion();
+ if (!MRegion)
+ return UnknownVal();
+ RegionOffset Offset = MRegion->getAsOffset();
+ if (Offset.hasSymbolicOffset())
+ return UnknownVal();
+ const MemRegion *BaseRegion = MRegion->getBaseRegion();
+ if (!BaseRegion)
+ return UnknownVal();
+
+ SValBuilder &SvalBuilder = C.getSValBuilder();
+ NonLoc OffsetInBytes = SvalBuilder.makeArrayIndex(
+ Offset.getOffset() / C.getASTContext().getCharWidth());
+ DefinedOrUnknownSVal ExtentInBytes =
+ BaseRegion->castAs<SubRegion>()->getExtent(SvalBuilder);
+
+ return SvalBuilder.evalBinOp(State, BinaryOperator::Opcode::BO_Sub,
+ ExtentInBytes, OffsetInBytes,
+ SvalBuilder.getArrayIndexType());
+}
+
+SVal PlacementNewChecker::getExtentSizeOfNewTarget(const CXXNewExpr *NE,
+ ProgramStateRef State,
+ CheckerContext &C) const {
+ SValBuilder &SvalBuilder = C.getSValBuilder();
+ QualType ElementType = NE->getAllocatedType();
+ ASTContext &AstContext = C.getASTContext();
+ CharUnits TypeSize = AstContext.getTypeSizeInChars(ElementType);
+ if (NE->isArray()) {
+ const Expr *SizeExpr = *NE->getArraySize();
+ SVal ElementCount = C.getSVal(SizeExpr);
+ if (auto ElementCountNL = ElementCount.getAs<NonLoc>()) {
+ // size in Bytes = ElementCountNL * TypeSize
+ return SvalBuilder.evalBinOp(
+ State, BO_Mul, *ElementCountNL,
+ SvalBuilder.makeArrayIndex(TypeSize.getQuantity()),
+ SvalBuilder.getArrayIndexType());
+ }
+ } else {
+ // Create a concrete int whose size in bits and signedness is equal to
+ // ArrayIndexType.
+ llvm::APInt I(AstContext.getTypeSizeInChars(SvalBuilder.getArrayIndexType())
+ .getQuantity() *
+ C.getASTContext().getCharWidth(),
+ TypeSize.getQuantity());
+ return SvalBuilder.makeArrayIndex(I.getZExtValue());
+ }
+ return UnknownVal();
+}
+
+void PlacementNewChecker::checkPreStmt(const CXXNewExpr *NE,
+ CheckerContext &C) const {
+ // Check only the default placement new.
+ if (!NE->getOperatorNew()->isReservedGlobalPlacementOperator())
+ return;
+ if (NE->getNumPlacementArgs() == 0)
+ return;
+
+ ProgramStateRef State = C.getState();
+ SVal SizeOfTarget = getExtentSizeOfNewTarget(NE, State, C);
+ const Expr *Place = NE->getPlacementArg(0);
+ SVal SizeOfPlace = getExtentSizeOfPlace(Place, State, C);
+ const auto SizeOfTargetCI = SizeOfTarget.getAs<nonloc::ConcreteInt>();
+ if (!SizeOfTargetCI)
+ return;
+ const auto SizeOfPlaceCI = SizeOfPlace.getAs<nonloc::ConcreteInt>();
+ if (!SizeOfPlaceCI)
+ return;
+
+ if (SizeOfPlaceCI->getValue() < SizeOfTargetCI->getValue()) {
+ if (ExplodedNode *N = C.generateErrorNode(State)) {
+ std::string Msg =
+ llvm::formatv("Storage provided to placement new is only {0} bytes, "
+ "whereas the allocated type requires {1} bytes",
+ SizeOfPlaceCI->getValue(), SizeOfTargetCI->getValue());
+
+ auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
+ bugreporter::trackExpressionValue(N, Place, *R);
+ C.emitReport(std::move(R));
+ return;
+ }
+ }
+}
+
+void ento::registerPlacementNewChecker(CheckerManager &mgr) {
+ mgr.registerChecker<PlacementNewChecker>();
+}
+
+bool ento::shouldRegisterPlacementNewChecker(const LangOptions &LO) {
+ return true;
+}
diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
index 260a2896e78c..d9ffa562c0aa 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
@@ -49,6 +49,7 @@ struct ChecksFilter {
DefaultBool check_vfork;
DefaultBool check_FloatLoopCounter;
DefaultBool check_UncheckedReturn;
+ DefaultBool check_decodeValueOfObjCType;
CheckerNameRef checkName_bcmp;
CheckerNameRef checkName_bcopy;
@@ -63,6 +64,7 @@ struct ChecksFilter {
CheckerNameRef checkName_vfork;
CheckerNameRef checkName_FloatLoopCounter;
CheckerNameRef checkName_UncheckedReturn;
+ CheckerNameRef checkName_decodeValueOfObjCType;
};
class WalkAST : public StmtVisitor<WalkAST> {
@@ -83,6 +85,7 @@ public:
// Statement visitor methods.
void VisitCallExpr(CallExpr *CE);
+ void VisitObjCMessageExpr(ObjCMessageExpr *CE);
void VisitForStmt(ForStmt *S);
void VisitCompoundStmt (CompoundStmt *S);
void VisitStmt(Stmt *S) { VisitChildren(S); }
@@ -93,6 +96,7 @@ public:
bool checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD);
typedef void (WalkAST::*FnCheck)(const CallExpr *, const FunctionDecl *);
+ typedef void (WalkAST::*MsgCheck)(const ObjCMessageExpr *);
// Checker-specific methods.
void checkLoopConditionForFloat(const ForStmt *FS);
@@ -110,6 +114,7 @@ public:
void checkCall_rand(const CallExpr *CE, const FunctionDecl *FD);
void checkCall_random(const CallExpr *CE, const FunctionDecl *FD);
void checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD);
+ void checkMsg_decodeValueOfObjCType(const ObjCMessageExpr *ME);
void checkUncheckedReturnValue(CallExpr *CE);
};
} // end anonymous namespace
@@ -182,6 +187,20 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
VisitChildren(CE);
}
+void WalkAST::VisitObjCMessageExpr(ObjCMessageExpr *ME) {
+ MsgCheck evalFunction =
+ llvm::StringSwitch<MsgCheck>(ME->getSelector().getAsString())
+ .Case("decodeValueOfObjCType:at:",
+ &WalkAST::checkMsg_decodeValueOfObjCType)
+ .Default(nullptr);
+
+ if (evalFunction)
+ (this->*evalFunction)(ME);
+
+ // Recurse and check children.
+ VisitChildren(ME);
+}
+
void WalkAST::VisitCompoundStmt(CompoundStmt *S) {
for (Stmt *Child : S->children())
if (Child) {
@@ -924,6 +943,54 @@ void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) {
}
//===----------------------------------------------------------------------===//
+// Check: '-decodeValueOfObjCType:at:' should not be used.
+// It is deprecated in favor of '-decodeValueOfObjCType:at:size:' due to
+// likelihood of buffer overflows.
+//===----------------------------------------------------------------------===//
+
+void WalkAST::checkMsg_decodeValueOfObjCType(const ObjCMessageExpr *ME) {
+ if (!filter.check_decodeValueOfObjCType)
+ return;
+
+ // Check availability of the secure alternative:
+ // iOS 11+, macOS 10.13+, tvOS 11+, and watchOS 4.0+
+ // FIXME: We probably shouldn't register the check if it's not available.
+ const TargetInfo &TI = AC->getASTContext().getTargetInfo();
+ const llvm::Triple &T = TI.getTriple();
+ const VersionTuple &VT = TI.getPlatformMinVersion();
+ switch (T.getOS()) {
+ case llvm::Triple::IOS:
+ if (VT < VersionTuple(11, 0))
+ return;
+ break;
+ case llvm::Triple::MacOSX:
+ if (VT < VersionTuple(10, 13))
+ return;
+ break;
+ case llvm::Triple::WatchOS:
+ if (VT < VersionTuple(4, 0))
+ return;
+ break;
+ case llvm::Triple::TvOS:
+ if (VT < VersionTuple(11, 0))
+ return;
+ break;
+ default:
+ return;
+ }
+
+ PathDiagnosticLocation MELoc =
+ PathDiagnosticLocation::createBegin(ME, BR.getSourceManager(), AC);
+ BR.EmitBasicReport(
+ AC->getDecl(), filter.checkName_decodeValueOfObjCType,
+ "Potential buffer overflow in '-decodeValueOfObjCType:at:'", "Security",
+ "Deprecated method '-decodeValueOfObjCType:at:' is insecure "
+ "as it can lead to potential buffer overflows. Use the safer "
+ "'-decodeValueOfObjCType:at:size:' method.",
+ MELoc, ME->getSourceRange());
+}
+
+//===----------------------------------------------------------------------===//
// Check: Should check whether privileges are dropped successfully.
// Originally: <rdar://problem/6337132>
//===----------------------------------------------------------------------===//
@@ -1035,3 +1102,4 @@ REGISTER_CHECKER(vfork)
REGISTER_CHECKER(FloatLoopCounter)
REGISTER_CHECKER(UncheckedReturn)
REGISTER_CHECKER(DeprecatedOrUnsafeBufferHandling)
+REGISTER_CHECKER(decodeValueOfObjCType)
diff --git a/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp
new file mode 100644
index 000000000000..4717fef96341
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp
@@ -0,0 +1,196 @@
+//===-- DebugIteratorModeling.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
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines a checker for debugging iterator modeling.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+#include "Iterator.h"
+
+using namespace clang;
+using namespace ento;
+using namespace iterator;
+
+namespace {
+
+class DebugIteratorModeling
+ : public Checker<eval::Call> {
+
+ std::unique_ptr<BugType> DebugMsgBugType;
+
+ template <typename Getter>
+ void analyzerContainerDataField(const CallExpr *CE, CheckerContext &C,
+ Getter get) const;
+ void analyzerContainerBegin(const CallExpr *CE, CheckerContext &C) const;
+ void analyzerContainerEnd(const CallExpr *CE, CheckerContext &C) const;
+ template <typename Getter>
+ void analyzerIteratorDataField(const CallExpr *CE, CheckerContext &C,
+ Getter get, SVal Default) const;
+ void analyzerIteratorPosition(const CallExpr *CE, CheckerContext &C) const;
+ void analyzerIteratorContainer(const CallExpr *CE, CheckerContext &C) const;
+ void analyzerIteratorValidity(const CallExpr *CE, CheckerContext &C) const;
+ ExplodedNode *reportDebugMsg(llvm::StringRef Msg, CheckerContext &C) const;
+
+ typedef void (DebugIteratorModeling::*FnCheck)(const CallExpr *,
+ CheckerContext &) const;
+
+ CallDescriptionMap<FnCheck> Callbacks = {
+ {{0, "clang_analyzer_container_begin", 1},
+ &DebugIteratorModeling::analyzerContainerBegin},
+ {{0, "clang_analyzer_container_end", 1},
+ &DebugIteratorModeling::analyzerContainerEnd},
+ {{0, "clang_analyzer_iterator_position", 1},
+ &DebugIteratorModeling::analyzerIteratorPosition},
+ {{0, "clang_analyzer_iterator_container", 1},
+ &DebugIteratorModeling::analyzerIteratorContainer},
+ {{0, "clang_analyzer_iterator_validity", 1},
+ &DebugIteratorModeling::analyzerIteratorValidity},
+ };
+
+public:
+ DebugIteratorModeling();
+
+ bool evalCall(const CallEvent &Call, CheckerContext &C) const;
+};
+
+} //namespace
+
+DebugIteratorModeling::DebugIteratorModeling() {
+ DebugMsgBugType.reset(
+ new BugType(this, "Checking analyzer assumptions", "debug",
+ /*SuppressOnSink=*/true));
+}
+
+bool DebugIteratorModeling::evalCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
+ if (!CE)
+ return false;
+
+ const FnCheck *Handler = Callbacks.lookup(Call);
+ if (!Handler)
+ return false;
+
+ (this->**Handler)(CE, C);
+ return true;
+}
+
+template <typename Getter>
+void DebugIteratorModeling::analyzerContainerDataField(const CallExpr *CE,
+ CheckerContext &C,
+ Getter get) const {
+ if (CE->getNumArgs() == 0) {
+ reportDebugMsg("Missing container argument", C);
+ return;
+ }
+
+ auto State = C.getState();
+ const MemRegion *Cont = C.getSVal(CE->getArg(0)).getAsRegion();
+ if (Cont) {
+ const auto *Data = getContainerData(State, Cont);
+ if (Data) {
+ SymbolRef Field = get(Data);
+ if (Field) {
+ State = State->BindExpr(CE, C.getLocationContext(),
+ nonloc::SymbolVal(Field));
+ C.addTransition(State);
+ return;
+ }
+ }
+ }
+
+ auto &BVF = C.getSValBuilder().getBasicValueFactory();
+ State = State->BindExpr(CE, C.getLocationContext(),
+ nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
+}
+
+void DebugIteratorModeling::analyzerContainerBegin(const CallExpr *CE,
+ CheckerContext &C) const {
+ analyzerContainerDataField(CE, C, [](const ContainerData *D) {
+ return D->getBegin();
+ });
+}
+
+void DebugIteratorModeling::analyzerContainerEnd(const CallExpr *CE,
+ CheckerContext &C) const {
+ analyzerContainerDataField(CE, C, [](const ContainerData *D) {
+ return D->getEnd();
+ });
+}
+
+template <typename Getter>
+void DebugIteratorModeling::analyzerIteratorDataField(const CallExpr *CE,
+ CheckerContext &C,
+ Getter get,
+ SVal Default) const {
+ if (CE->getNumArgs() == 0) {
+ reportDebugMsg("Missing iterator argument", C);
+ return;
+ }
+
+ auto State = C.getState();
+ SVal V = C.getSVal(CE->getArg(0));
+ const auto *Pos = getIteratorPosition(State, V);
+ if (Pos) {
+ State = State->BindExpr(CE, C.getLocationContext(), get(Pos));
+ } else {
+ State = State->BindExpr(CE, C.getLocationContext(), Default);
+ }
+ C.addTransition(State);
+}
+
+void DebugIteratorModeling::analyzerIteratorPosition(const CallExpr *CE,
+ CheckerContext &C) const {
+ auto &BVF = C.getSValBuilder().getBasicValueFactory();
+ analyzerIteratorDataField(CE, C, [](const IteratorPosition *P) {
+ return nonloc::SymbolVal(P->getOffset());
+ }, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
+}
+
+void DebugIteratorModeling::analyzerIteratorContainer(const CallExpr *CE,
+ CheckerContext &C) const {
+ auto &BVF = C.getSValBuilder().getBasicValueFactory();
+ analyzerIteratorDataField(CE, C, [](const IteratorPosition *P) {
+ return loc::MemRegionVal(P->getContainer());
+ }, loc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
+}
+
+void DebugIteratorModeling::analyzerIteratorValidity(const CallExpr *CE,
+ CheckerContext &C) const {
+ auto &BVF = C.getSValBuilder().getBasicValueFactory();
+ analyzerIteratorDataField(CE, C, [&BVF](const IteratorPosition *P) {
+ return
+ nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get((P->isValid()))));
+ }, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
+}
+
+ExplodedNode *DebugIteratorModeling::reportDebugMsg(llvm::StringRef Msg,
+ CheckerContext &C) const {
+ ExplodedNode *N = C.generateNonFatalErrorNode();
+ if (!N)
+ return nullptr;
+
+ auto &BR = C.getBugReporter();
+ BR.emitReport(std::make_unique<PathSensitiveBugReport>(*DebugMsgBugType,
+ Msg, N));
+ return N;
+}
+
+void ento::registerDebugIteratorModeling(CheckerManager &mgr) {
+ mgr.registerChecker<DebugIteratorModeling>();
+}
+
+bool ento::shouldRegisterDebugIteratorModeling(const LangOptions &LO) {
+ return true;
+}
diff --git a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
index e3de0b4f4a7f..46100cd1dace 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
@@ -107,7 +107,7 @@ static const Expr *getDereferenceExpr(const Stmt *S, bool IsBind=false){
static bool suppressReport(const Expr *E) {
// Do not report dereferences on memory in non-default address spaces.
- return E->getType().getQualifiers().hasAddressSpace();
+ return E->getType().hasAddressSpace();
}
static bool isDeclRefExprToReference(const Expr *E) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp b/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
index 0058f3d3881f..0c46447e1985 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
@@ -144,6 +144,8 @@ void DirectIvarAssignment::checkASTDecl(const ObjCImplementationDecl *D,
continue;
const Stmt *Body = M->getBody();
+ if (M->isSynthesizedAccessorStub())
+ continue;
assert(Body);
MethodCrawler MC(IvarToPropMap, M->getCanonicalDecl(), InterD, BR, this,
diff --git a/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp
new file mode 100644
index 000000000000..3c04983df443
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp
@@ -0,0 +1,557 @@
+//=== FuchsiaHandleChecker.cpp - Find handle leaks/double closes -*- 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 checker checks if the handle of Fuchsia is properly used according to
+// following rules.
+// - If a handle is acquired, it should be released before execution
+// ends.
+// - If a handle is released, it should not be released again.
+// - If a handle is released, it should not be used for other purposes
+// such as I/O.
+//
+// In this checker, each tracked handle is associated with a state. When the
+// handle variable is passed to different function calls or syscalls, its state
+// changes. The state changes can be generally represented by following ASCII
+// Art:
+//
+//
+// +-+---------v-+ +------------+
+// acquire_func succeeded | | Escape | |
+// +-----------------> Allocated +---------> Escaped <--+
+// | | | | | |
+// | +-----+------++ +------------+ |
+// | | | |
+// | release_func | +--+ |
+// | | | handle +--------+ |
+// | | | dies | | |
+// | +----v-----+ +---------> Leaked | |
+// | | | |(REPORT)| |
+// +----------+--+ | Released | Escape +--------+ |
+// | | | +---------------------------+
+// | Not tracked <--+ +----+---+-+
+// | | | | | As argument by value
+// +------+------+ | release_func | +------+ in function call
+// | | | | or by reference in
+// | | | | use_func call
+// +---------+ +----v-----+ | +-----------+
+// acquire_func failed | Double | +-----> Use after |
+// | released | | released |
+// | (REPORT) | | (REPORT) |
+// +----------+ +-----------+
+//
+// acquire_func represents the functions or syscalls that may acquire a handle.
+// release_func represents the functions or syscalls that may release a handle.
+// use_func represents the functions or syscall that requires an open handle.
+//
+// If a tracked handle dies in "Released" or "Not Tracked" state, we assume it
+// is properly used. Otherwise a bug and will be reported.
+//
+// Note that, the analyzer does not always know for sure if a function failed
+// or succeeded. In those cases we use the state MaybeAllocated.
+// Thus, the diagramm above captures the intent, not implementation details.
+//
+// Due to the fact that the number of handle related syscalls in Fuchsia
+// is large, we adopt the annotation attributes to descript syscalls'
+// operations(acquire/release/use) on handles instead of hardcoding
+// everything in the checker.
+//
+// We use following annotation attributes for handle related syscalls or
+// functions:
+// 1. __attribute__((acquire_handle("Fuchsia"))) |handle will be acquired
+// 2. __attribute__((release_handle("Fuchsia"))) |handle will be released
+// 3. __attribute__((use_handle("Fuchsia"))) |handle will not transit to
+// escaped state, it also needs to be open.
+//
+// For example, an annotated syscall:
+// zx_status_t zx_channel_create(
+// uint32_t options,
+// zx_handle_t* out0 __attribute__((acquire_handle("Fuchsia"))) ,
+// zx_handle_t* out1 __attribute__((acquire_handle("Fuchsia"))));
+// denotes a syscall which will acquire two handles and save them to 'out0' and
+// 'out1' when succeeded.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/Attr.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Type.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+static const StringRef HandleTypeName = "zx_handle_t";
+static const StringRef ErrorTypeName = "zx_status_t";
+
+class HandleState {
+private:
+ enum class Kind { MaybeAllocated, Allocated, Released, Escaped } K;
+ SymbolRef ErrorSym;
+ HandleState(Kind K, SymbolRef ErrorSym) : K(K), ErrorSym(ErrorSym) {}
+
+public:
+ bool operator==(const HandleState &Other) const {
+ return K == Other.K && ErrorSym == Other.ErrorSym;
+ }
+ bool isAllocated() const { return K == Kind::Allocated; }
+ bool maybeAllocated() const { return K == Kind::MaybeAllocated; }
+ bool isReleased() const { return K == Kind::Released; }
+ bool isEscaped() const { return K == Kind::Escaped; }
+
+ static HandleState getMaybeAllocated(SymbolRef ErrorSym) {
+ return HandleState(Kind::MaybeAllocated, ErrorSym);
+ }
+ static HandleState getAllocated(ProgramStateRef State, HandleState S) {
+ assert(S.maybeAllocated());
+ assert(State->getConstraintManager()
+ .isNull(State, S.getErrorSym())
+ .isConstrained());
+ return HandleState(Kind::Allocated, nullptr);
+ }
+ static HandleState getReleased() {
+ return HandleState(Kind::Released, nullptr);
+ }
+ static HandleState getEscaped() {
+ return HandleState(Kind::Escaped, nullptr);
+ }
+
+ SymbolRef getErrorSym() const { return ErrorSym; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(static_cast<int>(K));
+ ID.AddPointer(ErrorSym);
+ }
+
+ LLVM_DUMP_METHOD void dump(raw_ostream &OS) const {
+ switch (K) {
+#define CASE(ID) \
+ case ID: \
+ OS << #ID; \
+ break;
+ CASE(Kind::MaybeAllocated)
+ CASE(Kind::Allocated)
+ CASE(Kind::Released)
+ CASE(Kind::Escaped)
+ }
+ }
+
+ LLVM_DUMP_METHOD void dump() const { dump(llvm::errs()); }
+};
+
+template <typename Attr> static bool hasFuchsiaAttr(const Decl *D) {
+ return D->hasAttr<Attr>() && D->getAttr<Attr>()->getHandleType() == "Fuchsia";
+}
+
+class FuchsiaHandleChecker
+ : public Checker<check::PostCall, check::PreCall, check::DeadSymbols,
+ check::PointerEscape, eval::Assume> {
+ BugType LeakBugType{this, "Fuchsia handle leak", "Fuchsia Handle Error",
+ /*SuppressOnSink=*/true};
+ BugType DoubleReleaseBugType{this, "Fuchsia handle double release",
+ "Fuchsia Handle Error"};
+ BugType UseAfterReleaseBugType{this, "Fuchsia handle use after release",
+ "Fuchsia Handle Error"};
+
+public:
+ void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+ void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
+ void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
+ ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond,
+ bool Assumption) const;
+ ProgramStateRef checkPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind) const;
+
+ ExplodedNode *reportLeaks(ArrayRef<SymbolRef> LeakedHandles,
+ CheckerContext &C, ExplodedNode *Pred) const;
+
+ void reportDoubleRelease(SymbolRef HandleSym, const SourceRange &Range,
+ CheckerContext &C) const;
+
+ void reportUseAfterFree(SymbolRef HandleSym, const SourceRange &Range,
+ CheckerContext &C) const;
+
+ void reportBug(SymbolRef Sym, ExplodedNode *ErrorNode, CheckerContext &C,
+ const SourceRange *Range, const BugType &Type,
+ StringRef Msg) const;
+
+ void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
+ const char *Sep) const override;
+};
+} // end anonymous namespace
+
+REGISTER_MAP_WITH_PROGRAMSTATE(HStateMap, SymbolRef, HandleState)
+
+static const ExplodedNode *getAcquireSite(const ExplodedNode *N, SymbolRef Sym,
+ CheckerContext &Ctx) {
+ ProgramStateRef State = N->getState();
+ // When bug type is handle leak, exploded node N does not have state info for
+ // leaking handle. Get the predecessor of N instead.
+ if (!State->get<HStateMap>(Sym))
+ N = N->getFirstPred();
+
+ const ExplodedNode *Pred = N;
+ while (N) {
+ State = N->getState();
+ if (!State->get<HStateMap>(Sym)) {
+ const HandleState *HState = Pred->getState()->get<HStateMap>(Sym);
+ if (HState && (HState->isAllocated() || HState->maybeAllocated()))
+ return N;
+ }
+ Pred = N;
+ N = N->getFirstPred();
+ }
+ return nullptr;
+}
+
+/// Returns the symbols extracted from the argument or null if it cannot be
+/// found.
+static SymbolRef getFuchsiaHandleSymbol(QualType QT, SVal Arg,
+ ProgramStateRef State) {
+ int PtrToHandleLevel = 0;
+ while (QT->isAnyPointerType() || QT->isReferenceType()) {
+ ++PtrToHandleLevel;
+ QT = QT->getPointeeType();
+ }
+ if (const auto *HandleType = QT->getAs<TypedefType>()) {
+ if (HandleType->getDecl()->getName() != HandleTypeName)
+ return nullptr;
+ if (PtrToHandleLevel > 1) {
+ // Not supported yet.
+ return nullptr;
+ }
+
+ if (PtrToHandleLevel == 0) {
+ return Arg.getAsSymbol();
+ } else {
+ assert(PtrToHandleLevel == 1);
+ if (Optional<Loc> ArgLoc = Arg.getAs<Loc>())
+ return State->getSVal(*ArgLoc).getAsSymbol();
+ }
+ }
+ return nullptr;
+}
+
+void FuchsiaHandleChecker::checkPreCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ const FunctionDecl *FuncDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
+ if (!FuncDecl) {
+ // Unknown call, escape by value handles. They are not covered by
+ // PointerEscape callback.
+ for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) {
+ if (SymbolRef Handle = Call.getArgSVal(Arg).getAsSymbol())
+ State = State->set<HStateMap>(Handle, HandleState::getEscaped());
+ }
+ C.addTransition(State);
+ return;
+ }
+
+ for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) {
+ if (Arg >= FuncDecl->getNumParams())
+ break;
+ const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
+ SymbolRef Handle =
+ getFuchsiaHandleSymbol(PVD->getType(), Call.getArgSVal(Arg), State);
+ if (!Handle)
+ continue;
+
+ // Handled in checkPostCall.
+ if (hasFuchsiaAttr<ReleaseHandleAttr>(PVD) ||
+ hasFuchsiaAttr<AcquireHandleAttr>(PVD))
+ continue;
+
+ const HandleState *HState = State->get<HStateMap>(Handle);
+ if (!HState || HState->isEscaped())
+ continue;
+
+ if (hasFuchsiaAttr<UseHandleAttr>(PVD) || PVD->getType()->isIntegerType()) {
+ if (HState->isReleased()) {
+ reportUseAfterFree(Handle, Call.getArgSourceRange(Arg), C);
+ return;
+ }
+ }
+ if (!hasFuchsiaAttr<UseHandleAttr>(PVD) &&
+ PVD->getType()->isIntegerType()) {
+ // Working around integer by-value escapes.
+ State = State->set<HStateMap>(Handle, HandleState::getEscaped());
+ }
+ }
+ C.addTransition(State);
+}
+
+void FuchsiaHandleChecker::checkPostCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ const FunctionDecl *FuncDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
+ if (!FuncDecl)
+ return;
+
+ ProgramStateRef State = C.getState();
+
+ std::vector<std::function<std::string(BugReport & BR)>> Notes;
+ SymbolRef ResultSymbol = nullptr;
+ if (const auto *TypeDefTy = FuncDecl->getReturnType()->getAs<TypedefType>())
+ if (TypeDefTy->getDecl()->getName() == ErrorTypeName)
+ ResultSymbol = Call.getReturnValue().getAsSymbol();
+
+ // Function returns an open handle.
+ if (hasFuchsiaAttr<AcquireHandleAttr>(FuncDecl)) {
+ SymbolRef RetSym = Call.getReturnValue().getAsSymbol();
+ State =
+ State->set<HStateMap>(RetSym, HandleState::getMaybeAllocated(nullptr));
+ }
+
+ for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) {
+ if (Arg >= FuncDecl->getNumParams())
+ break;
+ const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
+ SymbolRef Handle =
+ getFuchsiaHandleSymbol(PVD->getType(), Call.getArgSVal(Arg), State);
+ if (!Handle)
+ continue;
+
+ const HandleState *HState = State->get<HStateMap>(Handle);
+ if (HState && HState->isEscaped())
+ continue;
+ if (hasFuchsiaAttr<ReleaseHandleAttr>(PVD)) {
+ if (HState && HState->isReleased()) {
+ reportDoubleRelease(Handle, Call.getArgSourceRange(Arg), C);
+ return;
+ } else {
+ Notes.push_back([Handle](BugReport &BR) {
+ auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
+ if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) {
+ return "Handle released here.";
+ } else
+ return "";
+ });
+ State = State->set<HStateMap>(Handle, HandleState::getReleased());
+ }
+ } else if (hasFuchsiaAttr<AcquireHandleAttr>(PVD)) {
+ Notes.push_back([Handle](BugReport &BR) {
+ auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
+ if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) {
+ return "Handle allocated here.";
+ } else
+ return "";
+ });
+ State = State->set<HStateMap>(
+ Handle, HandleState::getMaybeAllocated(ResultSymbol));
+ }
+ }
+ const NoteTag *T = nullptr;
+ if (!Notes.empty()) {
+ T = C.getNoteTag(
+ [this, Notes{std::move(Notes)}](BugReport &BR) -> std::string {
+ if (&BR.getBugType() != &UseAfterReleaseBugType &&
+ &BR.getBugType() != &LeakBugType &&
+ &BR.getBugType() != &DoubleReleaseBugType)
+ return "";
+ for (auto &Note : Notes) {
+ std::string Text = Note(BR);
+ if (!Text.empty())
+ return Text;
+ }
+ return "";
+ });
+ }
+ C.addTransition(State, T);
+}
+
+void FuchsiaHandleChecker::checkDeadSymbols(SymbolReaper &SymReaper,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ SmallVector<SymbolRef, 2> LeakedSyms;
+ HStateMapTy TrackedHandles = State->get<HStateMap>();
+ for (auto &CurItem : TrackedHandles) {
+ if (!SymReaper.isDead(CurItem.first))
+ continue;
+ if (CurItem.second.isAllocated() || CurItem.second.maybeAllocated())
+ LeakedSyms.push_back(CurItem.first);
+ State = State->remove<HStateMap>(CurItem.first);
+ }
+
+ ExplodedNode *N = C.getPredecessor();
+ if (!LeakedSyms.empty())
+ N = reportLeaks(LeakedSyms, C, N);
+
+ C.addTransition(State, N);
+}
+
+// Acquiring a handle is not always successful. In Fuchsia most functions
+// return a status code that determines the status of the handle.
+// When we split the path based on this status code we know that on one
+// path we do have the handle and on the other path the acquire failed.
+// This method helps avoiding false positive leak warnings on paths where
+// the function failed.
+// Moreover, when a handle is known to be zero (the invalid handle),
+// we no longer can follow the symbol on the path, becaue the constant
+// zero will be used instead of the symbol. We also do not need to release
+// an invalid handle, so we remove the corresponding symbol from the state.
+ProgramStateRef FuchsiaHandleChecker::evalAssume(ProgramStateRef State,
+ SVal Cond,
+ bool Assumption) const {
+ // TODO: add notes about successes/fails for APIs.
+ ConstraintManager &Cmr = State->getConstraintManager();
+ HStateMapTy TrackedHandles = State->get<HStateMap>();
+ for (auto &CurItem : TrackedHandles) {
+ ConditionTruthVal HandleVal = Cmr.isNull(State, CurItem.first);
+ if (HandleVal.isConstrainedTrue()) {
+ // The handle is invalid. We can no longer follow the symbol on this path.
+ State = State->remove<HStateMap>(CurItem.first);
+ }
+ SymbolRef ErrorSym = CurItem.second.getErrorSym();
+ if (!ErrorSym)
+ continue;
+ ConditionTruthVal ErrorVal = Cmr.isNull(State, ErrorSym);
+ if (ErrorVal.isConstrainedTrue()) {
+ // Allocation succeeded.
+ if (CurItem.second.maybeAllocated())
+ State = State->set<HStateMap>(
+ CurItem.first, HandleState::getAllocated(State, CurItem.second));
+ } else if (ErrorVal.isConstrainedFalse()) {
+ // Allocation failed.
+ if (CurItem.second.maybeAllocated())
+ State = State->remove<HStateMap>(CurItem.first);
+ }
+ }
+ return State;
+}
+
+ProgramStateRef FuchsiaHandleChecker::checkPointerEscape(
+ ProgramStateRef State, const InvalidatedSymbols &Escaped,
+ const CallEvent *Call, PointerEscapeKind Kind) const {
+ const FunctionDecl *FuncDecl =
+ Call ? dyn_cast_or_null<FunctionDecl>(Call->getDecl()) : nullptr;
+
+ llvm::DenseSet<SymbolRef> UnEscaped;
+ // Not all calls should escape our symbols.
+ if (FuncDecl &&
+ (Kind == PSK_DirectEscapeOnCall || Kind == PSK_IndirectEscapeOnCall ||
+ Kind == PSK_EscapeOutParameters)) {
+ for (unsigned Arg = 0; Arg < Call->getNumArgs(); ++Arg) {
+ if (Arg >= FuncDecl->getNumParams())
+ break;
+ const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
+ SymbolRef Handle =
+ getFuchsiaHandleSymbol(PVD->getType(), Call->getArgSVal(Arg), State);
+ if (!Handle)
+ continue;
+ if (hasFuchsiaAttr<UseHandleAttr>(PVD) ||
+ hasFuchsiaAttr<ReleaseHandleAttr>(PVD))
+ UnEscaped.insert(Handle);
+ }
+ }
+
+ // For out params, we have to deal with derived symbols. See
+ // MacOSKeychainAPIChecker for details.
+ for (auto I : State->get<HStateMap>()) {
+ if (Escaped.count(I.first) && !UnEscaped.count(I.first))
+ State = State->set<HStateMap>(I.first, HandleState::getEscaped());
+ if (const auto *SD = dyn_cast<SymbolDerived>(I.first)) {
+ auto ParentSym = SD->getParentSymbol();
+ if (Escaped.count(ParentSym))
+ State = State->set<HStateMap>(I.first, HandleState::getEscaped());
+ }
+ }
+
+ return State;
+}
+
+ExplodedNode *
+FuchsiaHandleChecker::reportLeaks(ArrayRef<SymbolRef> LeakedHandles,
+ CheckerContext &C, ExplodedNode *Pred) const {
+ ExplodedNode *ErrNode = C.generateNonFatalErrorNode(C.getState(), Pred);
+ for (SymbolRef LeakedHandle : LeakedHandles) {
+ reportBug(LeakedHandle, ErrNode, C, nullptr, LeakBugType,
+ "Potential leak of handle");
+ }
+ return ErrNode;
+}
+
+void FuchsiaHandleChecker::reportDoubleRelease(SymbolRef HandleSym,
+ const SourceRange &Range,
+ CheckerContext &C) const {
+ ExplodedNode *ErrNode = C.generateErrorNode(C.getState());
+ reportBug(HandleSym, ErrNode, C, &Range, DoubleReleaseBugType,
+ "Releasing a previously released handle");
+}
+
+void FuchsiaHandleChecker::reportUseAfterFree(SymbolRef HandleSym,
+ const SourceRange &Range,
+ CheckerContext &C) const {
+ ExplodedNode *ErrNode = C.generateErrorNode(C.getState());
+ reportBug(HandleSym, ErrNode, C, &Range, UseAfterReleaseBugType,
+ "Using a previously released handle");
+}
+
+void FuchsiaHandleChecker::reportBug(SymbolRef Sym, ExplodedNode *ErrorNode,
+ CheckerContext &C,
+ const SourceRange *Range,
+ const BugType &Type, StringRef Msg) const {
+ if (!ErrorNode)
+ return;
+
+ std::unique_ptr<PathSensitiveBugReport> R;
+ if (Type.isSuppressOnSink()) {
+ const ExplodedNode *AcquireNode = getAcquireSite(ErrorNode, Sym, C);
+ if (AcquireNode) {
+ PathDiagnosticLocation LocUsedForUniqueing =
+ PathDiagnosticLocation::createBegin(
+ AcquireNode->getStmtForDiagnostics(), C.getSourceManager(),
+ AcquireNode->getLocationContext());
+
+ R = std::make_unique<PathSensitiveBugReport>(
+ Type, Msg, ErrorNode, LocUsedForUniqueing,
+ AcquireNode->getLocationContext()->getDecl());
+ }
+ }
+ if (!R)
+ R = std::make_unique<PathSensitiveBugReport>(Type, Msg, ErrorNode);
+ if (Range)
+ R->addRange(*Range);
+ R->markInteresting(Sym);
+ C.emitReport(std::move(R));
+}
+
+void ento::registerFuchsiaHandleChecker(CheckerManager &mgr) {
+ mgr.registerChecker<FuchsiaHandleChecker>();
+}
+
+bool ento::shouldRegisterFuchsiaHandleChecker(const LangOptions &LO) {
+ return true;
+}
+
+void FuchsiaHandleChecker::printState(raw_ostream &Out, ProgramStateRef State,
+ const char *NL, const char *Sep) const {
+
+ HStateMapTy StateMap = State->get<HStateMap>();
+
+ if (!StateMap.isEmpty()) {
+ Out << Sep << "FuchsiaHandleChecker :" << NL;
+ for (HStateMapTy::iterator I = StateMap.begin(), E = StateMap.end(); I != E;
+ ++I) {
+ I.getKey()->dumpToStream(Out);
+ Out << " : ";
+ I.getData().dump(Out);
+ Out << NL;
+ }
+ }
+}
diff --git a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
index d442b26b3959..302d5bb1bea8 100644
--- a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -24,9 +24,10 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include "llvm/ADT/StringMap.h"
#include "llvm/Support/YAMLTraits.h"
+#include <algorithm>
#include <limits>
+#include <unordered_map>
#include <utility>
using namespace clang;
@@ -56,10 +57,11 @@ public:
/// Used to parse the configuration file.
struct TaintConfiguration {
- using NameArgsPair = std::pair<std::string, ArgVector>;
+ using NameScopeArgs = std::tuple<std::string, std::string, ArgVector>;
struct Propagation {
std::string Name;
+ std::string Scope;
ArgVector SrcArgs;
SignedArgVector DstArgs;
VariadicType VarType;
@@ -67,8 +69,8 @@ public:
};
std::vector<Propagation> Propagations;
- std::vector<NameArgsPair> Filters;
- std::vector<NameArgsPair> Sinks;
+ std::vector<NameScopeArgs> Filters;
+ std::vector<NameScopeArgs> Sinks;
TaintConfiguration() = default;
TaintConfiguration(const TaintConfiguration &) = default;
@@ -97,14 +99,52 @@ private:
BT.reset(new BugType(this, "Use of Untrusted Data", "Untrusted Data"));
}
+ struct FunctionData {
+ FunctionData() = delete;
+ FunctionData(const FunctionData &) = default;
+ FunctionData(FunctionData &&) = default;
+ FunctionData &operator=(const FunctionData &) = delete;
+ FunctionData &operator=(FunctionData &&) = delete;
+
+ static Optional<FunctionData> create(const CallExpr *CE,
+ const CheckerContext &C) {
+ const FunctionDecl *FDecl = C.getCalleeDecl(CE);
+ if (!FDecl || (FDecl->getKind() != Decl::Function &&
+ FDecl->getKind() != Decl::CXXMethod))
+ return None;
+
+ StringRef Name = C.getCalleeName(FDecl);
+ std::string FullName = FDecl->getQualifiedNameAsString();
+ if (Name.empty() || FullName.empty())
+ return None;
+
+ return FunctionData{FDecl, Name, FullName};
+ }
+
+ bool isInScope(StringRef Scope) const {
+ return StringRef(FullName).startswith(Scope);
+ }
+
+ const FunctionDecl *const FDecl;
+ const StringRef Name;
+ const std::string FullName;
+ };
+
/// Catch taint related bugs. Check if tainted data is passed to a
- /// system call etc.
- bool checkPre(const CallExpr *CE, CheckerContext &C) const;
+ /// system call etc. Returns true on matching.
+ bool checkPre(const CallExpr *CE, const FunctionData &FData,
+ CheckerContext &C) const;
- /// Add taint sources on a pre-visit.
- void addSourcesPre(const CallExpr *CE, CheckerContext &C) const;
+ /// Add taint sources on a pre-visit. Returns true on matching.
+ bool addSourcesPre(const CallExpr *CE, const FunctionData &FData,
+ CheckerContext &C) const;
- /// Propagate taint generated at pre-visit.
+ /// Mark filter's arguments not tainted on a pre-visit. Returns true on
+ /// matching.
+ bool addFiltersPre(const CallExpr *CE, const FunctionData &FData,
+ CheckerContext &C) const;
+
+ /// Propagate taint generated at pre-visit. Returns true on matching.
bool propagateFromPre(const CallExpr *CE, CheckerContext &C) const;
/// Check if the region the expression evaluates to is the standard input,
@@ -142,7 +182,7 @@ private:
/// Check if tainted data is used as a custom sink's parameter.
static constexpr llvm::StringLiteral MsgCustomSink =
"Untrusted data is passed to a user-defined sink";
- bool checkCustomSinks(const CallExpr *CE, StringRef Name,
+ bool checkCustomSinks(const CallExpr *CE, const FunctionData &FData,
CheckerContext &C) const;
/// Generate a report if the expression is tainted or points to tainted data.
@@ -150,8 +190,17 @@ private:
CheckerContext &C) const;
struct TaintPropagationRule;
- using NameRuleMap = llvm::StringMap<TaintPropagationRule>;
- using NameArgMap = llvm::StringMap<ArgVector>;
+ template <typename T>
+ using ConfigDataMap =
+ std::unordered_multimap<std::string, std::pair<std::string, T>>;
+ using NameRuleMap = ConfigDataMap<TaintPropagationRule>;
+ using NameArgMap = ConfigDataMap<ArgVector>;
+
+ /// Find a function with the given name and scope. Returns the first match
+ /// or the end of the map.
+ template <typename T>
+ static auto findFunctionInConfig(const ConfigDataMap<T> &Map,
+ const FunctionData &FData);
/// A struct used to specify taint propagation rules for a function.
///
@@ -193,8 +242,7 @@ private:
/// Get the propagation rule for a given function.
static TaintPropagationRule
getTaintPropagationRule(const NameRuleMap &CustomPropagations,
- const FunctionDecl *FDecl, StringRef Name,
- CheckerContext &C);
+ const FunctionData &FData, CheckerContext &C);
void addSrcArg(unsigned A) { SrcArgs.push_back(A); }
void addDstArg(unsigned A) { DstArgs.push_back(A); }
@@ -229,14 +277,15 @@ private:
CheckerContext &C);
};
- /// Defines a map between the propagation function's name and
- /// TaintPropagationRule.
+ /// Defines a map between the propagation function's name, scope
+ /// and TaintPropagationRule.
NameRuleMap CustomPropagations;
- /// Defines a map between the filter function's name and filtering args.
+ /// Defines a map between the filter function's name, scope and filtering
+ /// args.
NameArgMap CustomFilters;
- /// Defines a map between the sink function's name and sinking args.
+ /// Defines a map between the sink function's name, scope and sinking args.
NameArgMap CustomSinks;
};
@@ -253,7 +302,7 @@ constexpr llvm::StringLiteral GenericTaintChecker::MsgCustomSink;
using TaintConfig = GenericTaintChecker::TaintConfiguration;
LLVM_YAML_IS_SEQUENCE_VECTOR(TaintConfig::Propagation)
-LLVM_YAML_IS_SEQUENCE_VECTOR(TaintConfig::NameArgsPair)
+LLVM_YAML_IS_SEQUENCE_VECTOR(TaintConfig::NameScopeArgs)
namespace llvm {
namespace yaml {
@@ -268,6 +317,7 @@ template <> struct MappingTraits<TaintConfig> {
template <> struct MappingTraits<TaintConfig::Propagation> {
static void mapping(IO &IO, TaintConfig::Propagation &Propagation) {
IO.mapRequired("Name", Propagation.Name);
+ IO.mapOptional("Scope", Propagation.Scope);
IO.mapOptional("SrcArgs", Propagation.SrcArgs);
IO.mapOptional("DstArgs", Propagation.DstArgs);
IO.mapOptional("VariadicType", Propagation.VarType,
@@ -285,10 +335,11 @@ template <> struct ScalarEnumerationTraits<GenericTaintChecker::VariadicType> {
}
};
-template <> struct MappingTraits<TaintConfig::NameArgsPair> {
- static void mapping(IO &IO, TaintConfig::NameArgsPair &NameArg) {
- IO.mapRequired("Name", NameArg.first);
- IO.mapRequired("Args", NameArg.second);
+template <> struct MappingTraits<TaintConfig::NameScopeArgs> {
+ static void mapping(IO &IO, TaintConfig::NameScopeArgs &NSA) {
+ IO.mapRequired("Name", std::get<0>(NSA));
+ IO.mapOptional("Scope", std::get<1>(NSA));
+ IO.mapRequired("Args", std::get<2>(NSA));
}
};
} // namespace yaml
@@ -321,31 +372,51 @@ void GenericTaintChecker::parseConfiguration(CheckerManager &Mgr,
const std::string &Option,
TaintConfiguration &&Config) {
for (auto &P : Config.Propagations) {
- GenericTaintChecker::CustomPropagations.try_emplace(
- P.Name, std::move(P.SrcArgs),
- convertToArgVector(Mgr, Option, P.DstArgs), P.VarType, P.VarIndex);
+ GenericTaintChecker::CustomPropagations.emplace(
+ P.Name,
+ std::make_pair(P.Scope, TaintPropagationRule{
+ std::move(P.SrcArgs),
+ convertToArgVector(Mgr, Option, P.DstArgs),
+ P.VarType, P.VarIndex}));
}
for (auto &F : Config.Filters) {
- GenericTaintChecker::CustomFilters.try_emplace(F.first,
- std::move(F.second));
+ GenericTaintChecker::CustomFilters.emplace(
+ std::get<0>(F),
+ std::make_pair(std::move(std::get<1>(F)), std::move(std::get<2>(F))));
}
for (auto &S : Config.Sinks) {
- GenericTaintChecker::CustomSinks.try_emplace(S.first, std::move(S.second));
+ GenericTaintChecker::CustomSinks.emplace(
+ std::get<0>(S),
+ std::make_pair(std::move(std::get<1>(S)), std::move(std::get<2>(S))));
}
}
+template <typename T>
+auto GenericTaintChecker::findFunctionInConfig(const ConfigDataMap<T> &Map,
+ const FunctionData &FData) {
+ auto Range = Map.equal_range(FData.Name);
+ auto It =
+ std::find_if(Range.first, Range.second, [&FData](const auto &Entry) {
+ const auto &Value = Entry.second;
+ StringRef Scope = Value.first;
+ return Scope.empty() || FData.isInScope(Scope);
+ });
+ return It != Range.second ? It : Map.end();
+}
+
GenericTaintChecker::TaintPropagationRule
GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
- const NameRuleMap &CustomPropagations, const FunctionDecl *FDecl,
- StringRef Name, CheckerContext &C) {
+ const NameRuleMap &CustomPropagations, const FunctionData &FData,
+ CheckerContext &C) {
// TODO: Currently, we might lose precision here: we always mark a return
// value as tainted even if it's just a pointer, pointing to tainted data.
// Check for exact name match for functions without builtin substitutes.
+ // Use qualified name, because these are C functions without namespace.
TaintPropagationRule Rule =
- llvm::StringSwitch<TaintPropagationRule>(Name)
+ llvm::StringSwitch<TaintPropagationRule>(FData.FullName)
// Source functions
// TODO: Add support for vfscanf & family.
.Case("fdopen", TaintPropagationRule({}, {ReturnValueIndex}))
@@ -390,6 +461,7 @@ GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
// Check if it's one of the memory setting/copying functions.
// This check is specialized but faster then calling isCLibraryFunction.
+ const FunctionDecl *FDecl = FData.FDecl;
unsigned BId = 0;
if ((BId = FDecl->getMemoryFunctionKind()))
switch (BId) {
@@ -433,23 +505,32 @@ GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
// or smart memory copy:
// - memccpy - copying until hitting a special character.
- auto It = CustomPropagations.find(Name);
- if (It != CustomPropagations.end())
- return It->getValue();
+ auto It = findFunctionInConfig(CustomPropagations, FData);
+ if (It != CustomPropagations.end()) {
+ const auto &Value = It->second;
+ return Value.second;
+ }
return TaintPropagationRule();
}
void GenericTaintChecker::checkPreStmt(const CallExpr *CE,
CheckerContext &C) const {
+ Optional<FunctionData> FData = FunctionData::create(CE, C);
+ if (!FData)
+ return;
+
// Check for taintedness related errors first: system call, uncontrolled
// format string, tainted buffer size.
- if (checkPre(CE, C))
+ if (checkPre(CE, *FData, C))
return;
// Marks the function's arguments and/or return value tainted if it present in
// the list.
- addSourcesPre(CE, C);
+ if (addSourcesPre(CE, *FData, C))
+ return;
+
+ addFiltersPre(CE, *FData, C);
}
void GenericTaintChecker::checkPostStmt(const CallExpr *CE,
@@ -464,31 +545,47 @@ void GenericTaintChecker::printState(raw_ostream &Out, ProgramStateRef State,
printTaint(State, Out, NL, Sep);
}
-void GenericTaintChecker::addSourcesPre(const CallExpr *CE,
+bool GenericTaintChecker::addSourcesPre(const CallExpr *CE,
+ const FunctionData &FData,
CheckerContext &C) const {
- ProgramStateRef State = nullptr;
- const FunctionDecl *FDecl = C.getCalleeDecl(CE);
- if (!FDecl || FDecl->getKind() != Decl::Function)
- return;
-
- StringRef Name = C.getCalleeName(FDecl);
- if (Name.empty())
- return;
-
// First, try generating a propagation rule for this function.
TaintPropagationRule Rule = TaintPropagationRule::getTaintPropagationRule(
- this->CustomPropagations, FDecl, Name, C);
+ this->CustomPropagations, FData, C);
if (!Rule.isNull()) {
- State = Rule.process(CE, C);
- if (!State)
- return;
- C.addTransition(State);
- return;
+ ProgramStateRef State = Rule.process(CE, C);
+ if (State) {
+ C.addTransition(State);
+ return true;
+ }
}
+ return false;
+}
- if (!State)
- return;
- C.addTransition(State);
+bool GenericTaintChecker::addFiltersPre(const CallExpr *CE,
+ const FunctionData &FData,
+ CheckerContext &C) const {
+ auto It = findFunctionInConfig(CustomFilters, FData);
+ if (It == CustomFilters.end())
+ return false;
+
+ ProgramStateRef State = C.getState();
+ const auto &Value = It->second;
+ const ArgVector &Args = Value.second;
+ for (unsigned ArgNum : Args) {
+ if (ArgNum >= CE->getNumArgs())
+ continue;
+
+ const Expr *Arg = CE->getArg(ArgNum);
+ Optional<SVal> V = getPointedToSVal(C, Arg);
+ if (V)
+ State = removeTaint(State, *V);
+ }
+
+ if (State != C.getState()) {
+ C.addTransition(State);
+ return true;
+ }
+ return false;
}
bool GenericTaintChecker::propagateFromPre(const CallExpr *CE,
@@ -530,26 +627,19 @@ bool GenericTaintChecker::propagateFromPre(const CallExpr *CE,
}
bool GenericTaintChecker::checkPre(const CallExpr *CE,
+ const FunctionData &FData,
CheckerContext &C) const {
if (checkUncontrolledFormatString(CE, C))
return true;
- const FunctionDecl *FDecl = C.getCalleeDecl(CE);
- if (!FDecl || FDecl->getKind() != Decl::Function)
- return false;
-
- StringRef Name = C.getCalleeName(FDecl);
- if (Name.empty())
- return false;
-
- if (checkSystemCall(CE, Name, C))
+ if (checkSystemCall(CE, FData.Name, C))
return true;
- if (checkTaintedBufferSize(CE, FDecl, C))
+ if (checkTaintedBufferSize(CE, FData.FDecl, C))
return true;
- if (checkCustomSinks(CE, Name, C))
+ if (checkCustomSinks(CE, FData, C))
return true;
return false;
@@ -568,7 +658,7 @@ Optional<SVal> GenericTaintChecker::getPointedToSVal(CheckerContext &C,
QualType ArgTy = Arg->getType().getCanonicalType();
if (!ArgTy->isPointerType())
- return None;
+ return State->getSVal(*AddrLoc);
QualType ValTy = ArgTy->getPointeeType();
@@ -821,13 +911,15 @@ bool GenericTaintChecker::checkTaintedBufferSize(const CallExpr *CE,
generateReportIfTainted(CE->getArg(ArgNum), MsgTaintedBufferSize, C);
}
-bool GenericTaintChecker::checkCustomSinks(const CallExpr *CE, StringRef Name,
+bool GenericTaintChecker::checkCustomSinks(const CallExpr *CE,
+ const FunctionData &FData,
CheckerContext &C) const {
- auto It = CustomSinks.find(Name);
+ auto It = findFunctionInConfig(CustomSinks, FData);
if (It == CustomSinks.end())
return false;
- const GenericTaintChecker::ArgVector &Args = It->getValue();
+ const auto &Value = It->second;
+ const GenericTaintChecker::ArgVector &Args = Value.second;
for (unsigned ArgNum : Args) {
if (ArgNum >= CE->getNumArgs())
continue;
diff --git a/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
index b0d101c88517..dd89c53478e8 100644
--- a/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
@@ -62,7 +62,7 @@ public:
// lookup by region.
bool isSymbolTracked(ProgramStateRef State, SymbolRef Sym) {
RawPtrMapTy Map = State->get<RawPtrMap>();
- for (const auto Entry : Map) {
+ for (const auto &Entry : Map) {
if (Entry.second.contains(Sym))
return true;
}
@@ -236,7 +236,7 @@ void InnerPointerChecker::checkDeadSymbols(SymbolReaper &SymReaper,
ProgramStateRef State = C.getState();
PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>();
RawPtrMapTy RPM = State->get<RawPtrMap>();
- for (const auto Entry : RPM) {
+ for (const auto &Entry : RPM) {
if (!SymReaper.isLiveRegion(Entry.first)) {
// Due to incomplete destructor support, some dead regions might
// remain in the program state map. Clean them up.
@@ -266,7 +266,7 @@ std::unique_ptr<BugReporterVisitor> getInnerPointerBRVisitor(SymbolRef Sym) {
const MemRegion *getContainerObjRegion(ProgramStateRef State, SymbolRef Sym) {
RawPtrMapTy Map = State->get<RawPtrMap>();
- for (const auto Entry : Map) {
+ for (const auto &Entry : Map) {
if (Entry.second.contains(Sym)) {
return Entry.first;
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/InvalidatedIteratorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/InvalidatedIteratorChecker.cpp
new file mode 100644
index 000000000000..d1a9a7df071d
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Checkers/InvalidatedIteratorChecker.cpp
@@ -0,0 +1,95 @@
+//===-- InvalidatedIteratorChecker.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
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines a checker for access of invalidated iterators.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+
+#include "Iterator.h"
+
+using namespace clang;
+using namespace ento;
+using namespace iterator;
+
+namespace {
+
+class InvalidatedIteratorChecker
+ : public Checker<check::PreCall> {
+
+ std::unique_ptr<BugType> InvalidatedBugType;
+
+ void verifyAccess(CheckerContext &C, const SVal &Val) const;
+ void reportBug(const StringRef &Message, const SVal &Val,
+ CheckerContext &C, ExplodedNode *ErrNode) const;
+public:
+ InvalidatedIteratorChecker();
+
+ void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+
+};
+
+} //namespace
+
+InvalidatedIteratorChecker::InvalidatedIteratorChecker() {
+ InvalidatedBugType.reset(
+ new BugType(this, "Iterator invalidated", "Misuse of STL APIs"));
+}
+
+void InvalidatedIteratorChecker::checkPreCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ // Check for access of invalidated position
+ const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
+ if (!Func)
+ return;
+
+ if (Func->isOverloadedOperator() &&
+ isAccessOperator(Func->getOverloadedOperator())) {
+ // Check for any kind of access of invalidated iterator positions
+ if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+ verifyAccess(C, InstCall->getCXXThisVal());
+ } else {
+ verifyAccess(C, Call.getArgSVal(0));
+ }
+ }
+}
+
+void InvalidatedIteratorChecker::verifyAccess(CheckerContext &C, const SVal &Val) const {
+ auto State = C.getState();
+ const auto *Pos = getIteratorPosition(State, Val);
+ if (Pos && !Pos->isValid()) {
+ auto *N = C.generateErrorNode(State);
+ if (!N) {
+ return;
+ }
+ reportBug("Invalidated iterator accessed.", Val, C, N);
+ }
+}
+
+void InvalidatedIteratorChecker::reportBug(const StringRef &Message,
+ const SVal &Val, CheckerContext &C,
+ ExplodedNode *ErrNode) const {
+ auto R = std::make_unique<PathSensitiveBugReport>(*InvalidatedBugType,
+ Message, ErrNode);
+ R->markInteresting(Val);
+ C.emitReport(std::move(R));
+}
+
+void ento::registerInvalidatedIteratorChecker(CheckerManager &mgr) {
+ mgr.registerChecker<InvalidatedIteratorChecker>();
+}
+
+bool ento::shouldRegisterInvalidatedIteratorChecker(const LangOptions &LO) {
+ return true;
+}
diff --git a/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp b/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
new file mode 100644
index 000000000000..6bca5515724c
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
@@ -0,0 +1,227 @@
+//=== Iterator.cpp - Common functions for iterator checkers. -------*- C++ -*-//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines common functions to be used by the itertor checkers .
+//
+//===----------------------------------------------------------------------===//
+
+#include "Iterator.h"
+
+namespace clang {
+namespace ento {
+namespace iterator {
+
+bool isIteratorType(const QualType &Type) {
+ if (Type->isPointerType())
+ return true;
+
+ const auto *CRD = Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
+ return isIterator(CRD);
+}
+
+bool isIterator(const CXXRecordDecl *CRD) {
+ if (!CRD)
+ return false;
+
+ const auto Name = CRD->getName();
+ if (!(Name.endswith_lower("iterator") || Name.endswith_lower("iter") ||
+ Name.endswith_lower("it")))
+ return false;
+
+ bool HasCopyCtor = false, HasCopyAssign = true, HasDtor = false,
+ HasPreIncrOp = false, HasPostIncrOp = false, HasDerefOp = false;
+ for (const auto *Method : CRD->methods()) {
+ if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Method)) {
+ if (Ctor->isCopyConstructor()) {
+ HasCopyCtor = !Ctor->isDeleted() && Ctor->getAccess() == AS_public;
+ }
+ continue;
+ }
+ if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) {
+ HasDtor = !Dtor->isDeleted() && Dtor->getAccess() == AS_public;
+ continue;
+ }
+ if (Method->isCopyAssignmentOperator()) {
+ HasCopyAssign = !Method->isDeleted() && Method->getAccess() == AS_public;
+ continue;
+ }
+ if (!Method->isOverloadedOperator())
+ continue;
+ const auto OPK = Method->getOverloadedOperator();
+ if (OPK == OO_PlusPlus) {
+ HasPreIncrOp = HasPreIncrOp || (Method->getNumParams() == 0);
+ HasPostIncrOp = HasPostIncrOp || (Method->getNumParams() == 1);
+ continue;
+ }
+ if (OPK == OO_Star) {
+ HasDerefOp = (Method->getNumParams() == 0);
+ continue;
+ }
+ }
+
+ return HasCopyCtor && HasCopyAssign && HasDtor && HasPreIncrOp &&
+ HasPostIncrOp && HasDerefOp;
+}
+
+bool isComparisonOperator(OverloadedOperatorKind OK) {
+ return OK == OO_EqualEqual || OK == OO_ExclaimEqual || OK == OO_Less ||
+ OK == OO_LessEqual || OK == OO_Greater || OK == OO_GreaterEqual;
+}
+
+bool isInsertCall(const FunctionDecl *Func) {
+ const auto *IdInfo = Func->getIdentifier();
+ if (!IdInfo)
+ return false;
+ if (Func->getNumParams() < 2 || Func->getNumParams() > 3)
+ return false;
+ if (!isIteratorType(Func->getParamDecl(0)->getType()))
+ return false;
+ return IdInfo->getName() == "insert";
+}
+
+bool isEmplaceCall(const FunctionDecl *Func) {
+ const auto *IdInfo = Func->getIdentifier();
+ if (!IdInfo)
+ return false;
+ if (Func->getNumParams() < 2)
+ return false;
+ if (!isIteratorType(Func->getParamDecl(0)->getType()))
+ return false;
+ return IdInfo->getName() == "emplace";
+}
+
+bool isEraseCall(const FunctionDecl *Func) {
+ const auto *IdInfo = Func->getIdentifier();
+ if (!IdInfo)
+ return false;
+ if (Func->getNumParams() < 1 || Func->getNumParams() > 2)
+ return false;
+ if (!isIteratorType(Func->getParamDecl(0)->getType()))
+ return false;
+ if (Func->getNumParams() == 2 &&
+ !isIteratorType(Func->getParamDecl(1)->getType()))
+ return false;
+ return IdInfo->getName() == "erase";
+}
+
+bool isEraseAfterCall(const FunctionDecl *Func) {
+ const auto *IdInfo = Func->getIdentifier();
+ if (!IdInfo)
+ return false;
+ if (Func->getNumParams() < 1 || Func->getNumParams() > 2)
+ return false;
+ if (!isIteratorType(Func->getParamDecl(0)->getType()))
+ return false;
+ if (Func->getNumParams() == 2 &&
+ !isIteratorType(Func->getParamDecl(1)->getType()))
+ return false;
+ return IdInfo->getName() == "erase_after";
+}
+
+bool isAccessOperator(OverloadedOperatorKind OK) {
+ return isDereferenceOperator(OK) || isIncrementOperator(OK) ||
+ isDecrementOperator(OK) || isRandomIncrOrDecrOperator(OK);
+}
+
+bool isDereferenceOperator(OverloadedOperatorKind OK) {
+ return OK == OO_Star || OK == OO_Arrow || OK == OO_ArrowStar ||
+ OK == OO_Subscript;
+}
+
+bool isIncrementOperator(OverloadedOperatorKind OK) {
+ return OK == OO_PlusPlus;
+}
+
+bool isDecrementOperator(OverloadedOperatorKind OK) {
+ return OK == OO_MinusMinus;
+}
+
+bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK) {
+ return OK == OO_Plus || OK == OO_PlusEqual || OK == OO_Minus ||
+ OK == OO_MinusEqual;
+}
+
+const ContainerData *getContainerData(ProgramStateRef State,
+ const MemRegion *Cont) {
+ return State->get<ContainerMap>(Cont);
+}
+
+const IteratorPosition *getIteratorPosition(ProgramStateRef State,
+ const SVal &Val) {
+ if (auto Reg = Val.getAsRegion()) {
+ Reg = Reg->getMostDerivedObjectRegion();
+ return State->get<IteratorRegionMap>(Reg);
+ } else if (const auto Sym = Val.getAsSymbol()) {
+ return State->get<IteratorSymbolMap>(Sym);
+ } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
+ return State->get<IteratorRegionMap>(LCVal->getRegion());
+ }
+ return nullptr;
+}
+
+ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
+ const IteratorPosition &Pos) {
+ if (auto Reg = Val.getAsRegion()) {
+ Reg = Reg->getMostDerivedObjectRegion();
+ return State->set<IteratorRegionMap>(Reg, Pos);
+ } else if (const auto Sym = Val.getAsSymbol()) {
+ return State->set<IteratorSymbolMap>(Sym, Pos);
+ } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
+ return State->set<IteratorRegionMap>(LCVal->getRegion(), Pos);
+ }
+ return nullptr;
+}
+
+ProgramStateRef advancePosition(ProgramStateRef State, const SVal &Iter,
+ OverloadedOperatorKind Op,
+ const SVal &Distance) {
+ const auto *Pos = getIteratorPosition(State, Iter);
+ if (!Pos)
+ return nullptr;
+
+ auto &SymMgr = State->getStateManager().getSymbolManager();
+ auto &SVB = State->getStateManager().getSValBuilder();
+
+ assert ((Op == OO_Plus || Op == OO_PlusEqual ||
+ Op == OO_Minus || Op == OO_MinusEqual) &&
+ "Advance operator must be one of +, -, += and -=.");
+ auto BinOp = (Op == OO_Plus || Op == OO_PlusEqual) ? BO_Add : BO_Sub;
+ if (const auto IntDist = Distance.getAs<nonloc::ConcreteInt>()) {
+ // For concrete integers we can calculate the new position
+ const auto NewPos =
+ Pos->setTo(SVB.evalBinOp(State, BinOp,
+ nonloc::SymbolVal(Pos->getOffset()),
+ *IntDist, SymMgr.getType(Pos->getOffset()))
+ .getAsSymbol());
+ return setIteratorPosition(State, Iter, NewPos);
+ }
+
+ return nullptr;
+}
+
+bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
+ BinaryOperator::Opcode Opc) {
+ return compare(State, nonloc::SymbolVal(Sym1), nonloc::SymbolVal(Sym2), Opc);
+}
+
+bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
+ BinaryOperator::Opcode Opc) {
+ auto &SVB = State->getStateManager().getSValBuilder();
+
+ const auto comparison =
+ SVB.evalBinOp(State, Opc, NL1, NL2, SVB.getConditionType());
+
+ assert(comparison.getAs<DefinedSVal>() &&
+ "Symbol comparison must be a `DefinedSVal`");
+
+ return !State->assume(comparison.castAs<DefinedSVal>(), false);
+}
+
+} // namespace iterator
+} // namespace ento
+} // namespace clang
diff --git a/clang/lib/StaticAnalyzer/Checkers/Iterator.h b/clang/lib/StaticAnalyzer/Checkers/Iterator.h
new file mode 100644
index 000000000000..c10d86691693
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Checkers/Iterator.h
@@ -0,0 +1,175 @@
+//=== Iterator.h - Common functions for iterator checkers. ---------*- C++ -*-//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines common functions to be used by the itertor checkers .
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_ITERATOR_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_ITERATOR_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
+
+namespace clang {
+namespace ento {
+namespace iterator {
+
+// Abstract position of an iterator. This helps to handle all three kinds
+// of operators in a common way by using a symbolic position.
+struct IteratorPosition {
+private:
+
+ // Container the iterator belongs to
+ const MemRegion *Cont;
+
+ // Whether iterator is valid
+ const bool Valid;
+
+ // Abstract offset
+ const SymbolRef Offset;
+
+ IteratorPosition(const MemRegion *C, bool V, SymbolRef Of)
+ : Cont(C), Valid(V), Offset(Of) {}
+
+public:
+ const MemRegion *getContainer() const { return Cont; }
+ bool isValid() const { return Valid; }
+ SymbolRef getOffset() const { return Offset; }
+
+ IteratorPosition invalidate() const {
+ return IteratorPosition(Cont, false, Offset);
+ }
+
+ static IteratorPosition getPosition(const MemRegion *C, SymbolRef Of) {
+ return IteratorPosition(C, true, Of);
+ }
+
+ IteratorPosition setTo(SymbolRef NewOf) const {
+ return IteratorPosition(Cont, Valid, NewOf);
+ }
+
+ IteratorPosition reAssign(const MemRegion *NewCont) const {
+ return IteratorPosition(NewCont, Valid, Offset);
+ }
+
+ bool operator==(const IteratorPosition &X) const {
+ return Cont == X.Cont && Valid == X.Valid && Offset == X.Offset;
+ }
+
+ bool operator!=(const IteratorPosition &X) const {
+ return Cont != X.Cont || Valid != X.Valid || Offset != X.Offset;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddPointer(Cont);
+ ID.AddInteger(Valid);
+ ID.Add(Offset);
+ }
+};
+
+// Structure to record the symbolic begin and end position of a container
+struct ContainerData {
+private:
+ const SymbolRef Begin, End;
+
+ ContainerData(SymbolRef B, SymbolRef E) : Begin(B), End(E) {}
+
+public:
+ static ContainerData fromBegin(SymbolRef B) {
+ return ContainerData(B, nullptr);
+ }
+
+ static ContainerData fromEnd(SymbolRef E) {
+ return ContainerData(nullptr, E);
+ }
+
+ SymbolRef getBegin() const { return Begin; }
+ SymbolRef getEnd() const { return End; }
+
+ ContainerData newBegin(SymbolRef B) const { return ContainerData(B, End); }
+
+ ContainerData newEnd(SymbolRef E) const { return ContainerData(Begin, E); }
+
+ bool operator==(const ContainerData &X) const {
+ return Begin == X.Begin && End == X.End;
+ }
+
+ bool operator!=(const ContainerData &X) const {
+ return Begin != X.Begin || End != X.End;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.Add(Begin);
+ ID.Add(End);
+ }
+};
+
+class IteratorSymbolMap {};
+class IteratorRegionMap {};
+class ContainerMap {};
+
+using IteratorSymbolMapTy = CLANG_ENTO_PROGRAMSTATE_MAP(SymbolRef, IteratorPosition);
+using IteratorRegionMapTy = CLANG_ENTO_PROGRAMSTATE_MAP(const MemRegion *, IteratorPosition);
+using ContainerMapTy = CLANG_ENTO_PROGRAMSTATE_MAP(const MemRegion *, ContainerData);
+
+} // namespace iterator
+
+template<>
+struct ProgramStateTrait<iterator::IteratorSymbolMap>
+ : public ProgramStatePartialTrait<iterator::IteratorSymbolMapTy> {
+ static void *GDMIndex() { static int Index; return &Index; }
+};
+
+template<>
+struct ProgramStateTrait<iterator::IteratorRegionMap>
+ : public ProgramStatePartialTrait<iterator::IteratorRegionMapTy> {
+ static void *GDMIndex() { static int Index; return &Index; }
+};
+
+template<>
+struct ProgramStateTrait<iterator::ContainerMap>
+ : public ProgramStatePartialTrait<iterator::ContainerMapTy> {
+ static void *GDMIndex() { static int Index; return &Index; }
+};
+
+namespace iterator {
+
+bool isIteratorType(const QualType &Type);
+bool isIterator(const CXXRecordDecl *CRD);
+bool isComparisonOperator(OverloadedOperatorKind OK);
+bool isInsertCall(const FunctionDecl *Func);
+bool isEraseCall(const FunctionDecl *Func);
+bool isEraseAfterCall(const FunctionDecl *Func);
+bool isEmplaceCall(const FunctionDecl *Func);
+bool isAccessOperator(OverloadedOperatorKind OK);
+bool isDereferenceOperator(OverloadedOperatorKind OK);
+bool isIncrementOperator(OverloadedOperatorKind OK);
+bool isDecrementOperator(OverloadedOperatorKind OK);
+bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK);
+const ContainerData *getContainerData(ProgramStateRef State,
+ const MemRegion *Cont);
+const IteratorPosition *getIteratorPosition(ProgramStateRef State,
+ const SVal &Val);
+ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
+ const IteratorPosition &Pos);
+ProgramStateRef advancePosition(ProgramStateRef State,
+ const SVal &Iter,
+ OverloadedOperatorKind Op,
+ const SVal &Distance);
+bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
+ BinaryOperator::Opcode Opc);
+bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
+ BinaryOperator::Opcode Opc);
+
+} // namespace iterator
+} // namespace ento
+} // namespace clang
+
+#endif
diff --git a/clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
index 97ace68569ef..eb962a2ffd9e 100644
--- a/clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
@@ -1,4 +1,4 @@
-//===-- IteratorChecker.cpp ---------------------------------------*- C++ -*--//
+//===-- IteratorModeling.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.
@@ -73,127 +73,33 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
+#include "Iterator.h"
+
#include <utility>
using namespace clang;
using namespace ento;
+using namespace iterator;
namespace {
-// Abstract position of an iterator. This helps to handle all three kinds
-// of operators in a common way by using a symbolic position.
-struct IteratorPosition {
-private:
-
- // Container the iterator belongs to
- const MemRegion *Cont;
-
- // Whether iterator is valid
- const bool Valid;
-
- // Abstract offset
- const SymbolRef Offset;
-
- IteratorPosition(const MemRegion *C, bool V, SymbolRef Of)
- : Cont(C), Valid(V), Offset(Of) {}
-
-public:
- const MemRegion *getContainer() const { return Cont; }
- bool isValid() const { return Valid; }
- SymbolRef getOffset() const { return Offset; }
-
- IteratorPosition invalidate() const {
- return IteratorPosition(Cont, false, Offset);
- }
-
- static IteratorPosition getPosition(const MemRegion *C, SymbolRef Of) {
- return IteratorPosition(C, true, Of);
- }
-
- IteratorPosition setTo(SymbolRef NewOf) const {
- return IteratorPosition(Cont, Valid, NewOf);
- }
-
- IteratorPosition reAssign(const MemRegion *NewCont) const {
- return IteratorPosition(NewCont, Valid, Offset);
- }
-
- bool operator==(const IteratorPosition &X) const {
- return Cont == X.Cont && Valid == X.Valid && Offset == X.Offset;
- }
-
- bool operator!=(const IteratorPosition &X) const {
- return Cont != X.Cont || Valid != X.Valid || Offset != X.Offset;
- }
-
- void Profile(llvm::FoldingSetNodeID &ID) const {
- ID.AddPointer(Cont);
- ID.AddInteger(Valid);
- ID.Add(Offset);
- }
-};
-
-// Structure to record the symbolic begin and end position of a container
-struct ContainerData {
-private:
- const SymbolRef Begin, End;
-
- ContainerData(SymbolRef B, SymbolRef E) : Begin(B), End(E) {}
-
-public:
- static ContainerData fromBegin(SymbolRef B) {
- return ContainerData(B, nullptr);
- }
-
- static ContainerData fromEnd(SymbolRef E) {
- return ContainerData(nullptr, E);
- }
-
- SymbolRef getBegin() const { return Begin; }
- SymbolRef getEnd() const { return End; }
+class IteratorModeling
+ : public Checker<check::PostCall, check::PostStmt<MaterializeTemporaryExpr>,
+ check::Bind, check::LiveSymbols, check::DeadSymbols> {
- ContainerData newBegin(SymbolRef B) const { return ContainerData(B, End); }
-
- ContainerData newEnd(SymbolRef E) const { return ContainerData(Begin, E); }
-
- bool operator==(const ContainerData &X) const {
- return Begin == X.Begin && End == X.End;
- }
-
- bool operator!=(const ContainerData &X) const {
- return Begin != X.Begin || End != X.End;
- }
-
- void Profile(llvm::FoldingSetNodeID &ID) const {
- ID.Add(Begin);
- ID.Add(End);
- }
-};
-
-class IteratorChecker
- : public Checker<check::PreCall, check::PostCall,
- check::PostStmt<MaterializeTemporaryExpr>, check::Bind,
- check::LiveSymbols, check::DeadSymbols> {
-
- std::unique_ptr<BugType> OutOfRangeBugType;
- std::unique_ptr<BugType> MismatchedBugType;
- std::unique_ptr<BugType> InvalidatedBugType;
-
- void handleComparison(CheckerContext &C, const Expr *CE, const SVal &RetVal,
+ void handleComparison(CheckerContext &C, const Expr *CE, SVal RetVal,
const SVal &LVal, const SVal &RVal,
OverloadedOperatorKind Op) const;
void processComparison(CheckerContext &C, ProgramStateRef State,
SymbolRef Sym1, SymbolRef Sym2, const SVal &RetVal,
OverloadedOperatorKind Op) const;
- void verifyAccess(CheckerContext &C, const SVal &Val) const;
- void verifyDereference(CheckerContext &C, const SVal &Val) const;
void handleIncrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter,
bool Postfix) const;
void handleDecrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter,
bool Postfix) const;
- void handleRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op,
- const SVal &RetVal, const SVal &LHS,
- const SVal &RHS) const;
+ void handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE,
+ OverloadedOperatorKind Op, const SVal &RetVal,
+ const SVal &LHS, const SVal &RHS) const;
void handleBegin(CheckerContext &C, const Expr *CE, const SVal &RetVal,
const SVal &Cont) const;
void handleEnd(CheckerContext &C, const Expr *CE, const SVal &RetVal,
@@ -215,42 +121,12 @@ class IteratorChecker
void handleEraseAfter(CheckerContext &C, const SVal &Iter) const;
void handleEraseAfter(CheckerContext &C, const SVal &Iter1,
const SVal &Iter2) const;
- void verifyIncrement(CheckerContext &C, const SVal &Iter) const;
- void verifyDecrement(CheckerContext &C, const SVal &Iter) const;
- void verifyRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op,
- const SVal &LHS, const SVal &RHS) const;
- void verifyMatch(CheckerContext &C, const SVal &Iter,
- const MemRegion *Cont) const;
- void verifyMatch(CheckerContext &C, const SVal &Iter1,
- const SVal &Iter2) const;
- IteratorPosition advancePosition(CheckerContext &C, OverloadedOperatorKind Op,
- const IteratorPosition &Pos,
- const SVal &Distance) const;
- void reportOutOfRangeBug(const StringRef &Message, const SVal &Val,
- CheckerContext &C, ExplodedNode *ErrNode) const;
- void reportMismatchedBug(const StringRef &Message, const SVal &Val1,
- const SVal &Val2, CheckerContext &C,
- ExplodedNode *ErrNode) const;
- void reportMismatchedBug(const StringRef &Message, const SVal &Val,
- const MemRegion *Reg, CheckerContext &C,
- ExplodedNode *ErrNode) const;
- void reportInvalidatedBug(const StringRef &Message, const SVal &Val,
- CheckerContext &C, ExplodedNode *ErrNode) const;
+ void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
+ const char *Sep) const override;
public:
- IteratorChecker();
-
- enum CheckKind {
- CK_IteratorRangeChecker,
- CK_MismatchedIteratorChecker,
- CK_InvalidatedIteratorChecker,
- CK_NumCheckKinds
- };
-
- DefaultBool ChecksEnabled[CK_NumCheckKinds];
- CheckerNameRef CheckNames[CK_NumCheckKinds];
+ IteratorModeling() {}
- void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const;
void checkPostStmt(const CXXConstructExpr *CCE, CheckerContext &C) const;
@@ -260,19 +136,7 @@ public:
void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
};
-} // namespace
-
-REGISTER_MAP_WITH_PROGRAMSTATE(IteratorSymbolMap, SymbolRef, IteratorPosition)
-REGISTER_MAP_WITH_PROGRAMSTATE(IteratorRegionMap, const MemRegion *,
- IteratorPosition)
-REGISTER_MAP_WITH_PROGRAMSTATE(ContainerMap, const MemRegion *, ContainerData)
-
-namespace {
-
-bool isIteratorType(const QualType &Type);
-bool isIterator(const CXXRecordDecl *CRD);
-bool isComparisonOperator(OverloadedOperatorKind OK);
bool isBeginCall(const FunctionDecl *Func);
bool isEndCall(const FunctionDecl *Func);
bool isAssignCall(const FunctionDecl *Func);
@@ -283,17 +147,8 @@ bool isPopBackCall(const FunctionDecl *Func);
bool isPushFrontCall(const FunctionDecl *Func);
bool isEmplaceFrontCall(const FunctionDecl *Func);
bool isPopFrontCall(const FunctionDecl *Func);
-bool isInsertCall(const FunctionDecl *Func);
-bool isEraseCall(const FunctionDecl *Func);
-bool isEraseAfterCall(const FunctionDecl *Func);
-bool isEmplaceCall(const FunctionDecl *Func);
bool isAssignmentOperator(OverloadedOperatorKind OK);
bool isSimpleComparisonOperator(OverloadedOperatorKind OK);
-bool isAccessOperator(OverloadedOperatorKind OK);
-bool isDereferenceOperator(OverloadedOperatorKind OK);
-bool isIncrementOperator(OverloadedOperatorKind OK);
-bool isDecrementOperator(OverloadedOperatorKind OK);
-bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK);
bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg);
bool frontModifiable(ProgramStateRef State, const MemRegion *Reg);
bool backModifiable(ProgramStateRef State, const MemRegion *Reg);
@@ -307,10 +162,8 @@ ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
const Expr *E, QualType T,
const LocationContext *LCtx,
unsigned BlockCount);
-const IteratorPosition *getIteratorPosition(ProgramStateRef State,
- const SVal &Val);
-ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
- const IteratorPosition &Pos);
+ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
+ const ContainerData &CData);
ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val);
ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym,
long Scale);
@@ -341,222 +194,16 @@ ProgramStateRef rebaseSymbolInIteratorPositionsIf(
SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc);
ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1,
SymbolRef Sym2, bool Equal);
-const ContainerData *getContainerData(ProgramStateRef State,
- const MemRegion *Cont);
-ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
- const ContainerData &CData);
+SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB, SymbolRef Expr,
+ SymbolRef OldSym, SymbolRef NewSym);
bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont);
bool isBoundThroughLazyCompoundVal(const Environment &Env,
const MemRegion *Reg);
-bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
-bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos);
-bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
-bool isZero(ProgramStateRef State, const NonLoc &Val);
-} // namespace
-
-IteratorChecker::IteratorChecker() {
- OutOfRangeBugType.reset(
- new BugType(this, "Iterator out of range", "Misuse of STL APIs"));
- MismatchedBugType.reset(
- new BugType(this, "Iterator(s) mismatched", "Misuse of STL APIs",
- /*SuppressOnSink=*/true));
- InvalidatedBugType.reset(
- new BugType(this, "Iterator invalidated", "Misuse of STL APIs"));
-}
-
-void IteratorChecker::checkPreCall(const CallEvent &Call,
- CheckerContext &C) const {
- // Check for out of range access or access of invalidated position and
- // iterator mismatches
- const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
- if (!Func)
- return;
-
- if (Func->isOverloadedOperator()) {
- if (ChecksEnabled[CK_InvalidatedIteratorChecker] &&
- isAccessOperator(Func->getOverloadedOperator())) {
- // Check for any kind of access of invalidated iterator positions
- if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
- verifyAccess(C, InstCall->getCXXThisVal());
- } else {
- verifyAccess(C, Call.getArgSVal(0));
- }
- }
- if (ChecksEnabled[CK_IteratorRangeChecker]) {
- if (isIncrementOperator(Func->getOverloadedOperator())) {
- // Check for out-of-range incrementions
- if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
- verifyIncrement(C, InstCall->getCXXThisVal());
- } else {
- if (Call.getNumArgs() >= 1) {
- verifyIncrement(C, Call.getArgSVal(0));
- }
- }
- } else if (isDecrementOperator(Func->getOverloadedOperator())) {
- // Check for out-of-range decrementions
- if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
- verifyDecrement(C, InstCall->getCXXThisVal());
- } else {
- if (Call.getNumArgs() >= 1) {
- verifyDecrement(C, Call.getArgSVal(0));
- }
- }
- } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
- if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
- // Check for out-of-range incrementions and decrementions
- if (Call.getNumArgs() >= 1 &&
- Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
- verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
- InstCall->getCXXThisVal(),
- Call.getArgSVal(0));
- }
- } else {
- if (Call.getNumArgs() >= 2 &&
- Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
- verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
- Call.getArgSVal(0), Call.getArgSVal(1));
- }
- }
- } else if (isDereferenceOperator(Func->getOverloadedOperator())) {
- // Check for dereference of out-of-range iterators
- if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
- verifyDereference(C, InstCall->getCXXThisVal());
- } else {
- verifyDereference(C, Call.getArgSVal(0));
- }
- }
- } else if (ChecksEnabled[CK_MismatchedIteratorChecker] &&
- isComparisonOperator(Func->getOverloadedOperator())) {
- // Check for comparisons of iterators of different containers
- if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
- if (Call.getNumArgs() < 1)
- return;
-
- if (!isIteratorType(InstCall->getCXXThisExpr()->getType()) ||
- !isIteratorType(Call.getArgExpr(0)->getType()))
- return;
-
- verifyMatch(C, InstCall->getCXXThisVal(), Call.getArgSVal(0));
- } else {
- if (Call.getNumArgs() < 2)
- return;
-
- if (!isIteratorType(Call.getArgExpr(0)->getType()) ||
- !isIteratorType(Call.getArgExpr(1)->getType()))
- return;
-
- verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1));
- }
- }
- } else if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
- if (!ChecksEnabled[CK_MismatchedIteratorChecker])
- return;
-
- const auto *ContReg = InstCall->getCXXThisVal().getAsRegion();
- if (!ContReg)
- return;
- // Check for erase, insert and emplace using iterator of another container
- if (isEraseCall(Func) || isEraseAfterCall(Func)) {
- verifyMatch(C, Call.getArgSVal(0),
- InstCall->getCXXThisVal().getAsRegion());
- if (Call.getNumArgs() == 2) {
- verifyMatch(C, Call.getArgSVal(1),
- InstCall->getCXXThisVal().getAsRegion());
- }
- } else if (isInsertCall(Func)) {
- verifyMatch(C, Call.getArgSVal(0),
- InstCall->getCXXThisVal().getAsRegion());
- if (Call.getNumArgs() == 3 &&
- isIteratorType(Call.getArgExpr(1)->getType()) &&
- isIteratorType(Call.getArgExpr(2)->getType())) {
- verifyMatch(C, Call.getArgSVal(1), Call.getArgSVal(2));
- }
- } else if (isEmplaceCall(Func)) {
- verifyMatch(C, Call.getArgSVal(0),
- InstCall->getCXXThisVal().getAsRegion());
- }
- } else if (isa<CXXConstructorCall>(&Call)) {
- // Check match of first-last iterator pair in a constructor of a container
- if (Call.getNumArgs() < 2)
- return;
-
- const auto *Ctr = cast<CXXConstructorDecl>(Call.getDecl());
- if (Ctr->getNumParams() < 2)
- return;
-
- if (Ctr->getParamDecl(0)->getName() != "first" ||
- Ctr->getParamDecl(1)->getName() != "last")
- return;
-
- if (!isIteratorType(Call.getArgExpr(0)->getType()) ||
- !isIteratorType(Call.getArgExpr(1)->getType()))
- return;
-
- verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1));
- } else {
- // The main purpose of iterators is to abstract away from different
- // containers and provide a (maybe limited) uniform access to them.
- // This implies that any correctly written template function that
- // works on multiple containers using iterators takes different
- // template parameters for different containers. So we can safely
- // assume that passing iterators of different containers as arguments
- // whose type replaces the same template parameter is a bug.
- //
- // Example:
- // template<typename I1, typename I2>
- // void f(I1 first1, I1 last1, I2 first2, I2 last2);
- //
- // In this case the first two arguments to f() must be iterators must belong
- // to the same container and the last to also to the same container but
- // not necessarily to the same as the first two.
-
- if (!ChecksEnabled[CK_MismatchedIteratorChecker])
- return;
-
- const auto *Templ = Func->getPrimaryTemplate();
- if (!Templ)
- return;
-
- const auto *TParams = Templ->getTemplateParameters();
- const auto *TArgs = Func->getTemplateSpecializationArgs();
-
- // Iterate over all the template parameters
- for (size_t I = 0; I < TParams->size(); ++I) {
- const auto *TPDecl = dyn_cast<TemplateTypeParmDecl>(TParams->getParam(I));
- if (!TPDecl)
- continue;
-
- if (TPDecl->isParameterPack())
- continue;
- const auto TAType = TArgs->get(I).getAsType();
- if (!isIteratorType(TAType))
- continue;
-
- SVal LHS = UndefinedVal();
-
- // For every template parameter which is an iterator type in the
- // instantiation look for all functions' parameters' type by it and
- // check whether they belong to the same container
- for (auto J = 0U; J < Func->getNumParams(); ++J) {
- const auto *Param = Func->getParamDecl(J);
- const auto *ParamType =
- Param->getType()->getAs<SubstTemplateTypeParmType>();
- if (!ParamType ||
- ParamType->getReplacedParameter()->getDecl() != TPDecl)
- continue;
- if (LHS.isUndef()) {
- LHS = Call.getArgSVal(J);
- } else {
- verifyMatch(C, LHS, Call.getArgSVal(J));
- }
- }
- }
- }
-}
+} // namespace
-void IteratorChecker::checkPostCall(const CallEvent &Call,
- CheckerContext &C) const {
+void IteratorModeling::checkPostCall(const CallEvent &Call,
+ CheckerContext &C) const {
// Record new iterator positions and iterator position changes
const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
if (!Func)
@@ -590,10 +237,14 @@ void IteratorChecker::checkPostCall(const CallEvent &Call,
Call.getArgSVal(1), Op);
return;
} else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
+ const auto *OrigExpr = Call.getOriginExpr();
+ if (!OrigExpr)
+ return;
+
if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
if (Call.getNumArgs() >= 1 &&
Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
- handleRandomIncrOrDecr(C, Func->getOverloadedOperator(),
+ handleRandomIncrOrDecr(C, OrigExpr, Func->getOverloadedOperator(),
Call.getReturnValue(),
InstCall->getCXXThisVal(), Call.getArgSVal(0));
return;
@@ -601,7 +252,7 @@ void IteratorChecker::checkPostCall(const CallEvent &Call,
} else {
if (Call.getNumArgs() >= 2 &&
Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
- handleRandomIncrOrDecr(C, Func->getOverloadedOperator(),
+ handleRandomIncrOrDecr(C, OrigExpr, Func->getOverloadedOperator(),
Call.getReturnValue(), Call.getArgSVal(0),
Call.getArgSVal(1));
return;
@@ -746,8 +397,8 @@ void IteratorChecker::checkPostCall(const CallEvent &Call,
}
}
-void IteratorChecker::checkBind(SVal Loc, SVal Val, const Stmt *S,
- CheckerContext &C) const {
+void IteratorModeling::checkBind(SVal Loc, SVal Val, const Stmt *S,
+ CheckerContext &C) const {
auto State = C.getState();
const auto *Pos = getIteratorPosition(State, Val);
if (Pos) {
@@ -762,24 +413,23 @@ void IteratorChecker::checkBind(SVal Loc, SVal Val, const Stmt *S,
}
}
-void IteratorChecker::checkPostStmt(const MaterializeTemporaryExpr *MTE,
- CheckerContext &C) const {
+void IteratorModeling::checkPostStmt(const MaterializeTemporaryExpr *MTE,
+ CheckerContext &C) const {
/* Transfer iterator state to temporary objects */
auto State = C.getState();
- const auto *Pos =
- getIteratorPosition(State, C.getSVal(MTE->GetTemporaryExpr()));
+ const auto *Pos = getIteratorPosition(State, C.getSVal(MTE->getSubExpr()));
if (!Pos)
return;
State = setIteratorPosition(State, C.getSVal(MTE), *Pos);
C.addTransition(State);
}
-void IteratorChecker::checkLiveSymbols(ProgramStateRef State,
- SymbolReaper &SR) const {
+void IteratorModeling::checkLiveSymbols(ProgramStateRef State,
+ SymbolReaper &SR) const {
// Keep symbolic expressions of iterator positions, container begins and ends
// alive
auto RegionMap = State->get<IteratorRegionMap>();
- for (const auto Reg : RegionMap) {
+ for (const auto &Reg : RegionMap) {
const auto Offset = Reg.second.getOffset();
for (auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i)
if (isa<SymbolData>(*i))
@@ -787,7 +437,7 @@ void IteratorChecker::checkLiveSymbols(ProgramStateRef State,
}
auto SymbolMap = State->get<IteratorSymbolMap>();
- for (const auto Sym : SymbolMap) {
+ for (const auto &Sym : SymbolMap) {
const auto Offset = Sym.second.getOffset();
for (auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i)
if (isa<SymbolData>(*i))
@@ -795,7 +445,7 @@ void IteratorChecker::checkLiveSymbols(ProgramStateRef State,
}
auto ContMap = State->get<ContainerMap>();
- for (const auto Cont : ContMap) {
+ for (const auto &Cont : ContMap) {
const auto CData = Cont.second;
if (CData.getBegin()) {
SR.markLive(CData.getBegin());
@@ -810,13 +460,13 @@ void IteratorChecker::checkLiveSymbols(ProgramStateRef State,
}
}
-void IteratorChecker::checkDeadSymbols(SymbolReaper &SR,
- CheckerContext &C) const {
+void IteratorModeling::checkDeadSymbols(SymbolReaper &SR,
+ CheckerContext &C) const {
// Cleanup
auto State = C.getState();
auto RegionMap = State->get<IteratorRegionMap>();
- for (const auto Reg : RegionMap) {
+ for (const auto &Reg : RegionMap) {
if (!SR.isLiveRegion(Reg.first)) {
// The region behind the `LazyCompoundVal` is often cleaned up before
// the `LazyCompoundVal` itself. If there are iterator positions keyed
@@ -828,14 +478,14 @@ void IteratorChecker::checkDeadSymbols(SymbolReaper &SR,
}
auto SymbolMap = State->get<IteratorSymbolMap>();
- for (const auto Sym : SymbolMap) {
+ for (const auto &Sym : SymbolMap) {
if (!SR.isLive(Sym.first)) {
State = State->remove<IteratorSymbolMap>(Sym.first);
}
}
auto ContMap = State->get<ContainerMap>();
- for (const auto Cont : ContMap) {
+ for (const auto &Cont : ContMap) {
if (!SR.isLiveRegion(Cont.first)) {
// We must keep the container data while it has live iterators to be able
// to compare them to the begin and the end of the container.
@@ -848,8 +498,8 @@ void IteratorChecker::checkDeadSymbols(SymbolReaper &SR,
C.addTransition(State);
}
-void IteratorChecker::handleComparison(CheckerContext &C, const Expr *CE,
- const SVal &RetVal, const SVal &LVal,
+void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE,
+ SVal RetVal, const SVal &LVal,
const SVal &RVal,
OverloadedOperatorKind Op) const {
// Record the operands and the operator of the comparison for the next
@@ -888,13 +538,23 @@ void IteratorChecker::handleComparison(CheckerContext &C, const Expr *CE,
RPos = getIteratorPosition(State, RVal);
}
+ // We cannot make assumpotions on `UnknownVal`. Let us conjure a symbol
+ // instead.
+ if (RetVal.isUnknown()) {
+ auto &SymMgr = C.getSymbolManager();
+ auto *LCtx = C.getLocationContext();
+ RetVal = nonloc::SymbolVal(SymMgr.conjureSymbol(
+ CE, LCtx, C.getASTContext().BoolTy, C.blockCount()));
+ State = State->BindExpr(CE, LCtx, RetVal);
+ }
+
processComparison(C, State, LPos->getOffset(), RPos->getOffset(), RetVal, Op);
}
-void IteratorChecker::processComparison(CheckerContext &C,
- ProgramStateRef State, SymbolRef Sym1,
- SymbolRef Sym2, const SVal &RetVal,
- OverloadedOperatorKind Op) const {
+void IteratorModeling::processComparison(CheckerContext &C,
+ ProgramStateRef State, SymbolRef Sym1,
+ SymbolRef Sym2, const SVal &RetVal,
+ OverloadedOperatorKind Op) const {
if (const auto TruthVal = RetVal.getAs<nonloc::ConcreteInt>()) {
if ((State = relateSymbols(State, Sym1, Sym2,
(Op == OO_EqualEqual) ==
@@ -909,7 +569,7 @@ void IteratorChecker::processComparison(CheckerContext &C,
const auto ConditionVal = RetVal.getAs<DefinedSVal>();
if (!ConditionVal)
return;
-
+
if (auto StateTrue = relateSymbols(State, Sym1, Sym2, Op == OO_EqualEqual)) {
StateTrue = StateTrue->assume(*ConditionVal, true);
C.addTransition(StateTrue);
@@ -921,75 +581,68 @@ void IteratorChecker::processComparison(CheckerContext &C,
}
}
-void IteratorChecker::verifyDereference(CheckerContext &C,
- const SVal &Val) const {
- auto State = C.getState();
- const auto *Pos = getIteratorPosition(State, Val);
- if (Pos && isPastTheEnd(State, *Pos)) {
- auto *N = C.generateErrorNode(State);
- if (!N)
- return;
- reportOutOfRangeBug("Past-the-end iterator dereferenced.", Val, C, N);
- return;
- }
-}
-
-void IteratorChecker::verifyAccess(CheckerContext &C, const SVal &Val) const {
- auto State = C.getState();
- const auto *Pos = getIteratorPosition(State, Val);
- if (Pos && !Pos->isValid()) {
- auto *N = C.generateErrorNode(State);
- if (!N) {
- return;
- }
- reportInvalidatedBug("Invalidated iterator accessed.", Val, C, N);
- }
-}
-
-void IteratorChecker::handleIncrement(CheckerContext &C, const SVal &RetVal,
- const SVal &Iter, bool Postfix) const {
+void IteratorModeling::handleIncrement(CheckerContext &C, const SVal &RetVal,
+ const SVal &Iter, bool Postfix) const {
// Increment the symbolic expressions which represents the position of the
// iterator
auto State = C.getState();
+ auto &BVF = C.getSymbolManager().getBasicVals();
+
const auto *Pos = getIteratorPosition(State, Iter);
- if (Pos) {
- auto &SymMgr = C.getSymbolManager();
- auto &BVF = SymMgr.getBasicVals();
- const auto NewPos =
- advancePosition(C, OO_Plus, *Pos,
+ if (!Pos)
+ return;
+
+ auto NewState =
+ advancePosition(State, Iter, OO_Plus,
nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
- State = setIteratorPosition(State, Iter, NewPos);
- State = setIteratorPosition(State, RetVal, Postfix ? *Pos : NewPos);
- C.addTransition(State);
- }
+ assert(NewState &&
+ "Advancing position by concrete int should always be successful");
+
+ const auto *NewPos = getIteratorPosition(NewState, Iter);
+ assert(NewPos &&
+ "Iterator should have position after successful advancement");
+
+ State = setIteratorPosition(State, Iter, *NewPos);
+ State = setIteratorPosition(State, RetVal, Postfix ? *Pos : *NewPos);
+ C.addTransition(State);
}
-void IteratorChecker::handleDecrement(CheckerContext &C, const SVal &RetVal,
- const SVal &Iter, bool Postfix) const {
+void IteratorModeling::handleDecrement(CheckerContext &C, const SVal &RetVal,
+ const SVal &Iter, bool Postfix) const {
// Decrement the symbolic expressions which represents the position of the
// iterator
auto State = C.getState();
+ auto &BVF = C.getSymbolManager().getBasicVals();
+
const auto *Pos = getIteratorPosition(State, Iter);
- if (Pos) {
- auto &SymMgr = C.getSymbolManager();
- auto &BVF = SymMgr.getBasicVals();
- const auto NewPos =
- advancePosition(C, OO_Minus, *Pos,
+ if (!Pos)
+ return;
+
+ auto NewState =
+ advancePosition(State, Iter, OO_Minus,
nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
- State = setIteratorPosition(State, Iter, NewPos);
- State = setIteratorPosition(State, RetVal, Postfix ? *Pos : NewPos);
- C.addTransition(State);
- }
+ assert(NewState &&
+ "Advancing position by concrete int should always be successful");
+
+ const auto *NewPos = getIteratorPosition(NewState, Iter);
+ assert(NewPos &&
+ "Iterator should have position after successful advancement");
+
+ State = setIteratorPosition(State, Iter, *NewPos);
+ State = setIteratorPosition(State, RetVal, Postfix ? *Pos : *NewPos);
+ C.addTransition(State);
}
-void IteratorChecker::handleRandomIncrOrDecr(CheckerContext &C,
- OverloadedOperatorKind Op,
- const SVal &RetVal,
- const SVal &LHS,
- const SVal &RHS) const {
+void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C,
+ const Expr *CE,
+ OverloadedOperatorKind Op,
+ const SVal &RetVal,
+ const SVal &LHS,
+ const SVal &RHS) const {
// Increment or decrement the symbolic expressions which represents the
// position of the iterator
auto State = C.getState();
+
const auto *Pos = getIteratorPosition(State, LHS);
if (!Pos)
return;
@@ -1001,142 +654,23 @@ void IteratorChecker::handleRandomIncrOrDecr(CheckerContext &C,
}
auto &TgtVal = (Op == OO_PlusEqual || Op == OO_MinusEqual) ? LHS : RetVal;
- State =
- setIteratorPosition(State, TgtVal, advancePosition(C, Op, *Pos, *value));
- C.addTransition(State);
-}
-void IteratorChecker::verifyIncrement(CheckerContext &C,
- const SVal &Iter) const {
- auto &BVF = C.getSValBuilder().getBasicValueFactory();
- verifyRandomIncrOrDecr(C, OO_Plus, Iter,
- nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
-}
+ auto NewState =
+ advancePosition(State, LHS, Op, *value);
+ if (NewState) {
+ const auto *NewPos = getIteratorPosition(NewState, LHS);
+ assert(NewPos &&
+ "Iterator should have position after successful advancement");
-void IteratorChecker::verifyDecrement(CheckerContext &C,
- const SVal &Iter) const {
- auto &BVF = C.getSValBuilder().getBasicValueFactory();
- verifyRandomIncrOrDecr(C, OO_Minus, Iter,
- nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
-}
-
-void IteratorChecker::verifyRandomIncrOrDecr(CheckerContext &C,
- OverloadedOperatorKind Op,
- const SVal &LHS,
- const SVal &RHS) const {
- auto State = C.getState();
-
- // If the iterator is initially inside its range, then the operation is valid
- const auto *Pos = getIteratorPosition(State, LHS);
- if (!Pos)
- return;
-
- auto Value = RHS;
- if (auto ValAsLoc = RHS.getAs<Loc>()) {
- Value = State->getRawSVal(*ValAsLoc);
- }
-
- if (Value.isUnknown())
- return;
-
- // Incremention or decremention by 0 is never a bug.
- if (isZero(State, Value.castAs<NonLoc>()))
- return;
-
- // The result may be the past-end iterator of the container, but any other
- // out of range position is undefined behaviour
- if (isAheadOfRange(State, advancePosition(C, Op, *Pos, Value))) {
- auto *N = C.generateErrorNode(State);
- if (!N)
- return;
- reportOutOfRangeBug("Iterator decremented ahead of its valid range.", LHS,
- C, N);
- }
- if (isBehindPastTheEnd(State, advancePosition(C, Op, *Pos, Value))) {
- auto *N = C.generateErrorNode(State);
- if (!N)
- return;
- reportOutOfRangeBug("Iterator incremented behind the past-the-end "
- "iterator.", LHS, C, N);
- }
-}
-
-void IteratorChecker::verifyMatch(CheckerContext &C, const SVal &Iter,
- const MemRegion *Cont) const {
- // Verify match between a container and the container of an iterator
- Cont = Cont->getMostDerivedObjectRegion();
-
- if (const auto *ContSym = Cont->getSymbolicBase()) {
- if (isa<SymbolConjured>(ContSym->getSymbol()))
- return;
- }
-
- auto State = C.getState();
- const auto *Pos = getIteratorPosition(State, Iter);
- if (!Pos)
- return;
-
- const auto *IterCont = Pos->getContainer();
-
- // Skip symbolic regions based on conjured symbols. Two conjured symbols
- // may or may not be the same. For example, the same function can return
- // the same or a different container but we get different conjured symbols
- // for each call. This may cause false positives so omit them from the check.
- if (const auto *ContSym = IterCont->getSymbolicBase()) {
- if (isa<SymbolConjured>(ContSym->getSymbol()))
- return;
- }
-
- if (IterCont != Cont) {
- auto *N = C.generateNonFatalErrorNode(State);
- if (!N) {
- return;
- }
- reportMismatchedBug("Container accessed using foreign iterator argument.",
- Iter, Cont, C, N);
- }
-}
-
-void IteratorChecker::verifyMatch(CheckerContext &C, const SVal &Iter1,
- const SVal &Iter2) const {
- // Verify match between the containers of two iterators
- auto State = C.getState();
- const auto *Pos1 = getIteratorPosition(State, Iter1);
- if (!Pos1)
- return;
-
- const auto *IterCont1 = Pos1->getContainer();
-
- // Skip symbolic regions based on conjured symbols. Two conjured symbols
- // may or may not be the same. For example, the same function can return
- // the same or a different container but we get different conjured symbols
- // for each call. This may cause false positives so omit them from the check.
- if (const auto *ContSym = IterCont1->getSymbolicBase()) {
- if (isa<SymbolConjured>(ContSym->getSymbol()))
- return;
- }
-
- const auto *Pos2 = getIteratorPosition(State, Iter2);
- if (!Pos2)
- return;
-
- const auto *IterCont2 = Pos2->getContainer();
- if (const auto *ContSym = IterCont2->getSymbolicBase()) {
- if (isa<SymbolConjured>(ContSym->getSymbol()))
- return;
- }
-
- if (IterCont1 != IterCont2) {
- auto *N = C.generateNonFatalErrorNode(State);
- if (!N)
- return;
- reportMismatchedBug("Iterators of different containers used where the "
- "same container is expected.", Iter1, Iter2, C, N);
+ State = setIteratorPosition(NewState, TgtVal, *NewPos);
+ C.addTransition(State);
+ } else {
+ assignToContainer(C, CE, TgtVal, Pos->getContainer());
}
}
-void IteratorChecker::handleBegin(CheckerContext &C, const Expr *CE,
- const SVal &RetVal, const SVal &Cont) const {
+void IteratorModeling::handleBegin(CheckerContext &C, const Expr *CE,
+ const SVal &RetVal, const SVal &Cont) const {
const auto *ContReg = Cont.getAsRegion();
if (!ContReg)
return;
@@ -1157,8 +691,8 @@ void IteratorChecker::handleBegin(CheckerContext &C, const Expr *CE,
C.addTransition(State);
}
-void IteratorChecker::handleEnd(CheckerContext &C, const Expr *CE,
- const SVal &RetVal, const SVal &Cont) const {
+void IteratorModeling::handleEnd(CheckerContext &C, const Expr *CE,
+ const SVal &RetVal, const SVal &Cont) const {
const auto *ContReg = Cont.getAsRegion();
if (!ContReg)
return;
@@ -1179,9 +713,9 @@ void IteratorChecker::handleEnd(CheckerContext &C, const Expr *CE,
C.addTransition(State);
}
-void IteratorChecker::assignToContainer(CheckerContext &C, const Expr *CE,
- const SVal &RetVal,
- const MemRegion *Cont) const {
+void IteratorModeling::assignToContainer(CheckerContext &C, const Expr *CE,
+ const SVal &RetVal,
+ const MemRegion *Cont) const {
Cont = Cont->getMostDerivedObjectRegion();
auto State = C.getState();
@@ -1194,8 +728,8 @@ void IteratorChecker::assignToContainer(CheckerContext &C, const Expr *CE,
C.addTransition(State);
}
-void IteratorChecker::handleAssign(CheckerContext &C, const SVal &Cont,
- const Expr *CE, const SVal &OldCont) const {
+void IteratorModeling::handleAssign(CheckerContext &C, const SVal &Cont,
+ const Expr *CE, const SVal &OldCont) const {
const auto *ContReg = Cont.getAsRegion();
if (!ContReg)
return;
@@ -1270,7 +804,7 @@ void IteratorChecker::handleAssign(CheckerContext &C, const SVal &Cont,
C.addTransition(State);
}
-void IteratorChecker::handleClear(CheckerContext &C, const SVal &Cont) const {
+void IteratorModeling::handleClear(CheckerContext &C, const SVal &Cont) const {
const auto *ContReg = Cont.getAsRegion();
if (!ContReg)
return;
@@ -1296,8 +830,8 @@ void IteratorChecker::handleClear(CheckerContext &C, const SVal &Cont) const {
C.addTransition(State);
}
-void IteratorChecker::handlePushBack(CheckerContext &C,
- const SVal &Cont) const {
+void IteratorModeling::handlePushBack(CheckerContext &C,
+ const SVal &Cont) const {
const auto *ContReg = Cont.getAsRegion();
if (!ContReg)
return;
@@ -1334,7 +868,8 @@ void IteratorChecker::handlePushBack(CheckerContext &C,
C.addTransition(State);
}
-void IteratorChecker::handlePopBack(CheckerContext &C, const SVal &Cont) const {
+void IteratorModeling::handlePopBack(CheckerContext &C,
+ const SVal &Cont) const {
const auto *ContReg = Cont.getAsRegion();
if (!ContReg)
return;
@@ -1371,8 +906,8 @@ void IteratorChecker::handlePopBack(CheckerContext &C, const SVal &Cont) const {
}
}
-void IteratorChecker::handlePushFront(CheckerContext &C,
- const SVal &Cont) const {
+void IteratorModeling::handlePushFront(CheckerContext &C,
+ const SVal &Cont) const {
const auto *ContReg = Cont.getAsRegion();
if (!ContReg)
return;
@@ -1404,8 +939,8 @@ void IteratorChecker::handlePushFront(CheckerContext &C,
}
}
-void IteratorChecker::handlePopFront(CheckerContext &C,
- const SVal &Cont) const {
+void IteratorModeling::handlePopFront(CheckerContext &C,
+ const SVal &Cont) const {
const auto *ContReg = Cont.getAsRegion();
if (!ContReg)
return;
@@ -1438,7 +973,7 @@ void IteratorChecker::handlePopFront(CheckerContext &C,
}
}
-void IteratorChecker::handleInsert(CheckerContext &C, const SVal &Iter) const {
+void IteratorModeling::handleInsert(CheckerContext &C, const SVal &Iter) const {
auto State = C.getState();
const auto *Pos = getIteratorPosition(State, Iter);
if (!Pos)
@@ -1463,7 +998,7 @@ void IteratorChecker::handleInsert(CheckerContext &C, const SVal &Iter) const {
}
}
-void IteratorChecker::handleErase(CheckerContext &C, const SVal &Iter) const {
+void IteratorModeling::handleErase(CheckerContext &C, const SVal &Iter) const {
auto State = C.getState();
const auto *Pos = getIteratorPosition(State, Iter);
if (!Pos)
@@ -1491,8 +1026,8 @@ void IteratorChecker::handleErase(CheckerContext &C, const SVal &Iter) const {
C.addTransition(State);
}
-void IteratorChecker::handleErase(CheckerContext &C, const SVal &Iter1,
- const SVal &Iter2) const {
+void IteratorModeling::handleErase(CheckerContext &C, const SVal &Iter1,
+ const SVal &Iter2) const {
auto State = C.getState();
const auto *Pos1 = getIteratorPosition(State, Iter1);
const auto *Pos2 = getIteratorPosition(State, Iter2);
@@ -1523,8 +1058,8 @@ void IteratorChecker::handleErase(CheckerContext &C, const SVal &Iter1,
C.addTransition(State);
}
-void IteratorChecker::handleEraseAfter(CheckerContext &C,
- const SVal &Iter) const {
+void IteratorModeling::handleEraseAfter(CheckerContext &C,
+ const SVal &Iter) const {
auto State = C.getState();
const auto *Pos = getIteratorPosition(State, Iter);
if (!Pos)
@@ -1544,8 +1079,8 @@ void IteratorChecker::handleEraseAfter(CheckerContext &C,
C.addTransition(State);
}
-void IteratorChecker::handleEraseAfter(CheckerContext &C, const SVal &Iter1,
- const SVal &Iter2) const {
+void IteratorModeling::handleEraseAfter(CheckerContext &C, const SVal &Iter1,
+ const SVal &Iter2) const {
auto State = C.getState();
const auto *Pos1 = getIteratorPosition(State, Iter1);
const auto *Pos2 = getIteratorPosition(State, Iter2);
@@ -1558,145 +1093,62 @@ void IteratorChecker::handleEraseAfter(CheckerContext &C, const SVal &Iter1,
C.addTransition(State);
}
-IteratorPosition IteratorChecker::advancePosition(CheckerContext &C,
- OverloadedOperatorKind Op,
- const IteratorPosition &Pos,
- const SVal &Distance) const {
- auto State = C.getState();
- auto &SymMgr = C.getSymbolManager();
- auto &SVB = C.getSValBuilder();
+void IteratorModeling::printState(raw_ostream &Out, ProgramStateRef State,
+ const char *NL, const char *Sep) const {
- assert ((Op == OO_Plus || Op == OO_PlusEqual ||
- Op == OO_Minus || Op == OO_MinusEqual) &&
- "Advance operator must be one of +, -, += and -=.");
- auto BinOp = (Op == OO_Plus || Op == OO_PlusEqual) ? BO_Add : BO_Sub;
- if (const auto IntDist = Distance.getAs<nonloc::ConcreteInt>()) {
- // For concrete integers we can calculate the new position
- return Pos.setTo(SVB.evalBinOp(State, BinOp,
- nonloc::SymbolVal(Pos.getOffset()), *IntDist,
- SymMgr.getType(Pos.getOffset()))
- .getAsSymbol());
- } else {
- // For other symbols create a new symbol to keep expressions simple
- const auto &LCtx = C.getLocationContext();
- const auto NewPosSym = SymMgr.conjureSymbol(nullptr, LCtx,
- SymMgr.getType(Pos.getOffset()),
- C.blockCount());
- State = assumeNoOverflow(State, NewPosSym, 4);
- return Pos.setTo(NewPosSym);
+ auto ContMap = State->get<ContainerMap>();
+
+ if (!ContMap.isEmpty()) {
+ Out << Sep << "Container Data :" << NL;
+ for (const auto &Cont : ContMap) {
+ Cont.first->dumpToStream(Out);
+ Out << " : [ ";
+ const auto CData = Cont.second;
+ if (CData.getBegin())
+ CData.getBegin()->dumpToStream(Out);
+ else
+ Out << "<Unknown>";
+ Out << " .. ";
+ if (CData.getEnd())
+ CData.getEnd()->dumpToStream(Out);
+ else
+ Out << "<Unknown>";
+ Out << " ]" << NL;
+ }
}
-}
-void IteratorChecker::reportOutOfRangeBug(const StringRef &Message,
- const SVal &Val, CheckerContext &C,
- ExplodedNode *ErrNode) const {
- auto R = std::make_unique<PathSensitiveBugReport>(*OutOfRangeBugType, Message,
- ErrNode);
- R->markInteresting(Val);
- C.emitReport(std::move(R));
-}
+ auto SymbolMap = State->get<IteratorSymbolMap>();
+ auto RegionMap = State->get<IteratorRegionMap>();
-void IteratorChecker::reportMismatchedBug(const StringRef &Message,
- const SVal &Val1, const SVal &Val2,
- CheckerContext &C,
- ExplodedNode *ErrNode) const {
- auto R = std::make_unique<PathSensitiveBugReport>(*MismatchedBugType, Message,
- ErrNode);
- R->markInteresting(Val1);
- R->markInteresting(Val2);
- C.emitReport(std::move(R));
-}
+ if (!SymbolMap.isEmpty() || !RegionMap.isEmpty()) {
+ Out << Sep << "Iterator Positions :" << NL;
+ for (const auto &Sym : SymbolMap) {
+ Sym.first->dumpToStream(Out);
+ Out << " : ";
+ const auto Pos = Sym.second;
+ Out << (Pos.isValid() ? "Valid" : "Invalid") << " ; Container == ";
+ Pos.getContainer()->dumpToStream(Out);
+ Out<<" ; Offset == ";
+ Pos.getOffset()->dumpToStream(Out);
+ }
-void IteratorChecker::reportMismatchedBug(const StringRef &Message,
- const SVal &Val, const MemRegion *Reg,
- CheckerContext &C,
- ExplodedNode *ErrNode) const {
- auto R = std::make_unique<PathSensitiveBugReport>(*MismatchedBugType, Message,
- ErrNode);
- R->markInteresting(Val);
- R->markInteresting(Reg);
- C.emitReport(std::move(R));
+ for (const auto &Reg : RegionMap) {
+ Reg.first->dumpToStream(Out);
+ Out << " : ";
+ const auto Pos = Reg.second;
+ Out << (Pos.isValid() ? "Valid" : "Invalid") << " ; Container == ";
+ Pos.getContainer()->dumpToStream(Out);
+ Out<<" ; Offset == ";
+ Pos.getOffset()->dumpToStream(Out);
+ }
+ }
}
-void IteratorChecker::reportInvalidatedBug(const StringRef &Message,
- const SVal &Val, CheckerContext &C,
- ExplodedNode *ErrNode) const {
- auto R = std::make_unique<PathSensitiveBugReport>(*InvalidatedBugType,
- Message, ErrNode);
- R->markInteresting(Val);
- C.emitReport(std::move(R));
-}
namespace {
-bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
-bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
-bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
-bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
- BinaryOperator::Opcode Opc);
-bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
- BinaryOperator::Opcode Opc);
const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State,
const MemRegion *Reg);
-SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB, SymbolRef Expr,
- SymbolRef OldSym, SymbolRef NewSym);
-
-bool isIteratorType(const QualType &Type) {
- if (Type->isPointerType())
- return true;
-
- const auto *CRD = Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
- return isIterator(CRD);
-}
-
-bool isIterator(const CXXRecordDecl *CRD) {
- if (!CRD)
- return false;
-
- const auto Name = CRD->getName();
- if (!(Name.endswith_lower("iterator") || Name.endswith_lower("iter") ||
- Name.endswith_lower("it")))
- return false;
-
- bool HasCopyCtor = false, HasCopyAssign = true, HasDtor = false,
- HasPreIncrOp = false, HasPostIncrOp = false, HasDerefOp = false;
- for (const auto *Method : CRD->methods()) {
- if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Method)) {
- if (Ctor->isCopyConstructor()) {
- HasCopyCtor = !Ctor->isDeleted() && Ctor->getAccess() == AS_public;
- }
- continue;
- }
- if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) {
- HasDtor = !Dtor->isDeleted() && Dtor->getAccess() == AS_public;
- continue;
- }
- if (Method->isCopyAssignmentOperator()) {
- HasCopyAssign = !Method->isDeleted() && Method->getAccess() == AS_public;
- continue;
- }
- if (!Method->isOverloadedOperator())
- continue;
- const auto OPK = Method->getOverloadedOperator();
- if (OPK == OO_PlusPlus) {
- HasPreIncrOp = HasPreIncrOp || (Method->getNumParams() == 0);
- HasPostIncrOp = HasPostIncrOp || (Method->getNumParams() == 1);
- continue;
- }
- if (OPK == OO_Star) {
- HasDerefOp = (Method->getNumParams() == 0);
- continue;
- }
- }
-
- return HasCopyCtor && HasCopyAssign && HasDtor && HasPreIncrOp &&
- HasPostIncrOp && HasDerefOp;
-}
-
-bool isComparisonOperator(OverloadedOperatorKind OK) {
- return OK == OO_EqualEqual || OK == OO_ExclaimEqual || OK == OO_Less ||
- OK == OO_LessEqual || OK == OO_Greater || OK == OO_GreaterEqual;
-}
bool isBeginCall(const FunctionDecl *Func) {
const auto *IdInfo = Func->getIdentifier();
@@ -1784,85 +1236,12 @@ bool isPopFrontCall(const FunctionDecl *Func) {
return IdInfo->getName() == "pop_front";
}
-bool isInsertCall(const FunctionDecl *Func) {
- const auto *IdInfo = Func->getIdentifier();
- if (!IdInfo)
- return false;
- if (Func->getNumParams() < 2 || Func->getNumParams() > 3)
- return false;
- if (!isIteratorType(Func->getParamDecl(0)->getType()))
- return false;
- return IdInfo->getName() == "insert";
-}
-
-bool isEmplaceCall(const FunctionDecl *Func) {
- const auto *IdInfo = Func->getIdentifier();
- if (!IdInfo)
- return false;
- if (Func->getNumParams() < 2)
- return false;
- if (!isIteratorType(Func->getParamDecl(0)->getType()))
- return false;
- return IdInfo->getName() == "emplace";
-}
-
-bool isEraseCall(const FunctionDecl *Func) {
- const auto *IdInfo = Func->getIdentifier();
- if (!IdInfo)
- return false;
- if (Func->getNumParams() < 1 || Func->getNumParams() > 2)
- return false;
- if (!isIteratorType(Func->getParamDecl(0)->getType()))
- return false;
- if (Func->getNumParams() == 2 &&
- !isIteratorType(Func->getParamDecl(1)->getType()))
- return false;
- return IdInfo->getName() == "erase";
-}
-
-bool isEraseAfterCall(const FunctionDecl *Func) {
- const auto *IdInfo = Func->getIdentifier();
- if (!IdInfo)
- return false;
- if (Func->getNumParams() < 1 || Func->getNumParams() > 2)
- return false;
- if (!isIteratorType(Func->getParamDecl(0)->getType()))
- return false;
- if (Func->getNumParams() == 2 &&
- !isIteratorType(Func->getParamDecl(1)->getType()))
- return false;
- return IdInfo->getName() == "erase_after";
-}
-
bool isAssignmentOperator(OverloadedOperatorKind OK) { return OK == OO_Equal; }
bool isSimpleComparisonOperator(OverloadedOperatorKind OK) {
return OK == OO_EqualEqual || OK == OO_ExclaimEqual;
}
-bool isAccessOperator(OverloadedOperatorKind OK) {
- return isDereferenceOperator(OK) || isIncrementOperator(OK) ||
- isDecrementOperator(OK) || isRandomIncrOrDecrOperator(OK);
-}
-
-bool isDereferenceOperator(OverloadedOperatorKind OK) {
- return OK == OO_Star || OK == OO_Arrow || OK == OO_ArrowStar ||
- OK == OO_Subscript;
-}
-
-bool isIncrementOperator(OverloadedOperatorKind OK) {
- return OK == OO_PlusPlus;
-}
-
-bool isDecrementOperator(OverloadedOperatorKind OK) {
- return OK == OO_MinusMinus;
-}
-
-bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK) {
- return OK == OO_Plus || OK == OO_PlusEqual || OK == OO_Minus ||
- OK == OO_MinusEqual;
-}
-
bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg) {
const auto *CRD = getCXXRecordDecl(State, Reg);
if (!CRD)
@@ -1985,52 +1364,62 @@ ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
return setContainerData(State, Cont, CData);
}
-const ContainerData *getContainerData(ProgramStateRef State,
- const MemRegion *Cont) {
- return State->get<ContainerMap>(Cont);
-}
-
ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
const ContainerData &CData) {
return State->set<ContainerMap>(Cont, CData);
}
-const IteratorPosition *getIteratorPosition(ProgramStateRef State,
- const SVal &Val) {
+ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val) {
if (auto Reg = Val.getAsRegion()) {
Reg = Reg->getMostDerivedObjectRegion();
- return State->get<IteratorRegionMap>(Reg);
+ return State->remove<IteratorRegionMap>(Reg);
} else if (const auto Sym = Val.getAsSymbol()) {
- return State->get<IteratorSymbolMap>(Sym);
+ return State->remove<IteratorSymbolMap>(Sym);
} else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
- return State->get<IteratorRegionMap>(LCVal->getRegion());
+ return State->remove<IteratorRegionMap>(LCVal->getRegion());
}
return nullptr;
}
-ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
- const IteratorPosition &Pos) {
- if (auto Reg = Val.getAsRegion()) {
- Reg = Reg->getMostDerivedObjectRegion();
- return State->set<IteratorRegionMap>(Reg, Pos);
- } else if (const auto Sym = Val.getAsSymbol()) {
- return State->set<IteratorSymbolMap>(Sym, Pos);
- } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
- return State->set<IteratorRegionMap>(LCVal->getRegion(), Pos);
+// This function tells the analyzer's engine that symbols produced by our
+// checker, most notably iterator positions, are relatively small.
+// A distance between items in the container should not be very large.
+// By assuming that it is within around 1/8 of the address space,
+// we can help the analyzer perform operations on these symbols
+// without being afraid of integer overflows.
+// FIXME: Should we provide it as an API, so that all checkers could use it?
+ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym,
+ long Scale) {
+ SValBuilder &SVB = State->getStateManager().getSValBuilder();
+ BasicValueFactory &BV = SVB.getBasicValueFactory();
+
+ QualType T = Sym->getType();
+ assert(T->isSignedIntegerOrEnumerationType());
+ APSIntType AT = BV.getAPSIntType(T);
+
+ ProgramStateRef NewState = State;
+
+ llvm::APSInt Max = AT.getMaxValue() / AT.getValue(Scale);
+ SVal IsCappedFromAbove =
+ SVB.evalBinOpNN(State, BO_LE, nonloc::SymbolVal(Sym),
+ nonloc::ConcreteInt(Max), SVB.getConditionType());
+ if (auto DV = IsCappedFromAbove.getAs<DefinedSVal>()) {
+ NewState = NewState->assume(*DV, true);
+ if (!NewState)
+ return State;
}
- return nullptr;
-}
-ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val) {
- if (auto Reg = Val.getAsRegion()) {
- Reg = Reg->getMostDerivedObjectRegion();
- return State->remove<IteratorRegionMap>(Reg);
- } else if (const auto Sym = Val.getAsSymbol()) {
- return State->remove<IteratorSymbolMap>(Sym);
- } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
- return State->remove<IteratorRegionMap>(LCVal->getRegion());
+ llvm::APSInt Min = -Max;
+ SVal IsCappedFromBelow =
+ SVB.evalBinOpNN(State, BO_GE, nonloc::SymbolVal(Sym),
+ nonloc::ConcreteInt(Min), SVB.getConditionType());
+ if (auto DV = IsCappedFromBelow.getAs<DefinedSVal>()) {
+ NewState = NewState->assume(*DV, true);
+ if (!NewState)
+ return State;
}
- return nullptr;
+
+ return NewState;
}
ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1,
@@ -2067,13 +1456,13 @@ ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1,
bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont) {
auto RegionMap = State->get<IteratorRegionMap>();
- for (const auto Reg : RegionMap) {
+ for (const auto &Reg : RegionMap) {
if (Reg.second.getContainer() == Cont)
return true;
}
auto SymbolMap = State->get<IteratorSymbolMap>();
- for (const auto Sym : SymbolMap) {
+ for (const auto &Sym : SymbolMap) {
if (Sym.second.getContainer() == Cont)
return true;
}
@@ -2083,7 +1472,7 @@ bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont) {
bool isBoundThroughLazyCompoundVal(const Environment &Env,
const MemRegion *Reg) {
- for (const auto Binding: Env) {
+ for (const auto &Binding : Env) {
if (const auto LCVal = Binding.second.getAs<nonloc::LazyCompoundVal>()) {
if (LCVal->getRegion() == Reg)
return true;
@@ -2093,54 +1482,13 @@ bool isBoundThroughLazyCompoundVal(const Environment &Env,
return false;
}
-// This function tells the analyzer's engine that symbols produced by our
-// checker, most notably iterator positions, are relatively small.
-// A distance between items in the container should not be very large.
-// By assuming that it is within around 1/8 of the address space,
-// we can help the analyzer perform operations on these symbols
-// without being afraid of integer overflows.
-// FIXME: Should we provide it as an API, so that all checkers could use it?
-ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym,
- long Scale) {
- SValBuilder &SVB = State->getStateManager().getSValBuilder();
- BasicValueFactory &BV = SVB.getBasicValueFactory();
-
- QualType T = Sym->getType();
- assert(T->isSignedIntegerOrEnumerationType());
- APSIntType AT = BV.getAPSIntType(T);
-
- ProgramStateRef NewState = State;
-
- llvm::APSInt Max = AT.getMaxValue() / AT.getValue(Scale);
- SVal IsCappedFromAbove =
- SVB.evalBinOpNN(State, BO_LE, nonloc::SymbolVal(Sym),
- nonloc::ConcreteInt(Max), SVB.getConditionType());
- if (auto DV = IsCappedFromAbove.getAs<DefinedSVal>()) {
- NewState = NewState->assume(*DV, true);
- if (!NewState)
- return State;
- }
-
- llvm::APSInt Min = -Max;
- SVal IsCappedFromBelow =
- SVB.evalBinOpNN(State, BO_GE, nonloc::SymbolVal(Sym),
- nonloc::ConcreteInt(Min), SVB.getConditionType());
- if (auto DV = IsCappedFromBelow.getAs<DefinedSVal>()) {
- NewState = NewState->assume(*DV, true);
- if (!NewState)
- return State;
- }
-
- return NewState;
-}
-
template <typename Condition, typename Process>
ProgramStateRef processIteratorPositions(ProgramStateRef State, Condition Cond,
Process Proc) {
auto &RegionMapFactory = State->get_context<IteratorRegionMap>();
auto RegionMap = State->get<IteratorRegionMap>();
bool Changed = false;
- for (const auto Reg : RegionMap) {
+ for (const auto &Reg : RegionMap) {
if (Cond(Reg.second)) {
RegionMap = RegionMapFactory.add(RegionMap, Reg.first, Proc(Reg.second));
Changed = true;
@@ -2153,7 +1501,7 @@ ProgramStateRef processIteratorPositions(ProgramStateRef State, Condition Cond,
auto &SymbolMapFactory = State->get_context<IteratorSymbolMap>();
auto SymbolMap = State->get<IteratorSymbolMap>();
Changed = false;
- for (const auto Sym : SymbolMap) {
+ for (const auto &Sym : SymbolMap) {
if (Cond(Sym.second)) {
SymbolMap = SymbolMapFactory.add(SymbolMap, Sym.first, Proc(Sym.second));
Changed = true;
@@ -2280,111 +1628,12 @@ SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB,
SymMgr.getType(OrigExpr)).getAsSymbol();
}
-bool isZero(ProgramStateRef State, const NonLoc &Val) {
- auto &BVF = State->getBasicVals();
- return compare(State, Val,
- nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))),
- BO_EQ);
-}
-
-bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
- const auto *Cont = Pos.getContainer();
- const auto *CData = getContainerData(State, Cont);
- if (!CData)
- return false;
-
- const auto End = CData->getEnd();
- if (End) {
- if (isEqual(State, Pos.getOffset(), End)) {
- return true;
- }
- }
-
- return false;
-}
-
-bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos) {
- const auto *Cont = Pos.getContainer();
- const auto *CData = getContainerData(State, Cont);
- if (!CData)
- return false;
-
- const auto Beg = CData->getBegin();
- if (Beg) {
- if (isLess(State, Pos.getOffset(), Beg)) {
- return true;
- }
- }
-
- return false;
-}
-
-bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
- const auto *Cont = Pos.getContainer();
- const auto *CData = getContainerData(State, Cont);
- if (!CData)
- return false;
-
- const auto End = CData->getEnd();
- if (End) {
- if (isGreater(State, Pos.getOffset(), End)) {
- return true;
- }
- }
-
- return false;
-}
-
-bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
- return compare(State, Sym1, Sym2, BO_LT);
-}
-
-bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
- return compare(State, Sym1, Sym2, BO_GT);
-}
-
-bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
- return compare(State, Sym1, Sym2, BO_EQ);
-}
-
-bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
- BinaryOperator::Opcode Opc) {
- return compare(State, nonloc::SymbolVal(Sym1), nonloc::SymbolVal(Sym2), Opc);
-}
-
-bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
- BinaryOperator::Opcode Opc) {
- auto &SVB = State->getStateManager().getSValBuilder();
-
- const auto comparison =
- SVB.evalBinOp(State, Opc, NL1, NL2, SVB.getConditionType());
-
- assert(comparison.getAs<DefinedSVal>() &&
- "Symbol comparison must be a `DefinedSVal`");
-
- return !State->assume(comparison.castAs<DefinedSVal>(), false);
-}
-
} // namespace
void ento::registerIteratorModeling(CheckerManager &mgr) {
- mgr.registerChecker<IteratorChecker>();
+ mgr.registerChecker<IteratorModeling>();
}
bool ento::shouldRegisterIteratorModeling(const LangOptions &LO) {
return true;
}
-
-#define REGISTER_CHECKER(name) \
- void ento::register##name(CheckerManager &Mgr) { \
- auto *checker = Mgr.getChecker<IteratorChecker>(); \
- checker->ChecksEnabled[IteratorChecker::CK_##name] = true; \
- checker->CheckNames[IteratorChecker::CK_##name] = \
- Mgr.getCurrentCheckerName(); \
- } \
- \
- bool ento::shouldRegister##name(const LangOptions &LO) { return true; }
-
-REGISTER_CHECKER(IteratorRangeChecker)
-REGISTER_CHECKER(MismatchedIteratorChecker)
-REGISTER_CHECKER(InvalidatedIteratorChecker)
diff --git a/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
new file mode 100644
index 000000000000..bd8b84d464b6
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
@@ -0,0 +1,273 @@
+//===-- IteratorRangeChecker.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
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines a checker for dereference of the past-the-end iterator and
+// out-of-range increments and decrements.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+
+#include "Iterator.h"
+
+using namespace clang;
+using namespace ento;
+using namespace iterator;
+
+namespace {
+
+class IteratorRangeChecker
+ : public Checker<check::PreCall> {
+
+ std::unique_ptr<BugType> OutOfRangeBugType;
+
+ void verifyDereference(CheckerContext &C, const SVal &Val) const;
+ void verifyIncrement(CheckerContext &C, const SVal &Iter) const;
+ void verifyDecrement(CheckerContext &C, const SVal &Iter) const;
+ void verifyRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op,
+ const SVal &LHS, const SVal &RHS) const;
+ void reportBug(const StringRef &Message, const SVal &Val,
+ CheckerContext &C, ExplodedNode *ErrNode) const;
+public:
+ IteratorRangeChecker();
+
+ void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+
+};
+
+bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
+bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos);
+bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
+bool isZero(ProgramStateRef State, const NonLoc &Val);
+
+} //namespace
+
+IteratorRangeChecker::IteratorRangeChecker() {
+ OutOfRangeBugType.reset(
+ new BugType(this, "Iterator out of range", "Misuse of STL APIs"));
+}
+
+void IteratorRangeChecker::checkPreCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ // Check for out of range access
+ const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
+ if (!Func)
+ return;
+
+ if (Func->isOverloadedOperator()) {
+ if (isIncrementOperator(Func->getOverloadedOperator())) {
+ // Check for out-of-range incrementions
+ if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+ verifyIncrement(C, InstCall->getCXXThisVal());
+ } else {
+ if (Call.getNumArgs() >= 1) {
+ verifyIncrement(C, Call.getArgSVal(0));
+ }
+ }
+ } else if (isDecrementOperator(Func->getOverloadedOperator())) {
+ // Check for out-of-range decrementions
+ if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+ verifyDecrement(C, InstCall->getCXXThisVal());
+ } else {
+ if (Call.getNumArgs() >= 1) {
+ verifyDecrement(C, Call.getArgSVal(0));
+ }
+ }
+ } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
+ if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+ // Check for out-of-range incrementions and decrementions
+ if (Call.getNumArgs() >= 1 &&
+ Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
+ verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
+ InstCall->getCXXThisVal(),
+ Call.getArgSVal(0));
+ }
+ } else {
+ if (Call.getNumArgs() >= 2 &&
+ Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
+ verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
+ Call.getArgSVal(0), Call.getArgSVal(1));
+ }
+ }
+ } else if (isDereferenceOperator(Func->getOverloadedOperator())) {
+ // Check for dereference of out-of-range iterators
+ if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+ verifyDereference(C, InstCall->getCXXThisVal());
+ } else {
+ verifyDereference(C, Call.getArgSVal(0));
+ }
+ }
+ }
+}
+
+void IteratorRangeChecker::verifyDereference(CheckerContext &C,
+ const SVal &Val) const {
+ auto State = C.getState();
+ const auto *Pos = getIteratorPosition(State, Val);
+ if (Pos && isPastTheEnd(State, *Pos)) {
+ auto *N = C.generateErrorNode(State);
+ if (!N)
+ return;
+ reportBug("Past-the-end iterator dereferenced.", Val, C, N);
+ return;
+ }
+}
+
+void IteratorRangeChecker::verifyIncrement(CheckerContext &C,
+ const SVal &Iter) const {
+ auto &BVF = C.getSValBuilder().getBasicValueFactory();
+ verifyRandomIncrOrDecr(C, OO_Plus, Iter,
+ nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
+}
+
+void IteratorRangeChecker::verifyDecrement(CheckerContext &C,
+ const SVal &Iter) const {
+ auto &BVF = C.getSValBuilder().getBasicValueFactory();
+ verifyRandomIncrOrDecr(C, OO_Minus, Iter,
+ nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
+}
+
+void IteratorRangeChecker::verifyRandomIncrOrDecr(CheckerContext &C,
+ OverloadedOperatorKind Op,
+ const SVal &LHS,
+ const SVal &RHS) const {
+ auto State = C.getState();
+
+ auto Value = RHS;
+ if (auto ValAsLoc = RHS.getAs<Loc>()) {
+ Value = State->getRawSVal(*ValAsLoc);
+ }
+
+ if (Value.isUnknown())
+ return;
+
+ // Incremention or decremention by 0 is never a bug.
+ if (isZero(State, Value.castAs<NonLoc>()))
+ return;
+
+ // The result may be the past-end iterator of the container, but any other
+ // out of range position is undefined behaviour
+ auto StateAfter = advancePosition(State, LHS, Op, Value);
+ if (!StateAfter)
+ return;
+
+ const auto *PosAfter = getIteratorPosition(StateAfter, LHS);
+ assert(PosAfter &&
+ "Iterator should have position after successful advancement");
+ if (isAheadOfRange(State, *PosAfter)) {
+ auto *N = C.generateErrorNode(State);
+ if (!N)
+ return;
+ reportBug("Iterator decremented ahead of its valid range.", LHS,
+ C, N);
+ }
+ if (isBehindPastTheEnd(State, *PosAfter)) {
+ auto *N = C.generateErrorNode(State);
+ if (!N)
+ return;
+ reportBug("Iterator incremented behind the past-the-end "
+ "iterator.", LHS, C, N);
+ }
+}
+
+void IteratorRangeChecker::reportBug(const StringRef &Message,
+ const SVal &Val, CheckerContext &C,
+ ExplodedNode *ErrNode) const {
+ auto R = std::make_unique<PathSensitiveBugReport>(*OutOfRangeBugType, Message,
+ ErrNode);
+ R->markInteresting(Val);
+ C.emitReport(std::move(R));
+}
+
+namespace {
+
+bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
+bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
+bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
+
+bool isZero(ProgramStateRef State, const NonLoc &Val) {
+ auto &BVF = State->getBasicVals();
+ return compare(State, Val,
+ nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))),
+ BO_EQ);
+}
+
+bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
+ const auto *Cont = Pos.getContainer();
+ const auto *CData = getContainerData(State, Cont);
+ if (!CData)
+ return false;
+
+ const auto End = CData->getEnd();
+ if (End) {
+ if (isEqual(State, Pos.getOffset(), End)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos) {
+ const auto *Cont = Pos.getContainer();
+ const auto *CData = getContainerData(State, Cont);
+ if (!CData)
+ return false;
+
+ const auto Beg = CData->getBegin();
+ if (Beg) {
+ if (isLess(State, Pos.getOffset(), Beg)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
+ const auto *Cont = Pos.getContainer();
+ const auto *CData = getContainerData(State, Cont);
+ if (!CData)
+ return false;
+
+ const auto End = CData->getEnd();
+ if (End) {
+ if (isGreater(State, Pos.getOffset(), End)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
+ return compare(State, Sym1, Sym2, BO_LT);
+}
+
+bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
+ return compare(State, Sym1, Sym2, BO_GT);
+}
+
+bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
+ return compare(State, Sym1, Sym2, BO_EQ);
+}
+
+} // namespace
+
+void ento::registerIteratorRangeChecker(CheckerManager &mgr) {
+ mgr.registerChecker<IteratorRangeChecker>();
+}
+
+bool ento::shouldRegisterIteratorRangeChecker(const LangOptions &LO) {
+ return true;
+}
diff --git a/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
index a81015b6e524..79de1844e745 100644
--- a/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
@@ -1077,7 +1077,10 @@ void EmptyLocalizationContextChecker::checkASTDecl(
AnalysisDeclContext *DCtx = Mgr.getAnalysisDeclContext(M);
const Stmt *Body = M->getBody();
- assert(Body);
+ if (!Body) {
+ assert(M->isSynthesizedAccessorStub());
+ continue;
+ }
MethodCrawler MC(M->getCanonicalDecl(), BR, this, Mgr, DCtx);
MC.VisitStmt(Body);
diff --git a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
index d8fd125f4003..d73e2eb92d42 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
@@ -21,6 +21,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/Attr.h"
#include "clang/Analysis/AnyCall.h"
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index d964a1668eaa..410721d8b6ff 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -14,8 +14,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/AST/Attr.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index a82449951873..09306383d53f 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -1469,6 +1469,9 @@ void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call,
if (!*FreeWhenDone)
return;
+ if (Call.hasNonZeroCallbackArg())
+ return;
+
bool IsKnownToBeAllocatedMemory;
ProgramStateRef State =
FreeMemAux(C, Call.getArgExpr(0), Call.getOriginExpr(), C.getState(),
@@ -2525,19 +2528,18 @@ MallocChecker::LeakInfo MallocChecker::getAllocationSite(const ExplodedNode *N,
// Find the most recent expression bound to the symbol in the current
// context.
- if (!ReferenceRegion) {
- if (const MemRegion *MR = C.getLocationRegionIfPostStore(N)) {
- SVal Val = State->getSVal(MR);
- if (Val.getAsLocSymbol() == Sym) {
- const VarRegion* VR = MR->getBaseRegion()->getAs<VarRegion>();
- // Do not show local variables belonging to a function other than
- // where the error is reported.
- if (!VR ||
- (VR->getStackFrame() == LeakContext->getStackFrame()))
- ReferenceRegion = MR;
- }
+ if (!ReferenceRegion) {
+ if (const MemRegion *MR = C.getLocationRegionIfPostStore(N)) {
+ SVal Val = State->getSVal(MR);
+ if (Val.getAsLocSymbol() == Sym) {
+ const VarRegion *VR = MR->getBaseRegion()->getAs<VarRegion>();
+ // Do not show local variables belonging to a function other than
+ // where the error is reported.
+ if (!VR || (VR->getStackFrame() == LeakContext->getStackFrame()))
+ ReferenceRegion = MR;
}
}
+ }
// Allocation node, is the last node in the current or parent context in
// which the symbol was tracked.
diff --git a/clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp
new file mode 100644
index 000000000000..143910588959
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp
@@ -0,0 +1,295 @@
+//===-- MismatchedIteratorChecker.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
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines a checker for mistakenly applying a foreign iterator on a container
+// and for using iterators of two different containers in a context where
+// iterators of the same container should be used.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+
+#include "Iterator.h"
+
+using namespace clang;
+using namespace ento;
+using namespace iterator;
+
+namespace {
+
+class MismatchedIteratorChecker
+ : public Checker<check::PreCall> {
+
+ std::unique_ptr<BugType> MismatchedBugType;
+
+ void verifyMatch(CheckerContext &C, const SVal &Iter,
+ const MemRegion *Cont) const;
+ void verifyMatch(CheckerContext &C, const SVal &Iter1,
+ const SVal &Iter2) const;
+ void reportBug(const StringRef &Message, const SVal &Val1,
+ const SVal &Val2, CheckerContext &C,
+ ExplodedNode *ErrNode) const;
+ void reportBug(const StringRef &Message, const SVal &Val,
+ const MemRegion *Reg, CheckerContext &C,
+ ExplodedNode *ErrNode) const;
+
+public:
+ MismatchedIteratorChecker();
+
+ void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+
+};
+
+} // namespace
+
+MismatchedIteratorChecker::MismatchedIteratorChecker() {
+ MismatchedBugType.reset(
+ new BugType(this, "Iterator(s) mismatched", "Misuse of STL APIs",
+ /*SuppressOnSink=*/true));
+}
+
+void MismatchedIteratorChecker::checkPreCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ // Check for iterator mismatches
+ const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
+ if (!Func)
+ return;
+
+ if (Func->isOverloadedOperator() &&
+ isComparisonOperator(Func->getOverloadedOperator())) {
+ // Check for comparisons of iterators of different containers
+ if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+ if (Call.getNumArgs() < 1)
+ return;
+
+ if (!isIteratorType(InstCall->getCXXThisExpr()->getType()) ||
+ !isIteratorType(Call.getArgExpr(0)->getType()))
+ return;
+
+ verifyMatch(C, InstCall->getCXXThisVal(), Call.getArgSVal(0));
+ } else {
+ if (Call.getNumArgs() < 2)
+ return;
+
+ if (!isIteratorType(Call.getArgExpr(0)->getType()) ||
+ !isIteratorType(Call.getArgExpr(1)->getType()))
+ return;
+
+ verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1));
+ }
+ } else if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+ const auto *ContReg = InstCall->getCXXThisVal().getAsRegion();
+ if (!ContReg)
+ return;
+ // Check for erase, insert and emplace using iterator of another container
+ if (isEraseCall(Func) || isEraseAfterCall(Func)) {
+ verifyMatch(C, Call.getArgSVal(0),
+ InstCall->getCXXThisVal().getAsRegion());
+ if (Call.getNumArgs() == 2) {
+ verifyMatch(C, Call.getArgSVal(1),
+ InstCall->getCXXThisVal().getAsRegion());
+ }
+ } else if (isInsertCall(Func)) {
+ verifyMatch(C, Call.getArgSVal(0),
+ InstCall->getCXXThisVal().getAsRegion());
+ if (Call.getNumArgs() == 3 &&
+ isIteratorType(Call.getArgExpr(1)->getType()) &&
+ isIteratorType(Call.getArgExpr(2)->getType())) {
+ verifyMatch(C, Call.getArgSVal(1), Call.getArgSVal(2));
+ }
+ } else if (isEmplaceCall(Func)) {
+ verifyMatch(C, Call.getArgSVal(0),
+ InstCall->getCXXThisVal().getAsRegion());
+ }
+ } else if (isa<CXXConstructorCall>(&Call)) {
+ // Check match of first-last iterator pair in a constructor of a container
+ if (Call.getNumArgs() < 2)
+ return;
+
+ const auto *Ctr = cast<CXXConstructorDecl>(Call.getDecl());
+ if (Ctr->getNumParams() < 2)
+ return;
+
+ if (Ctr->getParamDecl(0)->getName() != "first" ||
+ Ctr->getParamDecl(1)->getName() != "last")
+ return;
+
+ if (!isIteratorType(Call.getArgExpr(0)->getType()) ||
+ !isIteratorType(Call.getArgExpr(1)->getType()))
+ return;
+
+ verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1));
+ } else {
+ // The main purpose of iterators is to abstract away from different
+ // containers and provide a (maybe limited) uniform access to them.
+ // This implies that any correctly written template function that
+ // works on multiple containers using iterators takes different
+ // template parameters for different containers. So we can safely
+ // assume that passing iterators of different containers as arguments
+ // whose type replaces the same template parameter is a bug.
+ //
+ // Example:
+ // template<typename I1, typename I2>
+ // void f(I1 first1, I1 last1, I2 first2, I2 last2);
+ //
+ // In this case the first two arguments to f() must be iterators must belong
+ // to the same container and the last to also to the same container but
+ // not necessarily to the same as the first two.
+
+ const auto *Templ = Func->getPrimaryTemplate();
+ if (!Templ)
+ return;
+
+ const auto *TParams = Templ->getTemplateParameters();
+ const auto *TArgs = Func->getTemplateSpecializationArgs();
+
+ // Iterate over all the template parameters
+ for (size_t I = 0; I < TParams->size(); ++I) {
+ const auto *TPDecl = dyn_cast<TemplateTypeParmDecl>(TParams->getParam(I));
+ if (!TPDecl)
+ continue;
+
+ if (TPDecl->isParameterPack())
+ continue;
+
+ const auto TAType = TArgs->get(I).getAsType();
+ if (!isIteratorType(TAType))
+ continue;
+
+ SVal LHS = UndefinedVal();
+
+ // For every template parameter which is an iterator type in the
+ // instantiation look for all functions' parameters' type by it and
+ // check whether they belong to the same container
+ for (auto J = 0U; J < Func->getNumParams(); ++J) {
+ const auto *Param = Func->getParamDecl(J);
+ const auto *ParamType =
+ Param->getType()->getAs<SubstTemplateTypeParmType>();
+ if (!ParamType ||
+ ParamType->getReplacedParameter()->getDecl() != TPDecl)
+ continue;
+ if (LHS.isUndef()) {
+ LHS = Call.getArgSVal(J);
+ } else {
+ verifyMatch(C, LHS, Call.getArgSVal(J));
+ }
+ }
+ }
+ }
+}
+
+void MismatchedIteratorChecker::verifyMatch(CheckerContext &C, const SVal &Iter,
+ const MemRegion *Cont) const {
+ // Verify match between a container and the container of an iterator
+ Cont = Cont->getMostDerivedObjectRegion();
+
+ if (const auto *ContSym = Cont->getSymbolicBase()) {
+ if (isa<SymbolConjured>(ContSym->getSymbol()))
+ return;
+ }
+
+ auto State = C.getState();
+ const auto *Pos = getIteratorPosition(State, Iter);
+ if (!Pos)
+ return;
+
+ const auto *IterCont = Pos->getContainer();
+
+ // Skip symbolic regions based on conjured symbols. Two conjured symbols
+ // may or may not be the same. For example, the same function can return
+ // the same or a different container but we get different conjured symbols
+ // for each call. This may cause false positives so omit them from the check.
+ if (const auto *ContSym = IterCont->getSymbolicBase()) {
+ if (isa<SymbolConjured>(ContSym->getSymbol()))
+ return;
+ }
+
+ if (IterCont != Cont) {
+ auto *N = C.generateNonFatalErrorNode(State);
+ if (!N) {
+ return;
+ }
+ reportBug("Container accessed using foreign iterator argument.",
+ Iter, Cont, C, N);
+ }
+}
+
+void MismatchedIteratorChecker::verifyMatch(CheckerContext &C,
+ const SVal &Iter1,
+ const SVal &Iter2) const {
+ // Verify match between the containers of two iterators
+ auto State = C.getState();
+ const auto *Pos1 = getIteratorPosition(State, Iter1);
+ if (!Pos1)
+ return;
+
+ const auto *IterCont1 = Pos1->getContainer();
+
+ // Skip symbolic regions based on conjured symbols. Two conjured symbols
+ // may or may not be the same. For example, the same function can return
+ // the same or a different container but we get different conjured symbols
+ // for each call. This may cause false positives so omit them from the check.
+ if (const auto *ContSym = IterCont1->getSymbolicBase()) {
+ if (isa<SymbolConjured>(ContSym->getSymbol()))
+ return;
+ }
+
+ const auto *Pos2 = getIteratorPosition(State, Iter2);
+ if (!Pos2)
+ return;
+
+ const auto *IterCont2 = Pos2->getContainer();
+ if (const auto *ContSym = IterCont2->getSymbolicBase()) {
+ if (isa<SymbolConjured>(ContSym->getSymbol()))
+ return;
+ }
+
+ if (IterCont1 != IterCont2) {
+ auto *N = C.generateNonFatalErrorNode(State);
+ if (!N)
+ return;
+ reportBug("Iterators of different containers used where the "
+ "same container is expected.", Iter1, Iter2, C, N);
+ }
+}
+
+void MismatchedIteratorChecker::reportBug(const StringRef &Message,
+ const SVal &Val1,
+ const SVal &Val2,
+ CheckerContext &C,
+ ExplodedNode *ErrNode) const {
+ auto R = std::make_unique<PathSensitiveBugReport>(*MismatchedBugType, Message,
+ ErrNode);
+ R->markInteresting(Val1);
+ R->markInteresting(Val2);
+ C.emitReport(std::move(R));
+}
+
+void MismatchedIteratorChecker::reportBug(const StringRef &Message,
+ const SVal &Val, const MemRegion *Reg,
+ CheckerContext &C,
+ ExplodedNode *ErrNode) const {
+ auto R = std::make_unique<PathSensitiveBugReport>(*MismatchedBugType, Message,
+ ErrNode);
+ R->markInteresting(Val);
+ R->markInteresting(Reg);
+ C.emitReport(std::move(R));
+}
+
+void ento::registerMismatchedIteratorChecker(CheckerManager &mgr) {
+ mgr.registerChecker<MismatchedIteratorChecker>();
+}
+
+bool ento::shouldRegisterMismatchedIteratorChecker(const LangOptions &LO) {
+ return true;
+}
diff --git a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
index 1473c05d7e3f..40eb113e3f8e 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
@@ -12,6 +12,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/Attr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
@@ -685,7 +686,7 @@ void MoveChecker::checkDeadSymbols(SymbolReaper &SymReaper,
CheckerContext &C) const {
ProgramStateRef State = C.getState();
TrackedRegionMapTy TrackedRegions = State->get<TrackedRegionMap>();
- for (TrackedRegionMapTy::value_type E : TrackedRegions) {
+ for (auto E : TrackedRegions) {
const MemRegion *Region = E.first;
bool IsRegDead = !SymReaper.isLiveRegion(Region);
diff --git a/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp
index 43dbe57b8432..6efba433eed2 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp
@@ -36,6 +36,7 @@ class NonnullGlobalConstantsChecker : public Checker<check::Location> {
mutable IdentifierInfo *NSStringII = nullptr;
mutable IdentifierInfo *CFStringRefII = nullptr;
mutable IdentifierInfo *CFBooleanRefII = nullptr;
+ mutable IdentifierInfo *CFNullRefII = nullptr;
public:
NonnullGlobalConstantsChecker() {}
@@ -61,6 +62,7 @@ void NonnullGlobalConstantsChecker::initIdentifierInfo(ASTContext &Ctx) const {
NSStringII = &Ctx.Idents.get("NSString");
CFStringRefII = &Ctx.Idents.get("CFStringRef");
CFBooleanRefII = &Ctx.Idents.get("CFBooleanRef");
+ CFNullRefII = &Ctx.Idents.get("CFNullRef");
}
/// Add an assumption that const string-like globals are non-null.
@@ -136,7 +138,7 @@ bool NonnullGlobalConstantsChecker::isNonnullType(QualType Ty) const {
T->getInterfaceDecl()->getIdentifier() == NSStringII;
} else if (auto *T = dyn_cast<TypedefType>(Ty)) {
IdentifierInfo* II = T->getDecl()->getIdentifier();
- return II == CFStringRefII || II == CFBooleanRefII;
+ return II == CFStringRefII || II == CFBooleanRefII || II == CFNullRefII;
}
return false;
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
index 4322ac207112..922048733c7c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
@@ -728,11 +728,6 @@ void NullabilityChecker::checkPreCall(const CallEvent &Call,
}
continue;
}
- // No tracked nullability yet.
- if (ArgExprTypeLevelNullability != Nullability::Nullable)
- continue;
- State = State->set<NullabilityMap>(
- Region, NullabilityState(ArgExprTypeLevelNullability, ArgExpr));
}
if (State != OrigState)
C.addTransition(State);
diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index c254408351c8..47099f2afb6a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -19,84 +19,90 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+#include <functional>
using namespace clang;
using namespace ento;
+using namespace std::placeholders;
namespace {
struct StreamState {
enum Kind { Opened, Closed, OpenFailed, Escaped } K;
- const Stmt *S;
- StreamState(Kind k, const Stmt *s) : K(k), S(s) {}
+ StreamState(Kind k) : K(k) {}
bool isOpened() const { return K == Opened; }
bool isClosed() const { return K == Closed; }
//bool isOpenFailed() const { return K == OpenFailed; }
//bool isEscaped() const { return K == Escaped; }
- bool operator==(const StreamState &X) const {
- return K == X.K && S == X.S;
- }
+ bool operator==(const StreamState &X) const { return K == X.K; }
- static StreamState getOpened(const Stmt *s) { return StreamState(Opened, s); }
- static StreamState getClosed(const Stmt *s) { return StreamState(Closed, s); }
- static StreamState getOpenFailed(const Stmt *s) {
- return StreamState(OpenFailed, s);
- }
- static StreamState getEscaped(const Stmt *s) {
- return StreamState(Escaped, s);
- }
+ static StreamState getOpened() { return StreamState(Opened); }
+ static StreamState getClosed() { return StreamState(Closed); }
+ static StreamState getOpenFailed() { return StreamState(OpenFailed); }
+ static StreamState getEscaped() { return StreamState(Escaped); }
void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger(K);
- ID.AddPointer(S);
}
};
class StreamChecker : public Checker<eval::Call,
check::DeadSymbols > {
- mutable IdentifierInfo *II_fopen, *II_tmpfile, *II_fclose, *II_fread,
- *II_fwrite,
- *II_fseek, *II_ftell, *II_rewind, *II_fgetpos, *II_fsetpos,
- *II_clearerr, *II_feof, *II_ferror, *II_fileno;
mutable std::unique_ptr<BuiltinBug> BT_nullfp, BT_illegalwhence,
BT_doubleclose, BT_ResourceLeak;
public:
- StreamChecker()
- : II_fopen(nullptr), II_tmpfile(nullptr), II_fclose(nullptr),
- II_fread(nullptr), II_fwrite(nullptr), II_fseek(nullptr),
- II_ftell(nullptr), II_rewind(nullptr), II_fgetpos(nullptr),
- II_fsetpos(nullptr), II_clearerr(nullptr), II_feof(nullptr),
- II_ferror(nullptr), II_fileno(nullptr) {}
-
bool evalCall(const CallEvent &Call, CheckerContext &C) const;
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
private:
- void Fopen(CheckerContext &C, const CallExpr *CE) const;
- void Tmpfile(CheckerContext &C, const CallExpr *CE) const;
- void Fclose(CheckerContext &C, const CallExpr *CE) const;
- void Fread(CheckerContext &C, const CallExpr *CE) const;
- void Fwrite(CheckerContext &C, const CallExpr *CE) const;
- void Fseek(CheckerContext &C, const CallExpr *CE) const;
- void Ftell(CheckerContext &C, const CallExpr *CE) const;
- void Rewind(CheckerContext &C, const CallExpr *CE) const;
- void Fgetpos(CheckerContext &C, const CallExpr *CE) const;
- void Fsetpos(CheckerContext &C, const CallExpr *CE) const;
- void Clearerr(CheckerContext &C, const CallExpr *CE) const;
- void Feof(CheckerContext &C, const CallExpr *CE) const;
- void Ferror(CheckerContext &C, const CallExpr *CE) const;
- void Fileno(CheckerContext &C, const CallExpr *CE) const;
+ using FnCheck = std::function<void(const StreamChecker *, const CallEvent &,
+ CheckerContext &)>;
- void OpenFileAux(CheckerContext &C, const CallExpr *CE) const;
+ CallDescriptionMap<FnCheck> Callbacks = {
+ {{"fopen"}, &StreamChecker::evalFopen},
+ {{"freopen", 3}, &StreamChecker::evalFreopen},
+ {{"tmpfile"}, &StreamChecker::evalFopen},
+ {{"fclose", 1}, &StreamChecker::evalFclose},
+ {{"fread", 4},
+ std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 3)},
+ {{"fwrite", 4},
+ std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 3)},
+ {{"fseek", 3}, &StreamChecker::evalFseek},
+ {{"ftell", 1},
+ std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)},
+ {{"rewind", 1},
+ std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)},
+ {{"fgetpos", 2},
+ std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)},
+ {{"fsetpos", 2},
+ std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)},
+ {{"clearerr", 1},
+ std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)},
+ {{"feof", 1},
+ std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)},
+ {{"ferror", 1},
+ std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)},
+ {{"fileno", 1},
+ std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)},
+ };
- ProgramStateRef CheckNullStream(SVal SV, ProgramStateRef state,
- CheckerContext &C) const;
- ProgramStateRef CheckDoubleClose(const CallExpr *CE, ProgramStateRef state,
- CheckerContext &C) const;
+ void evalFopen(const CallEvent &Call, CheckerContext &C) const;
+ void evalFreopen(const CallEvent &Call, CheckerContext &C) const;
+ void evalFclose(const CallEvent &Call, CheckerContext &C) const;
+ void evalFseek(const CallEvent &Call, CheckerContext &C) const;
+
+ void checkArgNullStream(const CallEvent &Call, CheckerContext &C,
+ unsigned ArgI) const;
+ bool checkNullStream(SVal SV, CheckerContext &C,
+ ProgramStateRef &State) const;
+ void checkFseekWhence(SVal SV, CheckerContext &C,
+ ProgramStateRef &State) const;
+ bool checkDoubleClose(const CallEvent &Call, CheckerContext &C,
+ ProgramStateRef &State) const;
};
} // end anonymous namespace
@@ -109,115 +115,36 @@ bool StreamChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {
if (!FD || FD->getKind() != Decl::Function)
return false;
- const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
- if (!CE)
+ // Recognize "global C functions" with only integral or pointer arguments
+ // (and matching name) as stream functions.
+ if (!Call.isGlobalCFunction())
return false;
-
- ASTContext &Ctx = C.getASTContext();
- if (!II_fopen)
- II_fopen = &Ctx.Idents.get("fopen");
- if (!II_tmpfile)
- II_tmpfile = &Ctx.Idents.get("tmpfile");
- if (!II_fclose)
- II_fclose = &Ctx.Idents.get("fclose");
- if (!II_fread)
- II_fread = &Ctx.Idents.get("fread");
- if (!II_fwrite)
- II_fwrite = &Ctx.Idents.get("fwrite");
- if (!II_fseek)
- II_fseek = &Ctx.Idents.get("fseek");
- if (!II_ftell)
- II_ftell = &Ctx.Idents.get("ftell");
- if (!II_rewind)
- II_rewind = &Ctx.Idents.get("rewind");
- if (!II_fgetpos)
- II_fgetpos = &Ctx.Idents.get("fgetpos");
- if (!II_fsetpos)
- II_fsetpos = &Ctx.Idents.get("fsetpos");
- if (!II_clearerr)
- II_clearerr = &Ctx.Idents.get("clearerr");
- if (!II_feof)
- II_feof = &Ctx.Idents.get("feof");
- if (!II_ferror)
- II_ferror = &Ctx.Idents.get("ferror");
- if (!II_fileno)
- II_fileno = &Ctx.Idents.get("fileno");
-
- if (FD->getIdentifier() == II_fopen) {
- Fopen(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_tmpfile) {
- Tmpfile(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_fclose) {
- Fclose(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_fread) {
- Fread(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_fwrite) {
- Fwrite(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_fseek) {
- Fseek(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_ftell) {
- Ftell(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_rewind) {
- Rewind(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_fgetpos) {
- Fgetpos(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_fsetpos) {
- Fsetpos(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_clearerr) {
- Clearerr(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_feof) {
- Feof(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_ferror) {
- Ferror(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_fileno) {
- Fileno(C, CE);
- return true;
+ for (auto P : Call.parameters()) {
+ QualType T = P->getType();
+ if (!T->isIntegralOrEnumerationType() && !T->isPointerType())
+ return false;
}
- return false;
-}
+ const FnCheck *Callback = Callbacks.lookup(Call);
+ if (!Callback)
+ return false;
-void StreamChecker::Fopen(CheckerContext &C, const CallExpr *CE) const {
- OpenFileAux(C, CE);
-}
+ (*Callback)(this, Call, C);
-void StreamChecker::Tmpfile(CheckerContext &C, const CallExpr *CE) const {
- OpenFileAux(C, CE);
+ return C.isDifferent();
}
-void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const {
+void StreamChecker::evalFopen(const CallEvent &Call, CheckerContext &C) const {
ProgramStateRef state = C.getState();
SValBuilder &svalBuilder = C.getSValBuilder();
const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
- DefinedSVal RetVal = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx,
- C.blockCount())
- .castAs<DefinedSVal>();
+ auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
+ if (!CE)
+ return;
+
+ DefinedSVal RetVal =
+ svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount())
+ .castAs<DefinedSVal>();
state = state->BindExpr(CE, C.getLocationContext(), RetVal);
ConstraintManager &CM = C.getConstraintManager();
@@ -226,145 +153,153 @@ void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const {
ProgramStateRef stateNotNull, stateNull;
std::tie(stateNotNull, stateNull) = CM.assumeDual(state, RetVal);
- if (SymbolRef Sym = RetVal.getAsSymbol()) {
- // if RetVal is not NULL, set the symbol's state to Opened.
- stateNotNull =
- stateNotNull->set<StreamMap>(Sym,StreamState::getOpened(CE));
- stateNull =
- stateNull->set<StreamMap>(Sym, StreamState::getOpenFailed(CE));
+ SymbolRef Sym = RetVal.getAsSymbol();
+ assert(Sym && "RetVal must be a symbol here.");
+ stateNotNull = stateNotNull->set<StreamMap>(Sym, StreamState::getOpened());
+ stateNull = stateNull->set<StreamMap>(Sym, StreamState::getOpenFailed());
- C.addTransition(stateNotNull);
- C.addTransition(stateNull);
- }
+ C.addTransition(stateNotNull);
+ C.addTransition(stateNull);
}
-void StreamChecker::Fclose(CheckerContext &C, const CallExpr *CE) const {
- ProgramStateRef state = CheckDoubleClose(CE, C.getState(), C);
- if (state)
- C.addTransition(state);
-}
+void StreamChecker::evalFreopen(const CallEvent &Call,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
-void StreamChecker::Fread(CheckerContext &C, const CallExpr *CE) const {
- ProgramStateRef state = C.getState();
- if (!CheckNullStream(C.getSVal(CE->getArg(3)), state, C))
+ auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
+ if (!CE)
return;
-}
-void StreamChecker::Fwrite(CheckerContext &C, const CallExpr *CE) const {
- ProgramStateRef state = C.getState();
- if (!CheckNullStream(C.getSVal(CE->getArg(3)), state, C))
+ Optional<DefinedSVal> StreamVal = Call.getArgSVal(2).getAs<DefinedSVal>();
+ if (!StreamVal)
return;
-}
-
-void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) const {
- ProgramStateRef state = C.getState();
- if (!(state = CheckNullStream(C.getSVal(CE->getArg(0)), state, C)))
+ // Do not allow NULL as passed stream pointer.
+ // This is not specified in the man page but may crash on some system.
+ checkNullStream(*StreamVal, C, State);
+ // Check if error was generated.
+ if (C.isDifferent())
return;
- // Check the legality of the 'whence' argument of 'fseek'.
- SVal Whence = state->getSVal(CE->getArg(2), C.getLocationContext());
- Optional<nonloc::ConcreteInt> CI = Whence.getAs<nonloc::ConcreteInt>();
- if (!CI)
+ SymbolRef StreamSym = StreamVal->getAsSymbol();
+ // Do not care about special values for stream ("(FILE *)0x12345"?).
+ if (!StreamSym)
return;
- int64_t x = CI->getValue().getSExtValue();
- if (x >= 0 && x <= 2)
- return;
+ // Generate state for non-failed case.
+ // Return value is the passed stream pointer.
+ // According to the documentations, the stream is closed first
+ // but any close error is ignored. The state changes to (or remains) opened.
+ ProgramStateRef StateRetNotNull =
+ State->BindExpr(CE, C.getLocationContext(), *StreamVal);
+ // Generate state for NULL return value.
+ // Stream switches to OpenFailed state.
+ ProgramStateRef StateRetNull = State->BindExpr(CE, C.getLocationContext(),
+ C.getSValBuilder().makeNull());
- if (ExplodedNode *N = C.generateNonFatalErrorNode(state)) {
- if (!BT_illegalwhence)
- BT_illegalwhence.reset(
- new BuiltinBug(this, "Illegal whence argument",
- "The whence argument to fseek() should be "
- "SEEK_SET, SEEK_END, or SEEK_CUR."));
- C.emitReport(std::make_unique<PathSensitiveBugReport>(
- *BT_illegalwhence, BT_illegalwhence->getDescription(), N));
- }
-}
+ StateRetNotNull =
+ StateRetNotNull->set<StreamMap>(StreamSym, StreamState::getOpened());
+ StateRetNull =
+ StateRetNull->set<StreamMap>(StreamSym, StreamState::getOpenFailed());
-void StreamChecker::Ftell(CheckerContext &C, const CallExpr *CE) const {
- ProgramStateRef state = C.getState();
- if (!CheckNullStream(C.getSVal(CE->getArg(0)), state, C))
- return;
+ C.addTransition(StateRetNotNull);
+ C.addTransition(StateRetNull);
}
-void StreamChecker::Rewind(CheckerContext &C, const CallExpr *CE) const {
- ProgramStateRef state = C.getState();
- if (!CheckNullStream(C.getSVal(CE->getArg(0)), state, C))
- return;
+void StreamChecker::evalFclose(const CallEvent &Call, CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ if (checkDoubleClose(Call, C, State))
+ C.addTransition(State);
}
-void StreamChecker::Fgetpos(CheckerContext &C, const CallExpr *CE) const {
- ProgramStateRef state = C.getState();
- if (!CheckNullStream(C.getSVal(CE->getArg(0)), state, C))
+void StreamChecker::evalFseek(const CallEvent &Call, CheckerContext &C) const {
+ const Expr *AE2 = Call.getArgExpr(2);
+ if (!AE2)
return;
-}
-void StreamChecker::Fsetpos(CheckerContext &C, const CallExpr *CE) const {
- ProgramStateRef state = C.getState();
- if (!CheckNullStream(C.getSVal(CE->getArg(0)), state, C))
- return;
-}
+ ProgramStateRef State = C.getState();
-void StreamChecker::Clearerr(CheckerContext &C, const CallExpr *CE) const {
- ProgramStateRef state = C.getState();
- if (!CheckNullStream(C.getSVal(CE->getArg(0)), state, C))
+ bool StateChanged = checkNullStream(Call.getArgSVal(0), C, State);
+ // Check if error was generated.
+ if (C.isDifferent())
return;
-}
-void StreamChecker::Feof(CheckerContext &C, const CallExpr *CE) const {
- ProgramStateRef state = C.getState();
- if (!CheckNullStream(C.getSVal(CE->getArg(0)), state, C))
- return;
-}
+ // Check the legality of the 'whence' argument of 'fseek'.
+ checkFseekWhence(State->getSVal(AE2, C.getLocationContext()), C, State);
-void StreamChecker::Ferror(CheckerContext &C, const CallExpr *CE) const {
- ProgramStateRef state = C.getState();
- if (!CheckNullStream(C.getSVal(CE->getArg(0)), state, C))
- return;
+ if (!C.isDifferent() && StateChanged)
+ C.addTransition(State);
+
+ return;
}
-void StreamChecker::Fileno(CheckerContext &C, const CallExpr *CE) const {
- ProgramStateRef state = C.getState();
- if (!CheckNullStream(C.getSVal(CE->getArg(0)), state, C))
- return;
+void StreamChecker::checkArgNullStream(const CallEvent &Call, CheckerContext &C,
+ unsigned ArgI) const {
+ ProgramStateRef State = C.getState();
+ if (checkNullStream(Call.getArgSVal(ArgI), C, State))
+ C.addTransition(State);
}
-ProgramStateRef StreamChecker::CheckNullStream(SVal SV, ProgramStateRef state,
- CheckerContext &C) const {
+bool StreamChecker::checkNullStream(SVal SV, CheckerContext &C,
+ ProgramStateRef &State) const {
Optional<DefinedSVal> DV = SV.getAs<DefinedSVal>();
if (!DV)
- return nullptr;
+ return false;
ConstraintManager &CM = C.getConstraintManager();
- ProgramStateRef stateNotNull, stateNull;
- std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
+ ProgramStateRef StateNotNull, StateNull;
+ std::tie(StateNotNull, StateNull) = CM.assumeDual(C.getState(), *DV);
- if (!stateNotNull && stateNull) {
- if (ExplodedNode *N = C.generateErrorNode(stateNull)) {
+ if (!StateNotNull && StateNull) {
+ if (ExplodedNode *N = C.generateErrorNode(StateNull)) {
if (!BT_nullfp)
BT_nullfp.reset(new BuiltinBug(this, "NULL stream pointer",
"Stream pointer might be NULL."));
C.emitReport(std::make_unique<PathSensitiveBugReport>(
*BT_nullfp, BT_nullfp->getDescription(), N));
}
- return nullptr;
+ return false;
+ }
+
+ if (StateNotNull) {
+ State = StateNotNull;
+ return true;
+ }
+
+ return false;
+}
+
+void StreamChecker::checkFseekWhence(SVal SV, CheckerContext &C,
+ ProgramStateRef &State) const {
+ Optional<nonloc::ConcreteInt> CI = SV.getAs<nonloc::ConcreteInt>();
+ if (!CI)
+ return;
+
+ int64_t X = CI->getValue().getSExtValue();
+ if (X >= 0 && X <= 2)
+ return;
+
+ if (ExplodedNode *N = C.generateNonFatalErrorNode(State)) {
+ if (!BT_illegalwhence)
+ BT_illegalwhence.reset(
+ new BuiltinBug(this, "Illegal whence argument",
+ "The whence argument to fseek() should be "
+ "SEEK_SET, SEEK_END, or SEEK_CUR."));
+ C.emitReport(std::make_unique<PathSensitiveBugReport>(
+ *BT_illegalwhence, BT_illegalwhence->getDescription(), N));
}
- return stateNotNull;
}
-ProgramStateRef StreamChecker::CheckDoubleClose(const CallExpr *CE,
- ProgramStateRef state,
- CheckerContext &C) const {
- SymbolRef Sym = C.getSVal(CE->getArg(0)).getAsSymbol();
+bool StreamChecker::checkDoubleClose(const CallEvent &Call, CheckerContext &C,
+ ProgramStateRef &State) const {
+ SymbolRef Sym = Call.getArgSVal(0).getAsSymbol();
if (!Sym)
- return state;
+ return false;
- const StreamState *SS = state->get<StreamMap>(Sym);
+ const StreamState *SS = State->get<StreamMap>(Sym);
// If the file stream is not tracked, return.
if (!SS)
- return state;
+ return false;
// Check: Double close a File Descriptor could cause undefined behaviour.
// Conforming to man-pages
@@ -378,19 +313,21 @@ ProgramStateRef StreamChecker::CheckDoubleClose(const CallExpr *CE,
C.emitReport(std::make_unique<PathSensitiveBugReport>(
*BT_doubleclose, BT_doubleclose->getDescription(), N));
}
- return nullptr;
+ return false;
}
// Close the File Descriptor.
- return state->set<StreamMap>(Sym, StreamState::getClosed(CE));
+ State = State->set<StreamMap>(Sym, StreamState::getClosed());
+
+ return true;
}
void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
CheckerContext &C) const {
- ProgramStateRef state = C.getState();
+ ProgramStateRef State = C.getState();
// TODO: Clean up the state.
- const StreamMapTy &Map = state->get<StreamMap>();
+ const StreamMapTy &Map = State->get<StreamMap>();
for (const auto &I: Map) {
SymbolRef Sym = I.first;
const StreamState &SS = I.second;
@@ -399,7 +336,7 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
ExplodedNode *N = C.generateErrorNode();
if (!N)
- return;
+ continue;
if (!BT_ResourceLeak)
BT_ResourceLeak.reset(
diff --git a/clang/lib/StaticAnalyzer/Checkers/Taint.cpp b/clang/lib/StaticAnalyzer/Checkers/Taint.cpp
index 574d4ed1e600..5b46ffb656cf 100644
--- a/clang/lib/StaticAnalyzer/Checkers/Taint.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/Taint.cpp
@@ -37,9 +37,7 @@ void taint::printTaint(ProgramStateRef State, raw_ostream &Out, const char *NL,
Out << I.first << " : " << I.second << NL;
}
-void dumpTaint(ProgramStateRef State) {
- printTaint(State, llvm::errs());
-}
+void dumpTaint(ProgramStateRef State) { printTaint(State, llvm::errs()); }
ProgramStateRef taint::addTaint(ProgramStateRef State, const Stmt *S,
const LocationContext *LCtx,
@@ -64,8 +62,8 @@ ProgramStateRef taint::addTaint(ProgramStateRef State, SVal V,
// region of the parent region.
if (auto LCV = V.getAs<nonloc::LazyCompoundVal>()) {
if (Optional<SVal> binding =
- State->getStateManager().getStoreManager()
- .getDefaultBinding(*LCV)) {
+ State->getStateManager().getStoreManager().getDefaultBinding(
+ *LCV)) {
if (SymbolRef Sym = binding->getAsSymbol())
return addPartialTaint(State, Sym, LCV->getRegion(), Kind);
}
@@ -94,6 +92,32 @@ ProgramStateRef taint::addTaint(ProgramStateRef State, SymbolRef Sym,
return NewState;
}
+ProgramStateRef taint::removeTaint(ProgramStateRef State, SVal V) {
+ SymbolRef Sym = V.getAsSymbol();
+ if (Sym)
+ return removeTaint(State, Sym);
+
+ const MemRegion *R = V.getAsRegion();
+ return removeTaint(State, R);
+}
+
+ProgramStateRef taint::removeTaint(ProgramStateRef State, const MemRegion *R) {
+ if (const SymbolicRegion *SR = dyn_cast_or_null<SymbolicRegion>(R))
+ return removeTaint(State, SR->getSymbol());
+ return State;
+}
+
+ProgramStateRef taint::removeTaint(ProgramStateRef State, SymbolRef Sym) {
+ // If this is a symbol cast, remove the cast before adding the taint. Taint
+ // is cast agnostic.
+ while (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym))
+ Sym = SC->getOperand();
+
+ ProgramStateRef NewState = State->remove<TaintMap>(Sym);
+ assert(NewState);
+ return NewState;
+}
+
ProgramStateRef taint::addPartialTaint(ProgramStateRef State,
SymbolRef ParentSym,
const SubRegion *SubRegion,
@@ -157,7 +181,8 @@ bool taint::isTainted(ProgramStateRef State, SymbolRef Sym, TaintTagType Kind) {
// Traverse all the symbols this symbol depends on to see if any are tainted.
for (SymExpr::symbol_iterator SI = Sym->symbol_begin(),
- SE = Sym->symbol_end(); SI != SE; ++SI) {
+ SE = Sym->symbol_end();
+ SI != SE; ++SI) {
if (!isa<SymbolData>(*SI))
continue;
diff --git a/clang/lib/StaticAnalyzer/Checkers/Taint.h b/clang/lib/StaticAnalyzer/Checkers/Taint.h
index 8940916c1933..659a3c898d56 100644
--- a/clang/lib/StaticAnalyzer/Checkers/Taint.h
+++ b/clang/lib/StaticAnalyzer/Checkers/Taint.h
@@ -27,34 +27,39 @@ using TaintTagType = unsigned;
static constexpr TaintTagType TaintTagGeneric = 0;
/// Create a new state in which the value of the statement is marked as tainted.
-LLVM_NODISCARD ProgramStateRef
-addTaint(ProgramStateRef State, const Stmt *S, const LocationContext *LCtx,
- TaintTagType Kind = TaintTagGeneric);
+LLVM_NODISCARD ProgramStateRef addTaint(ProgramStateRef State, const Stmt *S,
+ const LocationContext *LCtx,
+ TaintTagType Kind = TaintTagGeneric);
/// Create a new state in which the value is marked as tainted.
-LLVM_NODISCARD ProgramStateRef
-addTaint(ProgramStateRef State, SVal V,
- TaintTagType Kind = TaintTagGeneric);
+LLVM_NODISCARD ProgramStateRef addTaint(ProgramStateRef State, SVal V,
+ TaintTagType Kind = TaintTagGeneric);
/// Create a new state in which the symbol is marked as tainted.
-LLVM_NODISCARD ProgramStateRef
-addTaint(ProgramStateRef State, SymbolRef Sym,
- TaintTagType Kind = TaintTagGeneric);
+LLVM_NODISCARD ProgramStateRef addTaint(ProgramStateRef State, SymbolRef Sym,
+ TaintTagType Kind = TaintTagGeneric);
/// Create a new state in which the pointer represented by the region
/// is marked as tainted.
-LLVM_NODISCARD ProgramStateRef
-addTaint(ProgramStateRef State, const MemRegion *R,
- TaintTagType Kind = TaintTagGeneric);
+LLVM_NODISCARD ProgramStateRef addTaint(ProgramStateRef State,
+ const MemRegion *R,
+ TaintTagType Kind = TaintTagGeneric);
+
+LLVM_NODISCARD ProgramStateRef removeTaint(ProgramStateRef State, SVal V);
+
+LLVM_NODISCARD ProgramStateRef removeTaint(ProgramStateRef State,
+ const MemRegion *R);
+
+LLVM_NODISCARD ProgramStateRef removeTaint(ProgramStateRef State,
+ SymbolRef Sym);
/// Create a new state in a which a sub-region of a given symbol is tainted.
/// This might be necessary when referring to regions that can not have an
/// individual symbol, e.g. if they are represented by the default binding of
/// a LazyCompoundVal.
-LLVM_NODISCARD ProgramStateRef
-addPartialTaint(ProgramStateRef State,
- SymbolRef ParentSym, const SubRegion *SubRegion,
- TaintTagType Kind = TaintTagGeneric);
+LLVM_NODISCARD ProgramStateRef addPartialTaint(
+ ProgramStateRef State, SymbolRef ParentSym, const SubRegion *SubRegion,
+ TaintTagType Kind = TaintTagGeneric);
/// Check if the statement has a tainted value in the given state.
bool isTainted(ProgramStateRef State, const Stmt *S,
@@ -99,4 +104,3 @@ public:
} // namespace clang
#endif
-
diff --git a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
index 12cee5f8d4f7..fd93fc33115f 100644
--- a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
@@ -11,8 +11,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
diff --git a/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp
index 73e1a0d0000f..fdd03c75920d 100644
--- a/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp
@@ -43,6 +43,9 @@ AnalysisManager::AnalysisManager(ASTContext &ASTCtx,
CreateConstraintMgr(constraintmgr), CheckerMgr(checkerMgr),
options(Options) {
AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd();
+ AnaCtxMgr.getCFGBuildOptions().OmitImplicitValueInitializers = true;
+ AnaCtxMgr.getCFGBuildOptions().AddCXXDefaultInitExprInAggregates =
+ Options.ShouldIncludeDefaultInitForAggregates;
}
AnalysisManager::~AnalysisManager() {
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 7ba93b858baf..0525b5c41e34 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -505,7 +505,7 @@ NoStoreFuncVisitor::findRegionOfInterestInRecord(
// 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())
+ for (const auto &II : RDX->bases())
if (const RecordDecl *RRD = II.getType()->getAsRecordDecl())
if (Optional<RegionVector> Out =
findRegionOfInterestInRecord(RRD, State, R, Vec, depth))
@@ -1606,9 +1606,6 @@ SuppressInlineDefensiveChecksVisitor(DefinedSVal Value, const ExplodedNode *N)
AnalyzerOptions &Options = N->getState()->getAnalysisManager().options;
if (!Options.ShouldSuppressInlinedDefensiveChecks)
IsSatisfied = true;
-
- assert(N->getState()->isNull(V).isConstrainedTrue() &&
- "The visitor only tracks the cases where V is constrained to 0");
}
void SuppressInlineDefensiveChecksVisitor::Profile(
@@ -1639,13 +1636,12 @@ SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ,
// Check if in the previous state it was feasible for this value
// to *not* be null.
- if (!Pred->getState()->isNull(V).isConstrainedTrue()) {
+ if (!Pred->getState()->isNull(V).isConstrainedTrue() &&
+ Succ->getState()->isNull(V).isConstrainedTrue()) {
IsSatisfied = true;
- assert(Succ->getState()->isNull(V).isConstrainedTrue());
-
// Check if this is inlined defensive checks.
- const LocationContext *CurLC =Succ->getLocationContext();
+ const LocationContext *CurLC = Succ->getLocationContext();
const LocationContext *ReportLC = BR.getErrorNode()->getLocationContext();
if (CurLC != ReportLC && !CurLC->isParentOf(ReportLC)) {
BR.markInvalid("Suppress IDC", CurLC);
@@ -2012,11 +2008,16 @@ bool bugreporter::trackExpressionValue(const ExplodedNode *InputNode,
// Add visitor, which will suppress inline defensive checks.
if (auto DV = V.getAs<DefinedSVal>())
- if (!DV->isZeroConstant() && LVState->isNull(*DV).isConstrainedTrue() &&
- EnableNullFPSuppression)
+ if (!DV->isZeroConstant() && EnableNullFPSuppression) {
+ // Note that LVNode may be too late (i.e., too far from the InputNode)
+ // because the lvalue may have been computed before the inlined call
+ // was evaluated. InputNode may as well be too early here, because
+ // the symbol is already dead; this, however, is fine because we can
+ // still find the node in which it collapsed to null previously.
report.addVisitor(
- std::make_unique<SuppressInlineDefensiveChecksVisitor>(*DV,
- LVNode));
+ std::make_unique<SuppressInlineDefensiveChecksVisitor>(
+ *DV, InputNode));
+ }
if (auto KV = V.getAs<KnownSVal>())
report.addVisitor(std::make_unique<FindLastStoreBRVisitor>(
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index 5f04a59ba055..168d6fe6ec48 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -14,6 +14,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
@@ -29,20 +30,20 @@
#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Analysis/ProgramPoint.h"
-#include "clang/CrossTU/CrossTranslationUnit.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Specifiers.h"
+#include "clang/CrossTU/CrossTranslationUnit.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
@@ -519,7 +520,7 @@ static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx,
// TODO: Support allocator calls.
if (Call.getKind() != CE_CXXAllocator)
- if (Call.isArgumentConstructedDirectly(Idx))
+ if (Call.isArgumentConstructedDirectly(Call.getASTArgumentIndex(Idx)))
continue;
// TODO: Allocators should receive the correct size and possibly alignment,
@@ -1080,7 +1081,7 @@ ObjCMessageKind ObjCMethodCall::getMessageKind() const {
const ObjCPropertyDecl *ObjCMethodCall::getAccessedProperty() const {
// Look for properties accessed with property syntax (foo.bar = ...)
- if ( getMessageKind() == OCM_PropertyAccess) {
+ if (getMessageKind() == OCM_PropertyAccess) {
const PseudoObjectExpr *POE = getContainingPseudoObjectExpr();
assert(POE && "Property access without PseudoObjectExpr?");
@@ -1309,6 +1310,8 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const {
}
const ObjCMethodDecl *MD = Val.getValue();
+ if (MD && !MD->hasBody())
+ MD = MD->getCanonicalDecl();
if (CanBeSubClassed)
return RuntimeDefinition(MD, Receiver);
else
diff --git a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
index f676bd895283..a9361837cf68 100644
--- a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -91,7 +91,7 @@ void CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr,
}
assert(checkers);
- for (const auto checker : *checkers)
+ for (const auto &checker : *checkers)
checker(D, mgr, BR);
}
@@ -99,7 +99,7 @@ void CheckerManager::runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) {
assert(D && D->hasBody());
- for (const auto BodyChecker : BodyCheckers)
+ for (const auto &BodyChecker : BodyCheckers)
BodyChecker(D, mgr, BR);
}
@@ -402,7 +402,7 @@ void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst,
void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G,
BugReporter &BR,
ExprEngine &Eng) {
- for (const auto EndAnalysisChecker : EndAnalysisCheckers)
+ for (const auto &EndAnalysisChecker : EndAnalysisCheckers)
EndAnalysisChecker(G, BR, Eng);
}
@@ -455,7 +455,7 @@ void CheckerManager::runCheckersForEndFunction(NodeBuilderContext &BC,
// creates a successor for Pred, we do not need to generate an
// autotransition for it.
NodeBuilder Bldr(Pred, Dst, BC);
- for (const auto checkFn : EndFunctionCheckers) {
+ for (const auto &checkFn : EndFunctionCheckers) {
const ProgramPoint &L =
FunctionExitPoint(RS, Pred->getLocationContext(), checkFn.Checker);
CheckerContext C(Bldr, Eng, Pred, L);
@@ -542,7 +542,7 @@ void CheckerManager::runCheckersForNewAllocator(
/// Run checkers for live symbols.
void CheckerManager::runCheckersForLiveSymbols(ProgramStateRef state,
SymbolReaper &SymReaper) {
- for (const auto LiveSymbolsChecker : LiveSymbolsCheckers)
+ for (const auto &LiveSymbolsChecker : LiveSymbolsCheckers)
LiveSymbolsChecker(state, SymReaper);
}
@@ -599,7 +599,7 @@ CheckerManager::runCheckersForRegionChanges(ProgramStateRef state,
ArrayRef<const MemRegion *> Regions,
const LocationContext *LCtx,
const CallEvent *Call) {
- for (const auto RegionChangesChecker : RegionChangesCheckers) {
+ for (const auto &RegionChangesChecker : RegionChangesCheckers) {
// If any checker declares the state infeasible (or if it starts that way),
// bail out.
if (!state)
@@ -621,7 +621,7 @@ CheckerManager::runCheckersForPointerEscape(ProgramStateRef State,
(Kind != PSK_DirectEscapeOnCall &&
Kind != PSK_IndirectEscapeOnCall)) &&
"Call must not be NULL when escaping on call");
- for (const auto PointerEscapeChecker : PointerEscapeCheckers) {
+ for (const auto &PointerEscapeChecker : PointerEscapeCheckers) {
// If any checker declares the state infeasible (or if it starts that
// way), bail out.
if (!State)
@@ -635,7 +635,7 @@ CheckerManager::runCheckersForPointerEscape(ProgramStateRef State,
ProgramStateRef
CheckerManager::runCheckersForEvalAssume(ProgramStateRef state,
SVal Cond, bool Assumption) {
- for (const auto EvalAssumeChecker : EvalAssumeCheckers) {
+ for (const auto &EvalAssumeChecker : EvalAssumeCheckers) {
// If any checker declares the state infeasible (or if it starts that way),
// bail out.
if (!state)
@@ -658,7 +658,7 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
NodeBuilder B(Pred, checkDst, Eng.getBuilderContext());
// Check if any of the EvalCall callbacks can evaluate the call.
- for (const auto EvalCallChecker : EvalCallCheckers) {
+ for (const auto &EvalCallChecker : EvalCallCheckers) {
// TODO: Support the situation when the call doesn't correspond
// to any Expr.
ProgramPoint L = ProgramPoint::getProgramPoint(
@@ -697,7 +697,7 @@ void CheckerManager::runCheckersOnEndOfTranslationUnit(
const TranslationUnitDecl *TU,
AnalysisManager &mgr,
BugReporter &BR) {
- for (const auto EndOfTranslationUnitChecker : EndOfTranslationUnitCheckers)
+ for (const auto &EndOfTranslationUnitChecker : EndOfTranslationUnitCheckers)
EndOfTranslationUnitChecker(TU, mgr, BR);
}
@@ -904,6 +904,6 @@ CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) {
}
CheckerManager::~CheckerManager() {
- for (const auto CheckerDtor : CheckerDtors)
+ for (const auto &CheckerDtor : CheckerDtors)
CheckerDtor();
}
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index e92e95354f5f..f917a4c8637b 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -728,7 +728,8 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out,
// Create a state in which dead bindings are removed from the environment
// and the store. TODO: The function should just return new env and store,
// not a new state.
- CleanedState = StateMgr.removeDeadBindings(CleanedState, SFC, SymReaper);
+ CleanedState = StateMgr.removeDeadBindingsFromEnvironmentAndStore(
+ CleanedState, SFC, SymReaper);
// Process any special transfer function for dead symbols.
// A tag to track convenience transitions, which can be removed at cleanup.
@@ -1171,13 +1172,16 @@ void ExprEngine::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE,
}
}
-ProgramStateRef ExprEngine::escapeValue(ProgramStateRef State, SVal V,
- PointerEscapeKind K) const {
+ProgramStateRef ExprEngine::escapeValues(ProgramStateRef State,
+ ArrayRef<SVal> Vs,
+ PointerEscapeKind K,
+ const CallEvent *Call) const {
class CollectReachableSymbolsCallback final : public SymbolVisitor {
- InvalidatedSymbols Symbols;
+ InvalidatedSymbols &Symbols;
public:
- explicit CollectReachableSymbolsCallback(ProgramStateRef) {}
+ explicit CollectReachableSymbolsCallback(InvalidatedSymbols &Symbols)
+ : Symbols(Symbols) {}
const InvalidatedSymbols &getSymbols() const { return Symbols; }
@@ -1186,11 +1190,13 @@ ProgramStateRef ExprEngine::escapeValue(ProgramStateRef State, SVal V,
return true;
}
};
+ InvalidatedSymbols Symbols;
+ CollectReachableSymbolsCallback CallBack(Symbols);
+ for (SVal V : Vs)
+ State->scanReachableSymbols(V, CallBack);
- const CollectReachableSymbolsCallback &Scanner =
- State->scanReachableSymbols<CollectReachableSymbolsCallback>(V);
return getCheckerManager().runCheckersForPointerEscape(
- State, Scanner.getSymbols(), /*CallEvent*/ nullptr, K, nullptr);
+ State, CallBack.getSymbols(), Call, K, nullptr);
}
void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
@@ -1245,6 +1251,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::OMPParallelForDirectiveClass:
case Stmt::OMPParallelForSimdDirectiveClass:
case Stmt::OMPParallelSectionsDirectiveClass:
+ case Stmt::OMPParallelMasterDirectiveClass:
case Stmt::OMPTaskDirectiveClass:
case Stmt::OMPTaskyieldDirectiveClass:
case Stmt::OMPBarrierDirectiveClass:
@@ -1268,6 +1275,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::OMPMasterTaskLoopDirectiveClass:
case Stmt::OMPMasterTaskLoopSimdDirectiveClass:
case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
+ case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:
case Stmt::OMPDistributeDirectiveClass:
case Stmt::OMPDistributeParallelForDirectiveClass:
case Stmt::OMPDistributeParallelForSimdDirectiveClass:
@@ -1313,6 +1321,11 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::WhileStmtClass:
case Expr::MSDependentExistsStmtClass:
llvm_unreachable("Stmt should not be in analyzer evaluation loop");
+ case Stmt::ImplicitValueInitExprClass:
+ // These nodes are shared in the CFG and would case caching out.
+ // Moreover, no additional evaluation required for them, the
+ // analyzer can reconstruct these values from the AST.
+ llvm_unreachable("Should be pruned from CFG");
case Stmt::ObjCSubscriptRefExprClass:
case Stmt::ObjCPropertyRefExprClass:
@@ -1383,7 +1396,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::IntegerLiteralClass:
case Stmt::FixedPointLiteralClass:
case Stmt::CharacterLiteralClass:
- case Stmt::ImplicitValueInitExprClass:
case Stmt::CXXScalarValueInitExprClass:
case Stmt::CXXBoolLiteralExprClass:
case Stmt::ObjCBoolLiteralExprClass:
@@ -1426,7 +1438,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
bool IsTemporary = false;
if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(ArgE)) {
- ArgE = MTE->GetTemporaryExpr();
+ ArgE = MTE->getSubExpr();
IsTemporary = true;
}
@@ -1481,7 +1493,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
for (auto Child : Ex->children()) {
assert(Child);
SVal Val = State->getSVal(Child, LCtx);
- State = escapeValue(State, Val, PSK_EscapeOther);
+ State = escapeValues(State, Val, PSK_EscapeOther);
}
Bldr2.generateNode(S, N, State);
@@ -2682,33 +2694,52 @@ void ExprEngine::VisitAtomicExpr(const AtomicExpr *AE, ExplodedNode *Pred,
// destructor. We won't see the destructor during analysis, but it's there.
// (4) We are binding to a MemRegion with stack storage that the store
// does not understand.
-ProgramStateRef
-ExprEngine::processPointerEscapedOnBind(ProgramStateRef State, SVal Loc,
- SVal Val, const LocationContext *LCtx) {
+ProgramStateRef ExprEngine::processPointerEscapedOnBind(
+ ProgramStateRef State, ArrayRef<std::pair<SVal, SVal>> LocAndVals,
+ const LocationContext *LCtx, PointerEscapeKind Kind,
+ const CallEvent *Call) {
+ SmallVector<SVal, 8> Escaped;
+ for (const std::pair<SVal, SVal> &LocAndVal : LocAndVals) {
+ // Cases (1) and (2).
+ const MemRegion *MR = LocAndVal.first.getAsRegion();
+ if (!MR || !MR->hasStackStorage()) {
+ Escaped.push_back(LocAndVal.second);
+ continue;
+ }
+
+ // Case (3).
+ if (const auto *VR = dyn_cast<VarRegion>(MR->getBaseRegion()))
+ if (VR->hasStackParametersStorage() && VR->getStackFrame()->inTopFrame())
+ if (const auto *RD = VR->getValueType()->getAsCXXRecordDecl())
+ if (!RD->hasTrivialDestructor()) {
+ Escaped.push_back(LocAndVal.second);
+ continue;
+ }
- // Cases (1) and (2).
- const MemRegion *MR = Loc.getAsRegion();
- if (!MR || !MR->hasStackStorage())
- return escapeValue(State, Val, PSK_EscapeOnBind);
+ // Case (4): in order to test that, generate a new state with the binding
+ // added. If it is the same state, then it escapes (since the store cannot
+ // represent the binding).
+ // Do this only if we know that the store is not supposed to generate the
+ // same state.
+ SVal StoredVal = State->getSVal(MR);
+ if (StoredVal != LocAndVal.second)
+ if (State ==
+ (State->bindLoc(loc::MemRegionVal(MR), LocAndVal.second, LCtx)))
+ Escaped.push_back(LocAndVal.second);
+ }
- // Case (3).
- if (const auto *VR = dyn_cast<VarRegion>(MR->getBaseRegion()))
- if (VR->hasStackParametersStorage() && VR->getStackFrame()->inTopFrame())
- if (const auto *RD = VR->getValueType()->getAsCXXRecordDecl())
- if (!RD->hasTrivialDestructor())
- return escapeValue(State, Val, PSK_EscapeOnBind);
+ if (Escaped.empty())
+ return State;
- // Case (4): in order to test that, generate a new state with the binding
- // added. If it is the same state, then it escapes (since the store cannot
- // represent the binding).
- // Do this only if we know that the store is not supposed to generate the
- // same state.
- SVal StoredVal = State->getSVal(MR);
- if (StoredVal != Val)
- if (State == (State->bindLoc(loc::MemRegionVal(MR), Val, LCtx)))
- return escapeValue(State, Val, PSK_EscapeOnBind);
+ return escapeValues(State, Escaped, Kind, Call);
+}
- return State;
+ProgramStateRef
+ExprEngine::processPointerEscapedOnBind(ProgramStateRef State, SVal Loc,
+ SVal Val, const LocationContext *LCtx) {
+ std::pair<SVal, SVal> LocAndVal(Loc, Val);
+ return processPointerEscapedOnBind(State, LocAndVal, LCtx, PSK_EscapeOnBind,
+ nullptr);
}
ProgramStateRef
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 02a398c77ac8..b17f26aa9c53 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -102,8 +102,8 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
state = state->BindExpr(B, LCtx, Result);
} else {
// If we cannot evaluate the operation escape the operands.
- state = escapeValue(state, LeftV, PSK_EscapeOther);
- state = escapeValue(state, RightV, PSK_EscapeOther);
+ state = escapeValues(state, LeftV, PSK_EscapeOther);
+ state = escapeValues(state, RightV, PSK_EscapeOther);
}
Bldr.generateNode(B, *it, state);
@@ -275,7 +275,7 @@ ProgramStateRef ExprEngine::handleLValueBitCast(
V = evalMinus(V);
state = state->BindExpr(CastE, LCtx, V);
if (V.isUnknown() && !OrigV.isUnknown()) {
- state = escapeValue(state, OrigV, PSK_EscapeOther);
+ state = escapeValues(state, OrigV, PSK_EscapeOther);
}
Bldr.generateNode(CastE, Pred, state);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 058be985540d..b816aab7c18f 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -27,7 +27,7 @@ void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
- const Expr *tempExpr = ME->GetTemporaryExpr()->IgnoreParens();
+ const Expr *tempExpr = ME->getSubExpr()->IgnoreParens();
ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 345d4d817dea..01a371e664b2 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/Decl.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "PrettyStackTraceLocationContext.h"
#include "clang/AST/CXXInheritance.h"
@@ -592,9 +593,45 @@ void ExprEngine::evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
for (auto I : dstCallEvaluated)
finishArgumentConstruction(dstArgumentCleanup, I, Call);
- // Finally, run any post-call checks.
- getCheckerManager().runCheckersForPostCall(Dst, dstArgumentCleanup,
+ ExplodedNodeSet dstPostCall;
+ getCheckerManager().runCheckersForPostCall(dstPostCall, dstArgumentCleanup,
Call, *this);
+
+ // Escaping symbols conjured during invalidating the regions above.
+ // Note that, for inlined calls the nodes were put back into the worklist,
+ // so we can assume that every node belongs to a conservative call at this
+ // point.
+
+ // Run pointerEscape callback with the newly conjured symbols.
+ SmallVector<std::pair<SVal, SVal>, 8> Escaped;
+ for (auto I : dstPostCall) {
+ NodeBuilder B(I, Dst, *currBldrCtx);
+ ProgramStateRef State = I->getState();
+ Escaped.clear();
+ {
+ unsigned Arg = -1;
+ for (const ParmVarDecl *PVD : Call.parameters()) {
+ ++Arg;
+ QualType ParamTy = PVD->getType();
+ if (ParamTy.isNull() ||
+ (!ParamTy->isPointerType() && !ParamTy->isReferenceType()))
+ continue;
+ QualType Pointee = ParamTy->getPointeeType();
+ if (Pointee.isConstQualified() || Pointee->isVoidType())
+ continue;
+ if (const MemRegion *MR = Call.getArgSVal(Arg).getAsRegion())
+ Escaped.emplace_back(loc::MemRegionVal(MR), State->getSVal(MR, Pointee));
+ }
+ }
+
+ State = processPointerEscapedOnBind(State, Escaped, I->getLocationContext(),
+ PSK_EscapeOutParameters, &Call);
+
+ if (State == I->getState())
+ Dst.insert(I);
+ else
+ B.generateNode(I->getLocation(), State, I);
+ }
}
ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call,
@@ -670,8 +707,7 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call,
// Conservatively evaluate call by invalidating regions and binding
// a conjured return value.
void ExprEngine::conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr,
- ExplodedNode *Pred,
- ProgramStateRef State) {
+ ExplodedNode *Pred, ProgramStateRef State) {
State = Call.invalidateRegions(currBldrCtx->blockCount(), State);
State = bindReturnValue(Call, Pred->getLocationContext(), State);
diff --git a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
index f50d82de3b28..14006f79fd0f 100644
--- a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -91,10 +91,9 @@ ProgramStateManager::~ProgramStateManager() {
I->second.second(I->second.first);
}
-ProgramStateRef
-ProgramStateManager::removeDeadBindings(ProgramStateRef state,
- const StackFrameContext *LCtx,
- SymbolReaper& SymReaper) {
+ProgramStateRef ProgramStateManager::removeDeadBindingsFromEnvironmentAndStore(
+ ProgramStateRef state, const StackFrameContext *LCtx,
+ SymbolReaper &SymReaper) {
// This code essentially performs a "mark-and-sweep" of the VariableBindings.
// The roots are any Block-level exprs and Decls that our liveness algorithm
@@ -112,8 +111,7 @@ ProgramStateManager::removeDeadBindings(ProgramStateRef state,
NewState.setStore(newStore);
SymReaper.setReapedStore(newStore);
- ProgramStateRef Result = getPersistentState(NewState);
- return ConstraintMgr->removeDeadBindings(Result, SymReaper);
+ return getPersistentState(NewState);
}
ProgramStateRef ProgramState::bindLoc(Loc LV,
diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index 5d2ef59e2d66..4797f564a837 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1951,7 +1951,8 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
if (hasSymbolicIndex)
return UnknownVal();
- if (!hasPartialLazyBinding)
+ // Additionally allow introspection of a block's internal layout.
+ if (!hasPartialLazyBinding && !isa<BlockDataRegion>(R->getBaseRegion()))
return UndefinedVal();
}
diff --git a/clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp
index 190ab7e21dbc..12332aaf936f 100644
--- a/clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp
@@ -17,6 +17,7 @@
#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/Path.h"
@@ -27,10 +28,12 @@ using namespace ento;
namespace {
class SarifDiagnostics : public PathDiagnosticConsumer {
std::string OutputFile;
+ const LangOptions &LO;
public:
- SarifDiagnostics(AnalyzerOptions &, const std::string &Output)
- : OutputFile(Output) {}
+ SarifDiagnostics(AnalyzerOptions &, const std::string &Output,
+ const LangOptions &LO)
+ : OutputFile(Output), LO(LO) {}
~SarifDiagnostics() override = default;
void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
@@ -45,9 +48,9 @@ public:
void ento::createSarifDiagnosticConsumer(
AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C,
- const std::string &Output, const Preprocessor &,
+ const std::string &Output, const Preprocessor &PP,
const cross_tu::CrossTranslationUnitContext &) {
- C.push_back(new SarifDiagnostics(AnalyzerOpts, Output));
+ C.push_back(new SarifDiagnostics(AnalyzerOpts, Output, PP.getLangOpts()));
}
static StringRef getFileName(const FileEntry &FE) {
@@ -142,26 +145,56 @@ static json::Object createArtifactLocation(const FileEntry &FE,
return json::Object{{"uri", FileURI}, {"index", Index}};
}
-static json::Object createTextRegion(SourceRange R, const SourceManager &SM) {
+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?");
+
+ bool InvalidBuffer = false;
+ const MemoryBuffer *Buf = SM.getBuffer(LocInfo.first, &InvalidBuffer);
+ assert(!InvalidBuffer && "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", SM.getExpansionColumnNumber(R.getBegin())},
+ {"startColumn", adjustColumnPos(SM, R.getBegin())},
};
if (R.getBegin() == R.getEnd()) {
- Region["endColumn"] = SM.getExpansionColumnNumber(R.getBegin());
+ Region["endColumn"] = adjustColumnPos(SM, R.getBegin());
} else {
Region["endLine"] = SM.getExpansionLineNumber(R.getEnd());
- Region["endColumn"] = SM.getExpansionColumnNumber(R.getEnd()) + 1;
+ Region["endColumn"] = adjustColumnPos(
+ SM, R.getEnd(),
+ Lexer::MeasureTokenLength(R.getEnd(), SM, LO));
}
return Region;
}
-static json::Object createPhysicalLocation(SourceRange R, const FileEntry &FE,
+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(R, SMgr)}}};
+ {"region", createTextRegion(LO, R, SMgr)}}};
}
enum class Importance { Important, Essential, Unimportant };
@@ -213,7 +246,8 @@ static Importance calculateImportance(const PathDiagnosticPiece &Piece) {
return Importance::Unimportant;
}
-static json::Object createThreadFlow(const PathPieces &Pieces,
+static json::Object createThreadFlow(const LangOptions &LO,
+ const PathPieces &Pieces,
json::Array &Artifacts) {
const SourceManager &SMgr = Pieces.front()->getLocation().getManager();
json::Array Locations;
@@ -221,7 +255,7 @@ static json::Object createThreadFlow(const PathPieces &Pieces,
const PathDiagnosticLocation &P = Piece->getLocation();
Locations.push_back(createThreadFlowLocation(
createLocation(createPhysicalLocation(
- P.asRange(),
+ LO, P.asRange(),
*P.asLocation().getExpansionLoc().getFileEntry(),
SMgr, Artifacts),
Piece->getString()),
@@ -230,13 +264,15 @@ static json::Object createThreadFlow(const PathPieces &Pieces,
return json::Object{{"locations", std::move(Locations)}};
}
-static json::Object createCodeFlow(const PathPieces &Pieces,
+static json::Object createCodeFlow(const LangOptions &LO,
+ const PathPieces &Pieces,
json::Array &Artifacts) {
return json::Object{
- {"threadFlows", json::Array{createThreadFlow(Pieces, Artifacts)}}};
+ {"threadFlows", json::Array{createThreadFlow(LO, Pieces, Artifacts)}}};
}
-static json::Object createResult(const PathDiagnostic &Diag,
+static json::Object createResult(const LangOptions &LO,
+ const PathDiagnostic &Diag,
json::Array &Artifacts,
const StringMap<unsigned> &RuleMapping) {
const PathPieces &Path = Diag.path.flatten(false);
@@ -247,10 +283,10 @@ static json::Object createResult(const PathDiagnostic &Diag,
return json::Object{
{"message", createMessage(Diag.getVerboseDescription())},
- {"codeFlows", json::Array{createCodeFlow(Path, Artifacts)}},
+ {"codeFlows", json::Array{createCodeFlow(LO, Path, Artifacts)}},
{"locations",
json::Array{createLocation(createPhysicalLocation(
- Diag.getLocation().asRange(),
+ LO, Diag.getLocation().asRange(),
*Diag.getLocation().asLocation().getExpansionLoc().getFileEntry(),
SMgr, Artifacts))}},
{"ruleIndex", Iter->getValue()},
@@ -320,18 +356,20 @@ static json::Object createTool(std::vector<const PathDiagnostic *> &Diags,
{"rules", createRules(Diags, RuleMapping)}}}};
}
-static json::Object createRun(std::vector<const PathDiagnostic *> &Diags) {
+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);
llvm::for_each(Diags, [&](const PathDiagnostic *D) {
- Results.push_back(createResult(*D, Artifacts, RuleMapping));
+ Results.push_back(createResult(LO, *D, Artifacts, RuleMapping));
});
return json::Object{{"tool", std::move(Tool)},
{"results", std::move(Results)},
- {"artifacts", std::move(Artifacts)}};
+ {"artifacts", std::move(Artifacts)},
+ {"columnKind", "unicodeCodePoints"}};
}
void SarifDiagnostics::FlushDiagnosticsImpl(
@@ -351,6 +389,6 @@ void SarifDiagnostics::FlushDiagnosticsImpl(
{"$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(Diags)}}};
+ {"runs", json::Array{createRun(LO, Diags)}}};
OS << llvm::formatv("{0:2}\n", json::Value(std::move(Sarif)));
}
diff --git a/clang/lib/StaticAnalyzer/Core/Store.cpp b/clang/lib/StaticAnalyzer/Core/Store.cpp
index b4ab6877726c..b33129c88cea 100644
--- a/clang/lib/StaticAnalyzer/Core/Store.cpp
+++ b/clang/lib/StaticAnalyzer/Core/Store.cpp
@@ -393,6 +393,11 @@ SVal StoreManager::attemptDownCast(SVal Base, QualType TargetType,
return UnknownVal();
}
+static bool hasSameUnqualifiedPointeeType(QualType ty1, QualType ty2) {
+ return ty1->getPointeeType().getCanonicalType().getTypePtr() ==
+ ty2->getPointeeType().getCanonicalType().getTypePtr();
+}
+
/// CastRetrievedVal - Used by subclasses of StoreManager to implement
/// implicit casts that arise from loads from regions that are reinterpreted
/// as another region.
@@ -421,10 +426,11 @@ SVal StoreManager::CastRetrievedVal(SVal V, const TypedValueRegion *R,
// FIXME: We really need a single good function to perform casts for us
// correctly every time we need it.
if (castTy->isPointerType() && !castTy->isVoidPointerType())
- if (const auto *SR = dyn_cast_or_null<SymbolicRegion>(V.getAsRegion()))
- if (SR->getSymbol()->getType().getCanonicalType() !=
- castTy.getCanonicalType())
- return loc::MemRegionVal(castRegion(SR, castTy));
+ if (const auto *SR = dyn_cast_or_null<SymbolicRegion>(V.getAsRegion())) {
+ QualType sr = SR->getSymbol()->getType();
+ if (!hasSameUnqualifiedPointeeType(sr, castTy))
+ return loc::MemRegionVal(castRegion(SR, castTy));
+ }
return svalBuilder.dispatchCast(V, castTy);
}
diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 8236907ea773..fea8100c3b3b 100644
--- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -722,13 +722,6 @@ std::string AnalysisConsumer::getFunctionName(const Decl *D) {
} else if (const auto *OCD = dyn_cast<ObjCCategoryImplDecl>(DC)) {
OS << OCD->getClassInterface()->getName() << '('
<< OCD->getName() << ')';
- } else if (isa<ObjCProtocolDecl>(DC)) {
- // We can extract the type of the class from the self pointer.
- if (ImplicitParamDecl *SelfDecl = OMD->getSelfDecl()) {
- QualType ClassTy =
- cast<ObjCObjectPointerType>(SelfDecl->getType())->getPointeeType();
- ClassTy.print(OS, PrintingPolicy(LangOptions()));
- }
}
OS << ' ' << OMD->getSelector().getAsString() << ']';
diff --git a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
index e00fd976f6b8..f5c05281adab 100644
--- a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
@@ -591,7 +591,8 @@ void CheckerRegistry::printCheckerOptionList(raw_ostream &Out) const {
/*MinLineWidth*/ 90);
Out << "\n\n";
};
- for (const std::pair<StringRef, const CmdLineOption &> &Entry : OptionMap) {
+ for (const std::pair<const StringRef, const CmdLineOption &> &Entry :
+ OptionMap) {
const CmdLineOption &Option = Entry.second;
std::string FullOption = (Entry.first + ":" + Option.OptionName).str();
diff --git a/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp b/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp
index 687fda75db48..7baae6778ebd 100644
--- a/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp
@@ -11,6 +11,7 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LangStandard.h"
#include "clang/Basic/Stack.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
diff --git a/clang/lib/Tooling/ASTDiff/ASTDiff.cpp b/clang/lib/Tooling/ASTDiff/ASTDiff.cpp
index 00db7702cd8b..4d495228cb51 100644
--- a/clang/lib/Tooling/ASTDiff/ASTDiff.cpp
+++ b/clang/lib/Tooling/ASTDiff/ASTDiff.cpp
@@ -787,7 +787,7 @@ void ASTDiff::Impl::addOptimalMapping(Mapping &M, NodeId Id1,
return;
ZhangShashaMatcher Matcher(*this, T1, T2, Id1, Id2);
std::vector<std::pair<NodeId, NodeId>> R = Matcher.getMatchingNodes();
- for (const auto Tuple : R) {
+ for (const auto &Tuple : R) {
NodeId Src = Tuple.first;
NodeId Dst = Tuple.second;
if (!M.hasSrc(Src) && !M.hasDst(Dst))
diff --git a/clang/lib/Tooling/ArgumentsAdjusters.cpp b/clang/lib/Tooling/ArgumentsAdjusters.cpp
index f56d08c47b9a..a609e4ed2469 100644
--- a/clang/lib/Tooling/ArgumentsAdjusters.cpp
+++ b/clang/lib/Tooling/ArgumentsAdjusters.cpp
@@ -13,20 +13,32 @@
#include "clang/Tooling/ArgumentsAdjusters.h"
#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include <cstddef>
+#include <vector>
namespace clang {
namespace tooling {
-/// Add -fsyntax-only option to the command line arguments.
+/// Add -fsyntax-only option and drop options that triggers output generation.
ArgumentsAdjuster getClangSyntaxOnlyAdjuster() {
return [](const CommandLineArguments &Args, StringRef /*unused*/) {
CommandLineArguments AdjustedArgs;
bool HasSyntaxOnly = false;
+ const std::vector<llvm::StringRef> OutputCommands = {
+ // FIXME: Add other options that generate output.
+ "-save-temps",
+ "--save-temps",
+ };
for (size_t i = 0, e = Args.size(); i < e; ++i) {
StringRef Arg = Args[i];
- // FIXME: Remove options that generate output.
+ // Skip output commands.
+ if (llvm::any_of(OutputCommands, [&Arg](llvm::StringRef OutputCommand) {
+ return Arg.startswith(OutputCommand);
+ }))
+ continue;
+
if (!Arg.startswith("-fcolor-diagnostics") &&
!Arg.startswith("-fdiagnostics-color"))
AdjustedArgs.push_back(Args[i]);
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp
index 7436c7256327..b4d5a29ca695 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp
@@ -122,6 +122,32 @@ DependencyScanningFilesystemSharedCache::get(StringRef Key) {
return It.first->getValue();
}
+/// Whitelist file extensions that should be minimized, treating no extension as
+/// a source file that should be minimized.
+///
+/// This is kinda hacky, it would be better if we knew what kind of file Clang
+/// was expecting instead.
+static bool shouldMinimize(StringRef Filename) {
+ StringRef Ext = llvm::sys::path::extension(Filename);
+ if (Ext.empty())
+ return true; // C++ standard library
+ return llvm::StringSwitch<bool>(Ext)
+ .CasesLower(".c", ".cc", ".cpp", ".c++", ".cxx", true)
+ .CasesLower(".h", ".hh", ".hpp", ".h++", ".hxx", true)
+ .CasesLower(".m", ".mm", true)
+ .CasesLower(".i", ".ii", ".mi", ".mmi", true)
+ .CasesLower(".def", ".inc", true)
+ .Default(false);
+}
+
+
+static bool shouldCacheStatFailures(StringRef Filename) {
+ StringRef Ext = llvm::sys::path::extension(Filename);
+ if (Ext.empty())
+ return false; // This may be the module cache directory.
+ return shouldMinimize(Filename); // Only cache stat failures on source files.
+}
+
llvm::ErrorOr<const CachedFileSystemEntry *>
DependencyScanningWorkerFilesystem::getOrCreateFileSystemEntry(
const StringRef Filename) {
@@ -132,7 +158,8 @@ DependencyScanningWorkerFilesystem::getOrCreateFileSystemEntry(
// FIXME: Handle PCM/PCH files.
// FIXME: Handle module map files.
- bool KeepOriginalSource = IgnoredFiles.count(Filename);
+ bool KeepOriginalSource = IgnoredFiles.count(Filename) ||
+ !shouldMinimize(Filename);
DependencyScanningFilesystemSharedCache::SharedFileSystemEntry
&SharedCacheEntry = SharedCache.get(Filename);
const CachedFileSystemEntry *Result;
@@ -143,9 +170,16 @@ DependencyScanningWorkerFilesystem::getOrCreateFileSystemEntry(
if (!CacheEntry.isValid()) {
llvm::vfs::FileSystem &FS = getUnderlyingFS();
auto MaybeStatus = FS.status(Filename);
- if (!MaybeStatus)
- CacheEntry = CachedFileSystemEntry(MaybeStatus.getError());
- else if (MaybeStatus->isDirectory())
+ if (!MaybeStatus) {
+ if (!shouldCacheStatFailures(Filename))
+ // HACK: We need to always restat non source files if the stat fails.
+ // This is because Clang first looks up the module cache and module
+ // files before building them, and then looks for them again. If we
+ // cache the stat failure, it won't see them the second time.
+ return MaybeStatus.getError();
+ else
+ CacheEntry = CachedFileSystemEntry(MaybeStatus.getError());
+ } else if (MaybeStatus->isDirectory())
CacheEntry = CachedFileSystemEntry::createDirectoryEntry(
std::move(*MaybeStatus));
else
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp
index e5cebe381000..93bb0cde439d 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp
@@ -12,8 +12,8 @@ using namespace clang;
using namespace tooling;
using namespace dependencies;
-DependencyScanningService::DependencyScanningService(ScanningMode Mode,
- bool ReuseFileManager,
- bool SkipExcludedPPRanges)
- : Mode(Mode), ReuseFileManager(ReuseFileManager),
+DependencyScanningService::DependencyScanningService(
+ ScanningMode Mode, ScanningOutputFormat Format, bool ReuseFileManager,
+ bool SkipExcludedPPRanges)
+ : Mode(Mode), Format(Format), ReuseFileManager(ReuseFileManager),
SkipExcludedPPRanges(SkipExcludedPPRanges) {}
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
index 82b3ae806c65..f643c538f8f9 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
@@ -1,4 +1,4 @@
-//===- DependencyScanningTool.cpp - clang-scan-deps service ------------===//
+//===- DependencyScanningTool.cpp - clang-scan-deps service ---------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -8,18 +8,29 @@
#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
#include "clang/Frontend/Utils.h"
+#include "llvm/Support/JSON.h"
+
+static llvm::json::Array toJSONSorted(const llvm::StringSet<> &Set) {
+ std::vector<llvm::StringRef> Strings;
+ for (auto &&I : Set)
+ Strings.push_back(I.getKey());
+ std::sort(Strings.begin(), Strings.end());
+ return llvm::json::Array(Strings);
+}
namespace clang{
namespace tooling{
namespace dependencies{
-DependencyScanningTool::DependencyScanningTool(DependencyScanningService &Service,
-const tooling::CompilationDatabase &Compilations) : Worker(Service), Compilations(Compilations) {}
+DependencyScanningTool::DependencyScanningTool(
+ DependencyScanningService &Service)
+ : Format(Service.getFormat()), Worker(Service) {
+}
-llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(const std::string &Input,
- StringRef CWD) {
+llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(
+ const tooling::CompilationDatabase &Compilations, StringRef CWD) {
/// Prints out all of the gathered dependencies into a string.
- class DependencyPrinterConsumer : public DependencyConsumer {
+ class MakeDependencyPrinterConsumer : public DependencyConsumer {
public:
void handleFileDependency(const DependencyOutputOptions &Opts,
StringRef File) override {
@@ -28,6 +39,14 @@ llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(const std:
Dependencies.push_back(File);
}
+ void handleModuleDependency(ModuleDeps MD) override {
+ // These are ignored for the make format as it can't support the full
+ // set of deps, and handleFileDependency handles enough for implicitly
+ // built modules to work.
+ }
+
+ void handleContextHash(std::string Hash) override {}
+
void printDependencies(std::string &S) {
if (!Opts)
return;
@@ -56,14 +75,98 @@ llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(const std:
std::vector<std::string> Dependencies;
};
- DependencyPrinterConsumer Consumer;
- auto Result =
- Worker.computeDependencies(Input, CWD, Compilations, Consumer);
- if (Result)
- return std::move(Result);
- std::string Output;
- Consumer.printDependencies(Output);
- return Output;
+ class FullDependencyPrinterConsumer : public DependencyConsumer {
+ public:
+ void handleFileDependency(const DependencyOutputOptions &Opts,
+ StringRef File) override {
+ Dependencies.push_back(File);
+ }
+
+ void handleModuleDependency(ModuleDeps MD) override {
+ ClangModuleDeps[MD.ContextHash + MD.ModuleName] = std::move(MD);
+ }
+
+ void handleContextHash(std::string Hash) override {
+ ContextHash = std::move(Hash);
+ }
+
+ void printDependencies(std::string &S, StringRef MainFile) {
+ // Sort the modules by name to get a deterministic order.
+ std::vector<StringRef> Modules;
+ for (auto &&Dep : ClangModuleDeps)
+ Modules.push_back(Dep.first);
+ std::sort(Modules.begin(), Modules.end());
+
+ llvm::raw_string_ostream OS(S);
+
+ using namespace llvm::json;
+
+ Array Imports;
+ for (auto &&ModName : Modules) {
+ auto &MD = ClangModuleDeps[ModName];
+ if (MD.ImportedByMainFile)
+ Imports.push_back(MD.ModuleName);
+ }
+
+ Array Mods;
+ for (auto &&ModName : Modules) {
+ auto &MD = ClangModuleDeps[ModName];
+ Object Mod{
+ {"name", MD.ModuleName},
+ {"file-deps", toJSONSorted(MD.FileDeps)},
+ {"clang-module-deps", toJSONSorted(MD.ClangModuleDeps)},
+ {"clang-modulemap-file", MD.ClangModuleMapFile},
+ };
+ Mods.push_back(std::move(Mod));
+ }
+
+ Object O{
+ {"input-file", MainFile},
+ {"clang-context-hash", ContextHash},
+ {"file-deps", Dependencies},
+ {"clang-module-deps", std::move(Imports)},
+ {"clang-modules", std::move(Mods)},
+ };
+
+ S = llvm::formatv("{0:2},\n", Value(std::move(O))).str();
+ return;
+ }
+
+ private:
+ std::vector<std::string> Dependencies;
+ std::unordered_map<std::string, ModuleDeps> ClangModuleDeps;
+ std::string ContextHash;
+ };
+
+
+ // We expect a single command here because if a source file occurs multiple
+ // times in the original CDB, then `computeDependencies` would run the
+ // `DependencyScanningAction` once for every time the input occured in the
+ // CDB. Instead we split up the CDB into single command chunks to avoid this
+ // behavior.
+ assert(Compilations.getAllCompileCommands().size() == 1 &&
+ "Expected a compilation database with a single command!");
+ std::string Input = Compilations.getAllCompileCommands().front().Filename;
+
+ if (Format == ScanningOutputFormat::Make) {
+ MakeDependencyPrinterConsumer Consumer;
+ auto Result =
+ Worker.computeDependencies(Input, CWD, Compilations, Consumer);
+ if (Result)
+ return std::move(Result);
+ std::string Output;
+ Consumer.printDependencies(Output);
+ return Output;
+ } else {
+ FullDependencyPrinterConsumer Consumer;
+ auto Result =
+ Worker.computeDependencies(Input, CWD, Compilations, Consumer);
+ if (Result)
+ return std::move(Result);
+ std::string Output;
+ Consumer.printDependencies(Output, Input);
+ return Output;
+ }
}
} // end namespace dependencies
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
index f382c202f8c2..edf2cf8bd70f 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
@@ -14,6 +14,7 @@
#include "clang/Frontend/Utils.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
+#include "clang/Tooling/DependencyScanning/ModuleDepCollector.h"
#include "clang/Tooling/Tooling.h"
using namespace clang;
@@ -72,9 +73,11 @@ public:
DependencyScanningAction(
StringRef WorkingDirectory, DependencyConsumer &Consumer,
llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS,
- ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings)
+ ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings,
+ ScanningOutputFormat Format)
: WorkingDirectory(WorkingDirectory), Consumer(Consumer),
- DepFS(std::move(DepFS)), PPSkipMappings(PPSkipMappings) {}
+ DepFS(std::move(DepFS)), PPSkipMappings(PPSkipMappings),
+ Format(Format) {}
bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
FileManager *FileMgr,
@@ -131,9 +134,20 @@ public:
// We need at least one -MT equivalent for the generator to work.
if (Opts->Targets.empty())
Opts->Targets = {"clang-scan-deps dependency"};
- Compiler.addDependencyCollector(
- std::make_shared<DependencyConsumerForwarder>(std::move(Opts),
- Consumer));
+
+ switch (Format) {
+ case ScanningOutputFormat::Make:
+ Compiler.addDependencyCollector(
+ std::make_shared<DependencyConsumerForwarder>(std::move(Opts),
+ Consumer));
+ break;
+ case ScanningOutputFormat::Full:
+ Compiler.addDependencyCollector(
+ std::make_shared<ModuleDepCollector>(Compiler, Consumer));
+ break;
+ }
+
+ Consumer.handleContextHash(Compiler.getInvocation().getModuleHash());
auto Action = std::make_unique<PreprocessOnlyAction>();
const bool Result = Compiler.ExecuteAction(*Action);
@@ -147,12 +161,14 @@ private:
DependencyConsumer &Consumer;
llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS;
ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings;
+ ScanningOutputFormat Format;
};
} // end anonymous namespace
DependencyScanningWorker::DependencyScanningWorker(
- DependencyScanningService &Service) {
+ DependencyScanningService &Service)
+ : Format(Service.getFormat()) {
DiagOpts = new DiagnosticOptions();
PCHContainerOps = std::make_shared<PCHContainerOperations>();
RealFS = new ProxyFileSystemWithoutChdir(llvm::vfs::getRealFileSystem());
@@ -195,7 +211,7 @@ llvm::Error DependencyScanningWorker::computeDependencies(
Tool.setPrintErrorMessage(false);
Tool.setDiagnosticConsumer(&DC);
DependencyScanningAction Action(WorkingDirectory, Consumer, DepFS,
- PPSkipMappings.get());
+ PPSkipMappings.get(), Format);
return !Tool.run(&Action);
});
}
diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
new file mode 100644
index 000000000000..422940047f2d
--- /dev/null
+++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
@@ -0,0 +1,135 @@
+//===- ModuleDepCollector.cpp - Callbacks to collect deps -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/DependencyScanning/ModuleDepCollector.h"
+
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
+
+using namespace clang;
+using namespace tooling;
+using namespace dependencies;
+
+void ModuleDepCollectorPP::FileChanged(SourceLocation Loc,
+ FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType,
+ FileID PrevFID) {
+ if (Reason != PPCallbacks::EnterFile)
+ return;
+
+ SourceManager &SM = Instance.getSourceManager();
+
+ // 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!
+ Optional<FileEntryRef> File =
+ SM.getFileEntryRefForID(SM.getFileID(SM.getExpansionLoc(Loc)));
+ if (!File)
+ return;
+
+ StringRef FileName =
+ llvm::sys::path::remove_leading_dotslash(File->getName());
+
+ MDC.MainDeps.push_back(FileName);
+}
+
+void ModuleDepCollectorPP::InclusionDirective(
+ SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
+ bool IsAngled, CharSourceRange FilenameRange, const FileEntry *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.MainDeps.push_back(FileName);
+ }
+
+ if (!Imported)
+ return;
+
+ MDC.Deps[MDC.ContextHash + Imported->getTopLevelModule()->getFullModuleName()]
+ .ImportedByMainFile = true;
+ DirectDeps.insert(Imported->getTopLevelModule());
+}
+
+void ModuleDepCollectorPP::EndOfMainFile() {
+ FileID MainFileID = Instance.getSourceManager().getMainFileID();
+ MDC.MainFile =
+ Instance.getSourceManager().getFileEntryForID(MainFileID)->getName();
+
+ for (const Module *M : DirectDeps) {
+ handleTopLevelModule(M);
+ }
+
+ for (auto &&I : MDC.Deps)
+ MDC.Consumer.handleModuleDependency(I.second);
+
+ DependencyOutputOptions Opts;
+ for (auto &&I : MDC.MainDeps)
+ MDC.Consumer.handleFileDependency(Opts, I);
+}
+
+void ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
+ assert(M == M->getTopLevelModule() && "Expected top level module!");
+
+ auto ModI = MDC.Deps.insert(
+ std::make_pair(MDC.ContextHash + M->getFullModuleName(), ModuleDeps{}));
+
+ if (!ModI.first->second.ModuleName.empty())
+ return;
+
+ ModuleDeps &MD = ModI.first->second;
+
+ const FileEntry *ModuleMap = Instance.getPreprocessor()
+ .getHeaderSearchInfo()
+ .getModuleMap()
+ .getContainingModuleMapFile(M);
+
+ MD.ClangModuleMapFile = ModuleMap ? ModuleMap->getName() : "";
+ MD.ModuleName = M->getFullModuleName();
+ MD.ModulePCMPath = M->getASTFile()->getName();
+ MD.ContextHash = MDC.ContextHash;
+ serialization::ModuleFile *MF =
+ MDC.Instance.getASTReader()->getModuleManager().lookup(M->getASTFile());
+ MDC.Instance.getASTReader()->visitInputFiles(
+ *MF, true, true, [&](const serialization::InputFile &IF, bool isSystem) {
+ MD.FileDeps.insert(IF.getFile()->getName());
+ });
+
+ addAllSubmoduleDeps(M, MD);
+}
+
+void ModuleDepCollectorPP::addAllSubmoduleDeps(const Module *M,
+ ModuleDeps &MD) {
+ addModuleDep(M, MD);
+
+ for (const Module *SubM : M->submodules())
+ addAllSubmoduleDeps(SubM, MD);
+}
+
+void ModuleDepCollectorPP::addModuleDep(const Module *M, ModuleDeps &MD) {
+ for (const Module *Import : M->Imports) {
+ if (Import->getTopLevelModule() != M->getTopLevelModule()) {
+ MD.ClangModuleDeps.insert(Import->getTopLevelModuleName());
+ handleTopLevelModule(Import->getTopLevelModule());
+ }
+ }
+}
+
+ModuleDepCollector::ModuleDepCollector(CompilerInstance &I,
+ DependencyConsumer &C)
+ : Instance(I), Consumer(C), ContextHash(I.getInvocation().getModuleHash()) {
+}
+
+void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) {
+ PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(Instance, *this));
+}
+
+void ModuleDepCollector::attachToASTReader(ASTReader &R) {}
diff --git a/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp b/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp
new file mode 100644
index 000000000000..99298316718b
--- /dev/null
+++ b/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp
@@ -0,0 +1,90 @@
+//===- ExpandResponseFileCompilationDataBase.cpp --------------------------===//
+//
+// 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/CompilationDatabase.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/StringSaver.h"
+
+namespace clang {
+namespace tooling {
+namespace {
+
+class ExpandResponseFilesDatabase : public CompilationDatabase {
+public:
+ ExpandResponseFilesDatabase(
+ std::unique_ptr<CompilationDatabase> Base,
+ llvm::cl::TokenizerCallback Tokenizer,
+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
+ : Base(std::move(Base)), Tokenizer(Tokenizer), FS(std::move(FS)) {
+ assert(this->Base != nullptr);
+ assert(this->Tokenizer != nullptr);
+ assert(this->FS != nullptr);
+ }
+
+ std::vector<std::string> getAllFiles() const override {
+ return Base->getAllFiles();
+ }
+
+ std::vector<CompileCommand>
+ getCompileCommands(StringRef FilePath) const override {
+ return expand(Base->getCompileCommands(FilePath));
+ }
+
+ std::vector<CompileCommand> getAllCompileCommands() const override {
+ return expand(Base->getAllCompileCommands());
+ }
+
+private:
+ std::vector<CompileCommand> expand(std::vector<CompileCommand> Cmds) const {
+ for (auto &Cmd : Cmds) {
+ bool SeenRSPFile = false;
+ llvm::SmallVector<const char *, 20> Argv;
+ Argv.reserve(Cmd.CommandLine.size());
+ for (auto &Arg : Cmd.CommandLine) {
+ Argv.push_back(Arg.c_str());
+ SeenRSPFile |= Arg.front() == '@';
+ }
+ if (!SeenRSPFile)
+ continue;
+ llvm::BumpPtrAllocator Alloc;
+ llvm::StringSaver Saver(Alloc);
+ llvm::cl::ExpandResponseFiles(Saver, Tokenizer, Argv, false, false, *FS,
+ llvm::StringRef(Cmd.Directory));
+ // Don't assign directly, Argv aliases CommandLine.
+ std::vector<std::string> ExpandedArgv(Argv.begin(), Argv.end());
+ Cmd.CommandLine = std::move(ExpandedArgv);
+ }
+ return Cmds;
+ }
+
+private:
+ std::unique_ptr<CompilationDatabase> Base;
+ llvm::cl::TokenizerCallback Tokenizer;
+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS;
+};
+
+} // namespace
+
+std::unique_ptr<CompilationDatabase>
+expandResponseFiles(std::unique_ptr<CompilationDatabase> Base,
+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) {
+ auto Tokenizer = llvm::Triple(llvm::sys::getProcessTriple()).isOSWindows()
+ ? llvm::cl::TokenizeWindowsCommandLine
+ : llvm::cl::TokenizeGNUCommandLine;
+ return std::make_unique<ExpandResponseFilesDatabase>(
+ std::move(Base), Tokenizer, std::move(FS));
+}
+
+} // namespace tooling
+} // namespace clang
diff --git a/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp b/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp
index e746bbb7f87b..37a0816c803e 100644
--- a/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp
+++ b/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp
@@ -184,6 +184,10 @@ IncludeCategoryManager::IncludeCategoryManager(const IncludeStyle &Style,
FileName.endswith(".cpp") || FileName.endswith(".c++") ||
FileName.endswith(".cxx") || FileName.endswith(".m") ||
FileName.endswith(".mm");
+ if (!Style.IncludeIsMainSourceRegex.empty()) {
+ llvm::Regex MainFileRegex(Style.IncludeIsMainSourceRegex);
+ IsMainFile |= MainFileRegex.match(FileName);
+ }
}
int IncludeCategoryManager::getIncludePriority(StringRef IncludeName,
@@ -364,6 +368,5 @@ tooling::Replacements HeaderIncludes::remove(llvm::StringRef IncludeName,
return Result;
}
-
} // namespace tooling
} // namespace clang
diff --git a/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp b/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
index 59b66abe65e9..2cc819a498c6 100644
--- a/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
+++ b/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
@@ -191,7 +191,8 @@ struct TransferableCommand {
OldArgs.data() + OldPos, OldArgs.data() + Pos);
}
- if (Std != LangStandard::lang_unspecified) // -std take precedence over -x
+ // Make use of -std iff -x was missing.
+ if (Type == types::TY_INVALID && Std != LangStandard::lang_unspecified)
Type = toType(LangStandard::getLangStandardForKind(Std).getLanguage());
Type = foldType(*Type);
// The contract is to store None instead of TY_INVALID.
diff --git a/clang/lib/Tooling/JSONCompilationDatabase.cpp b/clang/lib/Tooling/JSONCompilationDatabase.cpp
index f19a0f7550b9..04dd4dbf6248 100644
--- a/clang/lib/Tooling/JSONCompilationDatabase.cpp
+++ b/clang/lib/Tooling/JSONCompilationDatabase.cpp
@@ -29,6 +29,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/YAMLParser.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
@@ -168,7 +169,8 @@ class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin {
auto Base = JSONCompilationDatabase::loadFromFile(
JSONDatabasePath, ErrorMessage, JSONCommandLineSyntax::AutoDetect);
return Base ? inferTargetAndDriverMode(
- inferMissingCompileCommands(std::move(Base)))
+ inferMissingCompileCommands(expandResponseFiles(
+ std::move(Base), llvm::vfs::getRealFileSystem())))
: nullptr;
}
};
diff --git a/clang/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp b/clang/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp
index 7dfd3988d904..70a4df07ea67 100644
--- a/clang/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp
+++ b/clang/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h"
+#include "clang/AST/Attr.h"
using namespace clang;
using namespace tooling;
diff --git a/clang/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp b/clang/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp
index e26248f50c29..d966a5ef23c2 100644
--- a/clang/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp
+++ b/clang/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp
@@ -39,6 +39,8 @@ namespace clang {
namespace tooling {
const NamedDecl *getCanonicalSymbolDeclaration(const NamedDecl *FoundDecl) {
+ if (!FoundDecl)
+ return nullptr;
// If FoundDecl is a constructor or destructor, we want to instead take
// the Decl of the corresponding class.
if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FoundDecl))
@@ -65,7 +67,7 @@ public:
std::vector<std::string> Find() {
// Fill OverriddenMethods and PartialSpecs storages.
- TraverseDecl(Context.getTranslationUnitDecl());
+ TraverseAST(Context);
if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FoundDecl)) {
addUSRsOfOverridenFunctions(MethodDecl);
for (const auto &OverriddenMethod : OverriddenMethods) {
diff --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp
index a0b653df133d..aa8844771d37 100644
--- a/clang/lib/Tooling/Syntax/BuildTree.cpp
+++ b/clang/lib/Tooling/Syntax/BuildTree.cpp
@@ -6,6 +6,8 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Tooling/Syntax/BuildTree.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Stmt.h"
#include "clang/Basic/LLVM.h"
@@ -21,12 +23,17 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
using namespace clang;
+LLVM_ATTRIBUTE_UNUSED
+static bool isImplicitExpr(clang::Expr *E) { return E->IgnoreImplicit() != E; }
+
/// A helper class for constructing the syntax tree while traversing a clang
/// AST.
///
@@ -44,7 +51,10 @@ using namespace clang;
/// Call finalize() to finish building the tree and consume the root node.
class syntax::TreeBuilder {
public:
- TreeBuilder(syntax::Arena &Arena) : Arena(Arena), Pending(Arena) {}
+ TreeBuilder(syntax::Arena &Arena) : Arena(Arena), Pending(Arena) {
+ for (const auto &T : Arena.tokenBuffer().expandedTokens())
+ LocationToToken.insert({T.location().getRawEncoding(), &T});
+ }
llvm::BumpPtrAllocator &allocator() { return Arena.allocator(); }
@@ -52,8 +62,25 @@ public:
/// Range.
void foldNode(llvm::ArrayRef<syntax::Token> Range, syntax::Tree *New);
+ /// Must be called with the range of each `DeclaratorDecl`. Ensures the
+ /// corresponding declarator nodes are covered by `SimpleDeclaration`.
+ void noticeDeclaratorRange(llvm::ArrayRef<syntax::Token> Range);
+
+ /// Notifies that we should not consume trailing semicolon when computing
+ /// token range of \p D.
+ void noticeDeclaratorWithoutSemicolon(Decl *D);
+
+ /// Mark the \p Child node with a corresponding \p Role. All marked children
+ /// should be consumed by foldNode.
+ /// (!) when called on expressions (clang::Expr is derived from clang::Stmt),
+ /// wraps expressions into expression statement.
+ void markStmtChild(Stmt *Child, NodeRole Role);
+ /// Should be called for expressions in non-statement position to avoid
+ /// wrapping into expression statement.
+ void markExprChild(Expr *Child, NodeRole Role);
+
/// Set role for a token starting at \p Loc.
- void markChildToken(SourceLocation Loc, tok::TokenKind Kind, NodeRole R);
+ void markChildToken(SourceLocation Loc, NodeRole R);
/// Finish building the tree and consume the root node.
syntax::TranslationUnit *finalize() && {
@@ -62,10 +89,12 @@ public:
assert(Tokens.back().kind() == tok::eof);
// Build the root of the tree, consuming all the children.
- Pending.foldChildren(Tokens.drop_back(),
+ Pending.foldChildren(Arena, Tokens.drop_back(),
new (Arena.allocator()) syntax::TranslationUnit);
- return cast<syntax::TranslationUnit>(std::move(Pending).finalize());
+ auto *TU = cast<syntax::TranslationUnit>(std::move(Pending).finalize());
+ TU->assertInvariantsRecursive();
+ return TU;
}
/// getRange() finds the syntax tokens corresponding to the passed source
@@ -81,13 +110,43 @@ public:
return llvm::makeArrayRef(findToken(First), std::next(findToken(Last)));
}
llvm::ArrayRef<syntax::Token> getRange(const Decl *D) const {
- return getRange(D->getBeginLoc(), D->getEndLoc());
+ auto Tokens = getRange(D->getBeginLoc(), D->getEndLoc());
+ if (llvm::isa<NamespaceDecl>(D))
+ return Tokens;
+ if (DeclsWithoutSemicolons.count(D))
+ return Tokens;
+ // FIXME: do not consume trailing semicolon on function definitions.
+ // Most declarations own a semicolon in syntax trees, but not in clang AST.
+ return withTrailingSemicolon(Tokens);
}
- llvm::ArrayRef<syntax::Token> getRange(const Stmt *S) const {
- return getRange(S->getBeginLoc(), S->getEndLoc());
+ llvm::ArrayRef<syntax::Token> getExprRange(const Expr *E) const {
+ return getRange(E->getBeginLoc(), E->getEndLoc());
+ }
+ /// Find the adjusted range for the statement, consuming the trailing
+ /// semicolon when needed.
+ llvm::ArrayRef<syntax::Token> getStmtRange(const Stmt *S) const {
+ auto Tokens = getRange(S->getBeginLoc(), S->getEndLoc());
+ if (isa<CompoundStmt>(S))
+ return Tokens;
+
+ // Some statements miss a trailing semicolon, e.g. 'return', 'continue' and
+ // all statements that end with those. Consume this semicolon here.
+ if (Tokens.back().kind() == tok::semi)
+ return Tokens;
+ return withTrailingSemicolon(Tokens);
}
private:
+ llvm::ArrayRef<syntax::Token>
+ withTrailingSemicolon(llvm::ArrayRef<syntax::Token> Tokens) const {
+ assert(!Tokens.empty());
+ 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 Tokens;
+ }
+
/// Finds a token starting at \p L. The token must exist.
const syntax::Token *findToken(SourceLocation L) const;
@@ -103,11 +162,16 @@ private:
assert(A.tokenBuffer().expandedTokens().back().kind() == tok::eof);
// Create all leaf nodes.
// Note that we do not have 'eof' in the tree.
- for (auto &T : A.tokenBuffer().expandedTokens().drop_back())
- Trees.insert(Trees.end(),
- {&T, NodeAndRole{new (A.allocator()) syntax::Leaf(&T)}});
+ for (auto &T : A.tokenBuffer().expandedTokens().drop_back()) {
+ auto *L = new (A.allocator()) syntax::Leaf(&T);
+ L->Original = true;
+ L->CanModify = A.tokenBuffer().spelledForExpanded(T).hasValue();
+ Trees.insert(Trees.end(), {&T, NodeAndRole{L}});
+ }
}
+ ~Forest() { assert(DelayedFolds.empty()); }
+
void assignRole(llvm::ArrayRef<syntax::Token> Range,
syntax::NodeRole Role) {
assert(!Range.empty());
@@ -120,30 +184,47 @@ private:
It->second.Role = Role;
}
- /// Add \p Node to the forest and fill its children nodes based on the \p
- /// NodeRange.
- void foldChildren(llvm::ArrayRef<syntax::Token> NodeTokens,
+ /// Add \p Node to the forest and attach child nodes based on \p Tokens.
+ void foldChildren(const syntax::Arena &A,
+ llvm::ArrayRef<syntax::Token> Tokens,
syntax::Tree *Node) {
- assert(!NodeTokens.empty());
- assert(Node->firstChild() == nullptr && "node already has children");
+ // Execute delayed folds inside `Tokens`.
+ auto BeginExecuted = DelayedFolds.lower_bound(Tokens.begin());
+ auto It = BeginExecuted;
+ for (; It != DelayedFolds.end() && It->second.End <= Tokens.end(); ++It)
+ foldChildrenEager(A, llvm::makeArrayRef(It->first, It->second.End),
+ It->second.Node);
+ DelayedFolds.erase(BeginExecuted, It);
- auto *FirstToken = NodeTokens.begin();
- auto BeginChildren = Trees.lower_bound(FirstToken);
- assert(BeginChildren != Trees.end() &&
- BeginChildren->first == FirstToken &&
- "fold crosses boundaries of existing subtrees");
- auto EndChildren = Trees.lower_bound(NodeTokens.end());
- assert((EndChildren == Trees.end() ||
- EndChildren->first == NodeTokens.end()) &&
- "fold crosses boundaries of existing subtrees");
+ // Attach children to `Node`.
+ foldChildrenEager(A, Tokens, Node);
+ }
- // (!) we need to go in reverse order, because we can only prepend.
- for (auto It = EndChildren; It != BeginChildren; --It)
- Node->prependChildLowLevel(std::prev(It)->second.Node,
- std::prev(It)->second.Role);
+ /// Schedule a call to `foldChildren` that will only be executed when
+ /// containing node is folded. The range of delayed nodes can be extended by
+ /// calling `extendDelayedFold`. Only one delayed node for each starting
+ /// token is allowed.
+ void foldChildrenDelayed(llvm::ArrayRef<syntax::Token> Tokens,
+ syntax::Tree *Node) {
+ assert(!Tokens.empty());
+ bool Inserted =
+ DelayedFolds.insert({Tokens.begin(), DelayedFold{Tokens.end(), Node}})
+ .second;
+ (void)Inserted;
+ assert(Inserted && "Multiple delayed folds start at the same token");
+ }
- Trees.erase(BeginChildren, EndChildren);
- Trees.insert({FirstToken, NodeAndRole(Node)});
+ /// If there a delayed fold, starting at `ExtendedRange.begin()`, extends
+ /// its endpoint to `ExtendedRange.end()` and returns true.
+ /// Otherwise, returns false.
+ bool extendDelayedFold(llvm::ArrayRef<syntax::Token> ExtendedRange) {
+ assert(!ExtendedRange.empty());
+ auto It = DelayedFolds.find(ExtendedRange.data());
+ if (It == DelayedFolds.end())
+ return false;
+ assert(It->second.End <= ExtendedRange.end());
+ It->second.End = ExtendedRange.end();
+ return true;
}
// EXPECTS: all tokens were consumed and are owned by a single root node.
@@ -171,6 +252,35 @@ private:
}
private:
+ /// Implementation detail of `foldChildren`, does acutal folding ignoring
+ /// delayed folds.
+ void foldChildrenEager(const syntax::Arena &A,
+ llvm::ArrayRef<syntax::Token> Tokens,
+ syntax::Tree *Node) {
+ assert(Node->firstChild() == nullptr && "node already has children");
+
+ auto *FirstToken = Tokens.begin();
+ auto BeginChildren = Trees.lower_bound(FirstToken);
+ assert((BeginChildren == Trees.end() ||
+ BeginChildren->first == FirstToken) &&
+ "fold crosses boundaries of existing subtrees");
+ auto EndChildren = Trees.lower_bound(Tokens.end());
+ assert(
+ (EndChildren == Trees.end() || EndChildren->first == Tokens.end()) &&
+ "fold crosses boundaries of existing subtrees");
+
+ // (!) we need to go in reverse order, because we can only prepend.
+ for (auto It = EndChildren; It != BeginChildren; --It)
+ Node->prependChildLowLevel(std::prev(It)->second.Node,
+ std::prev(It)->second.Role);
+
+ // Mark that this node came from the AST and is backed by the source code.
+ Node->Original = true;
+ Node->CanModify = A.tokenBuffer().spelledForExpanded(Tokens).hasValue();
+
+ Trees.erase(BeginChildren, EndChildren);
+ Trees.insert({FirstToken, NodeAndRole(Node)});
+ }
/// A with a role that should be assigned to it when adding to a parent.
struct NodeAndRole {
explicit NodeAndRole(syntax::Node *Node)
@@ -181,16 +291,29 @@ private:
};
/// Maps from the start token to a subtree starting at that token.
+ /// Keys in the map are pointers into the array of expanded tokens, so
+ /// pointer order corresponds to the order of preprocessor tokens.
/// FIXME: storing the end tokens is redundant.
/// FIXME: the key of a map is redundant, it is also stored in NodeForRange.
std::map<const syntax::Token *, NodeAndRole> Trees;
+
+ /// See documentation of `foldChildrenDelayed` for details.
+ struct DelayedFold {
+ const syntax::Token *End = nullptr;
+ syntax::Tree *Node = nullptr;
+ };
+ std::map<const syntax::Token *, DelayedFold> DelayedFolds;
};
/// For debugging purposes.
std::string str() { return Pending.str(Arena); }
syntax::Arena &Arena;
+ /// To quickly find tokens by their start location.
+ llvm::DenseMap</*SourceLocation*/ unsigned, const syntax::Token *>
+ LocationToToken;
Forest Pending;
+ llvm::DenseSet<Decl *> DeclsWithoutSemicolons;
};
namespace {
@@ -201,20 +324,34 @@ public:
bool shouldTraversePostOrder() const { return true; }
- bool TraverseDecl(Decl *D) {
- if (!D || isa<TranslationUnitDecl>(D))
- return RecursiveASTVisitor::TraverseDecl(D);
- if (!llvm::isa<TranslationUnitDecl>(D->getDeclContext()))
- return true; // Only build top-level decls for now, do not recurse.
- return RecursiveASTVisitor::TraverseDecl(D);
+ bool WalkUpFromDeclaratorDecl(DeclaratorDecl *D) {
+ // Ensure declarators are covered by SimpleDeclaration.
+ Builder.noticeDeclaratorRange(Builder.getRange(D));
+ // FIXME: build nodes for the declarator too.
+ return true;
+ }
+ bool WalkUpFromTypedefNameDecl(TypedefNameDecl *D) {
+ // Also a declarator.
+ Builder.noticeDeclaratorRange(Builder.getRange(D));
+ // FIXME: build nodes for the declarator too.
+ return true;
}
bool VisitDecl(Decl *D) {
- assert(llvm::isa<TranslationUnitDecl>(D->getDeclContext()) &&
- "expected a top-level decl");
assert(!D->isImplicit());
Builder.foldNode(Builder.getRange(D),
- new (allocator()) syntax::TopLevelDeclaration());
+ new (allocator()) syntax::UnknownDeclaration());
+ return true;
+ }
+
+ bool WalkUpFromTagDecl(TagDecl *C) {
+ // FIXME: build the ClassSpecifier node.
+ if (C->isFreeStanding()) {
+ // Class is a declaration specifier and needs a spanning declaration node.
+ Builder.foldNode(Builder.getRange(C),
+ new (allocator()) syntax::SimpleDeclaration);
+ return true;
+ }
return true;
}
@@ -227,16 +364,238 @@ public:
bool WalkUpFromCompoundStmt(CompoundStmt *S) {
using NodeRole = syntax::NodeRole;
- Builder.markChildToken(S->getLBracLoc(), tok::l_brace,
- NodeRole::CompoundStatement_lbrace);
- Builder.markChildToken(S->getRBracLoc(), tok::r_brace,
- NodeRole::CompoundStatement_rbrace);
+ Builder.markChildToken(S->getLBracLoc(), NodeRole::OpenParen);
+ for (auto *Child : S->body())
+ Builder.markStmtChild(Child, NodeRole::CompoundStatement_statement);
+ Builder.markChildToken(S->getRBracLoc(), NodeRole::CloseParen);
- Builder.foldNode(Builder.getRange(S),
+ Builder.foldNode(Builder.getStmtRange(S),
new (allocator()) syntax::CompoundStatement);
return true;
}
+ // Some statements are not yet handled by syntax trees.
+ bool WalkUpFromStmt(Stmt *S) {
+ Builder.foldNode(Builder.getStmtRange(S),
+ new (allocator()) syntax::UnknownStatement);
+ return true;
+ }
+
+ bool TraverseCXXForRangeStmt(CXXForRangeStmt *S) {
+ // We override to traverse range initializer as VarDecl.
+ // RAV traverses it as a statement, we produce invalid node kinds in that
+ // case.
+ // FIXME: should do this in RAV instead?
+ if (S->getInit() && !TraverseStmt(S->getInit()))
+ return false;
+ if (S->getLoopVariable() && !TraverseDecl(S->getLoopVariable()))
+ return false;
+ if (S->getRangeInit() && !TraverseStmt(S->getRangeInit()))
+ return false;
+ if (S->getBody() && !TraverseStmt(S->getBody()))
+ return false;
+ return true;
+ }
+
+ bool TraverseStmt(Stmt *S) {
+ if (auto *DS = llvm::dyn_cast_or_null<DeclStmt>(S)) {
+ // We want to consume the semicolon, make sure SimpleDeclaration does not.
+ for (auto *D : DS->decls())
+ Builder.noticeDeclaratorWithoutSemicolon(D);
+ } else if (auto *E = llvm::dyn_cast_or_null<Expr>(S)) {
+ // (!) do not recurse into subexpressions.
+ // we do not have syntax trees for expressions yet, so we only want to see
+ // the first top-level expression.
+ return WalkUpFromExpr(E->IgnoreImplicit());
+ }
+ return RecursiveASTVisitor::TraverseStmt(S);
+ }
+
+ // Some expressions are not yet handled by syntax trees.
+ bool WalkUpFromExpr(Expr *E) {
+ assert(!isImplicitExpr(E) && "should be handled by TraverseStmt");
+ Builder.foldNode(Builder.getExprRange(E),
+ new (allocator()) syntax::UnknownExpression);
+ return true;
+ }
+
+ bool WalkUpFromNamespaceDecl(NamespaceDecl *S) {
+ auto Tokens = Builder.getRange(S);
+ if (Tokens.front().kind() == tok::coloncolon) {
+ // Handle nested namespace definitions. Those start at '::' token, e.g.
+ // namespace a^::b {}
+ // FIXME: build corresponding nodes for the name of this namespace.
+ return true;
+ }
+ Builder.foldNode(Tokens, new (allocator()) syntax::NamespaceDefinition);
+ return true;
+ }
+
+ // The code below is very regular, it could even be generated with some
+ // preprocessor magic. We merely assign roles to the corresponding children
+ // and fold resulting nodes.
+ bool WalkUpFromDeclStmt(DeclStmt *S) {
+ Builder.foldNode(Builder.getStmtRange(S),
+ new (allocator()) syntax::DeclarationStatement);
+ return true;
+ }
+
+ bool WalkUpFromNullStmt(NullStmt *S) {
+ Builder.foldNode(Builder.getStmtRange(S),
+ new (allocator()) syntax::EmptyStatement);
+ return true;
+ }
+
+ bool WalkUpFromSwitchStmt(SwitchStmt *S) {
+ Builder.markChildToken(S->getSwitchLoc(),
+ syntax::NodeRole::IntroducerKeyword);
+ Builder.markStmtChild(S->getBody(), syntax::NodeRole::BodyStatement);
+ Builder.foldNode(Builder.getStmtRange(S),
+ new (allocator()) syntax::SwitchStatement);
+ return true;
+ }
+
+ bool WalkUpFromCaseStmt(CaseStmt *S) {
+ Builder.markChildToken(S->getKeywordLoc(),
+ syntax::NodeRole::IntroducerKeyword);
+ Builder.markExprChild(S->getLHS(), syntax::NodeRole::CaseStatement_value);
+ Builder.markStmtChild(S->getSubStmt(), syntax::NodeRole::BodyStatement);
+ Builder.foldNode(Builder.getStmtRange(S),
+ new (allocator()) syntax::CaseStatement);
+ return true;
+ }
+
+ bool WalkUpFromDefaultStmt(DefaultStmt *S) {
+ Builder.markChildToken(S->getKeywordLoc(),
+ syntax::NodeRole::IntroducerKeyword);
+ Builder.markStmtChild(S->getSubStmt(), syntax::NodeRole::BodyStatement);
+ Builder.foldNode(Builder.getStmtRange(S),
+ new (allocator()) syntax::DefaultStatement);
+ return true;
+ }
+
+ bool WalkUpFromIfStmt(IfStmt *S) {
+ Builder.markChildToken(S->getIfLoc(), syntax::NodeRole::IntroducerKeyword);
+ Builder.markStmtChild(S->getThen(),
+ syntax::NodeRole::IfStatement_thenStatement);
+ Builder.markChildToken(S->getElseLoc(),
+ syntax::NodeRole::IfStatement_elseKeyword);
+ Builder.markStmtChild(S->getElse(),
+ syntax::NodeRole::IfStatement_elseStatement);
+ Builder.foldNode(Builder.getStmtRange(S),
+ new (allocator()) syntax::IfStatement);
+ return true;
+ }
+
+ bool WalkUpFromForStmt(ForStmt *S) {
+ Builder.markChildToken(S->getForLoc(), syntax::NodeRole::IntroducerKeyword);
+ Builder.markStmtChild(S->getBody(), syntax::NodeRole::BodyStatement);
+ Builder.foldNode(Builder.getStmtRange(S),
+ new (allocator()) syntax::ForStatement);
+ return true;
+ }
+
+ bool WalkUpFromWhileStmt(WhileStmt *S) {
+ Builder.markChildToken(S->getWhileLoc(),
+ syntax::NodeRole::IntroducerKeyword);
+ Builder.markStmtChild(S->getBody(), syntax::NodeRole::BodyStatement);
+ Builder.foldNode(Builder.getStmtRange(S),
+ new (allocator()) syntax::WhileStatement);
+ return true;
+ }
+
+ bool WalkUpFromContinueStmt(ContinueStmt *S) {
+ Builder.markChildToken(S->getContinueLoc(),
+ syntax::NodeRole::IntroducerKeyword);
+ Builder.foldNode(Builder.getStmtRange(S),
+ new (allocator()) syntax::ContinueStatement);
+ return true;
+ }
+
+ bool WalkUpFromBreakStmt(BreakStmt *S) {
+ Builder.markChildToken(S->getBreakLoc(),
+ syntax::NodeRole::IntroducerKeyword);
+ Builder.foldNode(Builder.getStmtRange(S),
+ new (allocator()) syntax::BreakStatement);
+ return true;
+ }
+
+ bool WalkUpFromReturnStmt(ReturnStmt *S) {
+ Builder.markChildToken(S->getReturnLoc(),
+ syntax::NodeRole::IntroducerKeyword);
+ Builder.markExprChild(S->getRetValue(),
+ syntax::NodeRole::ReturnStatement_value);
+ Builder.foldNode(Builder.getStmtRange(S),
+ new (allocator()) syntax::ReturnStatement);
+ return true;
+ }
+
+ bool WalkUpFromCXXForRangeStmt(CXXForRangeStmt *S) {
+ Builder.markChildToken(S->getForLoc(), syntax::NodeRole::IntroducerKeyword);
+ Builder.markStmtChild(S->getBody(), syntax::NodeRole::BodyStatement);
+ Builder.foldNode(Builder.getStmtRange(S),
+ new (allocator()) syntax::RangeBasedForStatement);
+ return true;
+ }
+
+ bool WalkUpFromEmptyDecl(EmptyDecl *S) {
+ Builder.foldNode(Builder.getRange(S),
+ new (allocator()) syntax::EmptyDeclaration);
+ return true;
+ }
+
+ bool WalkUpFromStaticAssertDecl(StaticAssertDecl *S) {
+ Builder.markExprChild(S->getAssertExpr(),
+ syntax::NodeRole::StaticAssertDeclaration_condition);
+ Builder.markExprChild(S->getMessage(),
+ syntax::NodeRole::StaticAssertDeclaration_message);
+ Builder.foldNode(Builder.getRange(S),
+ new (allocator()) syntax::StaticAssertDeclaration);
+ return true;
+ }
+
+ bool WalkUpFromLinkageSpecDecl(LinkageSpecDecl *S) {
+ Builder.foldNode(Builder.getRange(S),
+ new (allocator()) syntax::LinkageSpecificationDeclaration);
+ return true;
+ }
+
+ bool WalkUpFromNamespaceAliasDecl(NamespaceAliasDecl *S) {
+ Builder.foldNode(Builder.getRange(S),
+ new (allocator()) syntax::NamespaceAliasDefinition);
+ return true;
+ }
+
+ bool WalkUpFromUsingDirectiveDecl(UsingDirectiveDecl *S) {
+ Builder.foldNode(Builder.getRange(S),
+ new (allocator()) syntax::UsingNamespaceDirective);
+ return true;
+ }
+
+ bool WalkUpFromUsingDecl(UsingDecl *S) {
+ Builder.foldNode(Builder.getRange(S),
+ new (allocator()) syntax::UsingDeclaration);
+ return true;
+ }
+
+ bool WalkUpFromUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *S) {
+ Builder.foldNode(Builder.getRange(S),
+ new (allocator()) syntax::UsingDeclaration);
+ return true;
+ }
+
+ bool WalkUpFromUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *S) {
+ Builder.foldNode(Builder.getRange(S),
+ new (allocator()) syntax::UsingDeclaration);
+ return true;
+ }
+
+ bool WalkUpFromTypeAliasDecl(TypeAliasDecl *S) {
+ Builder.foldNode(Builder.getRange(S),
+ new (allocator()) syntax::TypeAliasDeclaration);
+ return true;
+ }
+
private:
/// A small helper to save some typing.
llvm::BumpPtrAllocator &allocator() { return Builder.allocator(); }
@@ -248,25 +607,55 @@ private:
void syntax::TreeBuilder::foldNode(llvm::ArrayRef<syntax::Token> Range,
syntax::Tree *New) {
- Pending.foldChildren(Range, New);
+ Pending.foldChildren(Arena, Range, New);
+}
+
+void syntax::TreeBuilder::noticeDeclaratorRange(
+ llvm::ArrayRef<syntax::Token> Range) {
+ if (Pending.extendDelayedFold(Range))
+ return;
+ Pending.foldChildrenDelayed(Range,
+ new (allocator()) syntax::SimpleDeclaration);
+}
+
+void syntax::TreeBuilder::noticeDeclaratorWithoutSemicolon(Decl *D) {
+ DeclsWithoutSemicolons.insert(D);
}
-void syntax::TreeBuilder::markChildToken(SourceLocation Loc,
- tok::TokenKind Kind, NodeRole Role) {
+void syntax::TreeBuilder::markChildToken(SourceLocation Loc, NodeRole Role) {
if (Loc.isInvalid())
return;
Pending.assignRole(*findToken(Loc), Role);
}
+void syntax::TreeBuilder::markStmtChild(Stmt *Child, NodeRole Role) {
+ if (!Child)
+ return;
+
+ auto Range = getStmtRange(Child);
+ // This is an expression in a statement position, consume the trailing
+ // semicolon and form an 'ExpressionStatement' node.
+ if (auto *E = dyn_cast<Expr>(Child)) {
+ Pending.assignRole(getExprRange(E),
+ NodeRole::ExpressionStatement_expression);
+ // (!) 'getRange(Stmt)' ensures this already covers a trailing semicolon.
+ Pending.foldChildren(Arena, Range,
+ new (allocator()) syntax::ExpressionStatement);
+ }
+ Pending.assignRole(Range, Role);
+}
+
+void syntax::TreeBuilder::markExprChild(Expr *Child, NodeRole Role) {
+ if (!Child)
+ return;
+
+ Pending.assignRole(getExprRange(Child), Role);
+}
+
const syntax::Token *syntax::TreeBuilder::findToken(SourceLocation L) const {
- auto Tokens = Arena.tokenBuffer().expandedTokens();
- auto &SM = Arena.sourceManager();
- auto It = llvm::partition_point(Tokens, [&](const syntax::Token &T) {
- return SM.isBeforeInTranslationUnit(T.location(), L);
- });
- assert(It != Tokens.end());
- assert(It->location() == L);
- return &*It;
+ auto It = LocationToToken.find(L.getRawEncoding());
+ assert(It != LocationToToken.end());
+ return It->second;
}
syntax::TranslationUnit *
diff --git a/clang/lib/Tooling/Syntax/ComputeReplacements.cpp b/clang/lib/Tooling/Syntax/ComputeReplacements.cpp
new file mode 100644
index 000000000000..30b3ee17d092
--- /dev/null
+++ b/clang/lib/Tooling/Syntax/ComputeReplacements.cpp
@@ -0,0 +1,126 @@
+//===- ComputeReplacements.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/Core/Replacement.h"
+#include "clang/Tooling/Syntax/Mutations.h"
+#include "clang/Tooling/Syntax/Tokens.h"
+#include "llvm/Support/Error.h"
+
+using namespace clang;
+
+namespace {
+using ProcessTokensFn = llvm::function_ref<void(llvm::ArrayRef<syntax::Token>,
+ bool /*IsOriginal*/)>;
+/// Enumerates spans of tokens from the tree consecutively laid out in memory.
+void enumerateTokenSpans(const syntax::Tree *Root, ProcessTokensFn Callback) {
+ struct Enumerator {
+ Enumerator(ProcessTokensFn Callback)
+ : SpanBegin(nullptr), SpanEnd(nullptr), SpanIsOriginal(false),
+ Callback(Callback) {}
+
+ void run(const syntax::Tree *Root) {
+ process(Root);
+ // Report the last span to the user.
+ if (SpanBegin)
+ Callback(llvm::makeArrayRef(SpanBegin, SpanEnd), SpanIsOriginal);
+ }
+
+ private:
+ void process(const syntax::Node *N) {
+ if (auto *T = dyn_cast<syntax::Tree>(N)) {
+ for (auto *C = T->firstChild(); C != nullptr; C = C->nextSibling())
+ process(C);
+ return;
+ }
+
+ auto *L = cast<syntax::Leaf>(N);
+ if (SpanEnd == L->token() && SpanIsOriginal == L->isOriginal()) {
+ // Extend the current span.
+ ++SpanEnd;
+ return;
+ }
+ // Report the current span to the user.
+ if (SpanBegin)
+ Callback(llvm::makeArrayRef(SpanBegin, SpanEnd), SpanIsOriginal);
+ // Start recording a new span.
+ SpanBegin = L->token();
+ SpanEnd = SpanBegin + 1;
+ SpanIsOriginal = L->isOriginal();
+ }
+
+ const syntax::Token *SpanBegin;
+ const syntax::Token *SpanEnd;
+ bool SpanIsOriginal;
+ ProcessTokensFn Callback;
+ };
+
+ return Enumerator(Callback).run(Root);
+}
+
+syntax::FileRange rangeOfExpanded(const syntax::Arena &A,
+ llvm::ArrayRef<syntax::Token> Expanded) {
+ auto &Buffer = A.tokenBuffer();
+ auto &SM = A.sourceManager();
+
+ // Check that \p Expanded actually points into expanded tokens.
+ assert(Buffer.expandedTokens().begin() <= Expanded.begin());
+ assert(Expanded.end() < Buffer.expandedTokens().end());
+
+ if (Expanded.empty())
+ // (!) empty tokens must always point before end().
+ return syntax::FileRange(
+ SM, SM.getExpansionLoc(Expanded.begin()->location()), /*Length=*/0);
+
+ auto Spelled = Buffer.spelledForExpanded(Expanded);
+ assert(Spelled && "could not find spelled tokens for expanded");
+ return syntax::Token::range(SM, Spelled->front(), Spelled->back());
+}
+} // namespace
+
+tooling::Replacements
+syntax::computeReplacements(const syntax::Arena &A,
+ const syntax::TranslationUnit &TU) {
+ auto &Buffer = A.tokenBuffer();
+ auto &SM = A.sourceManager();
+
+ tooling::Replacements Replacements;
+ // Text inserted by the replacement we are building now.
+ std::string Replacement;
+ auto emitReplacement = [&](llvm::ArrayRef<syntax::Token> ReplacedRange) {
+ if (ReplacedRange.empty() && Replacement.empty())
+ return;
+ llvm::cantFail(Replacements.add(tooling::Replacement(
+ SM, rangeOfExpanded(A, ReplacedRange).toCharRange(SM), Replacement)));
+ Replacement = "";
+ };
+
+ const syntax::Token *NextOriginal = Buffer.expandedTokens().begin();
+ enumerateTokenSpans(
+ &TU, [&](llvm::ArrayRef<syntax::Token> Tokens, bool IsOriginal) {
+ if (!IsOriginal) {
+ Replacement +=
+ syntax::Token::range(SM, Tokens.front(), Tokens.back()).text(SM);
+ return;
+ }
+ assert(NextOriginal <= Tokens.begin());
+ // 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()));
+ } else {
+ // No gap, but we may have pending insertions. Emit them now.
+ emitReplacement(llvm::makeArrayRef(NextOriginal, /*Length=*/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()));
+
+ return Replacements;
+}
diff --git a/clang/lib/Tooling/Syntax/Mutations.cpp b/clang/lib/Tooling/Syntax/Mutations.cpp
new file mode 100644
index 000000000000..72458528202e
--- /dev/null
+++ b/clang/lib/Tooling/Syntax/Mutations.cpp
@@ -0,0 +1,98 @@
+//===- Mutations.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/Syntax/Mutations.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Token.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "clang/Tooling/Syntax/BuildTree.h"
+#include "clang/Tooling/Syntax/Nodes.h"
+#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>
+#include <string>
+
+using namespace clang;
+
+// This class has access to the internals of tree nodes. Its sole purpose is to
+// define helpers that allow implementing the high-level mutation operations.
+class syntax::MutationsImpl {
+public:
+ /// Add a new node with a specified role.
+ static void addAfter(syntax::Node *Anchor, syntax::Node *New, NodeRole Role) {
+ assert(Anchor != nullptr);
+ assert(New->Parent == nullptr);
+ assert(New->NextSibling == nullptr);
+ assert(!New->isDetached());
+ assert(Role != NodeRole::Detached);
+
+ New->Role = static_cast<unsigned>(Role);
+ auto *P = Anchor->parent();
+ P->replaceChildRangeLowLevel(Anchor, Anchor, New);
+
+ P->assertInvariants();
+ }
+
+ /// Replace the node, keeping the role.
+ static void replace(syntax::Node *Old, syntax::Node *New) {
+ assert(Old != nullptr);
+ assert(Old->Parent != nullptr);
+ assert(Old->canModify());
+ assert(New->Parent == nullptr);
+ assert(New->NextSibling == nullptr);
+ assert(New->isDetached());
+
+ New->Role = Old->Role;
+ auto *P = Old->parent();
+ P->replaceChildRangeLowLevel(findPrevious(Old), Old->nextSibling(), New);
+
+ P->assertInvariants();
+ }
+
+ /// Completely remove the node from its parent.
+ static void remove(syntax::Node *N) {
+ auto *P = N->parent();
+ P->replaceChildRangeLowLevel(findPrevious(N), N->nextSibling(),
+ /*New=*/nullptr);
+
+ P->assertInvariants();
+ N->assertInvariants();
+ }
+
+private:
+ static syntax::Node *findPrevious(syntax::Node *N) {
+ if (N->parent()->firstChild() == N)
+ return nullptr;
+ for (syntax::Node *C = N->parent()->firstChild(); C != nullptr;
+ C = C->nextSibling()) {
+ if (C->nextSibling() == N)
+ return C;
+ }
+ llvm_unreachable("could not find a child node");
+ }
+};
+
+void syntax::removeStatement(syntax::Arena &A, syntax::Statement *S) {
+ assert(S);
+ assert(S->canModify());
+
+ if (isa<CompoundStatement>(S->parent())) {
+ // A child of CompoundStatement can just be safely removed.
+ MutationsImpl::remove(S);
+ return;
+ }
+ // For the rest, we have to replace with an empty statement.
+ if (isa<EmptyStatement>(S))
+ return; // already an empty statement, nothing to do.
+
+ MutationsImpl::replace(S, createEmptyStatement(A));
+}
diff --git a/clang/lib/Tooling/Syntax/Nodes.cpp b/clang/lib/Tooling/Syntax/Nodes.cpp
index 061ed73bbebd..5b0c5107c134 100644
--- a/clang/lib/Tooling/Syntax/Nodes.cpp
+++ b/clang/lib/Tooling/Syntax/Nodes.cpp
@@ -16,20 +16,233 @@ llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeKind K) {
return OS << "Leaf";
case NodeKind::TranslationUnit:
return OS << "TranslationUnit";
- case NodeKind::TopLevelDeclaration:
- return OS << "TopLevelDeclaration";
+ case NodeKind::UnknownExpression:
+ return OS << "UnknownExpression";
+ case NodeKind::UnknownStatement:
+ return OS << "UnknownStatement";
+ case NodeKind::DeclarationStatement:
+ return OS << "DeclarationStatement";
+ case NodeKind::EmptyStatement:
+ return OS << "EmptyStatement";
+ case NodeKind::SwitchStatement:
+ return OS << "SwitchStatement";
+ case NodeKind::CaseStatement:
+ return OS << "CaseStatement";
+ case NodeKind::DefaultStatement:
+ return OS << "DefaultStatement";
+ case NodeKind::IfStatement:
+ return OS << "IfStatement";
+ case NodeKind::ForStatement:
+ return OS << "ForStatement";
+ case NodeKind::WhileStatement:
+ return OS << "WhileStatement";
+ case NodeKind::ContinueStatement:
+ return OS << "ContinueStatement";
+ case NodeKind::BreakStatement:
+ return OS << "BreakStatement";
+ case NodeKind::ReturnStatement:
+ return OS << "ReturnStatement";
+ case NodeKind::RangeBasedForStatement:
+ return OS << "RangeBasedForStatement";
+ case NodeKind::ExpressionStatement:
+ return OS << "ExpressionStatement";
case NodeKind::CompoundStatement:
return OS << "CompoundStatement";
+ case NodeKind::UnknownDeclaration:
+ return OS << "UnknownDeclaration";
+ case NodeKind::EmptyDeclaration:
+ return OS << "EmptyDeclaration";
+ case NodeKind::StaticAssertDeclaration:
+ return OS << "StaticAssertDeclaration";
+ case NodeKind::LinkageSpecificationDeclaration:
+ return OS << "LinkageSpecificationDeclaration";
+ case NodeKind::SimpleDeclaration:
+ return OS << "SimpleDeclaration";
+ case NodeKind::NamespaceDefinition:
+ return OS << "NamespaceDefinition";
+ case NodeKind::NamespaceAliasDefinition:
+ return OS << "NamespaceAliasDefinition";
+ case NodeKind::UsingNamespaceDirective:
+ return OS << "UsingNamespaceDirective";
+ case NodeKind::UsingDeclaration:
+ return OS << "UsingDeclaration";
+ case NodeKind::TypeAliasDeclaration:
+ return OS << "TypeAliasDeclaration";
}
llvm_unreachable("unknown node kind");
}
+llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeRole R) {
+ switch (R) {
+ case syntax::NodeRole::Detached:
+ return OS << "Detached";
+ case syntax::NodeRole::Unknown:
+ return OS << "Unknown";
+ case syntax::NodeRole::OpenParen:
+ return OS << "OpenParen";
+ case syntax::NodeRole::CloseParen:
+ return OS << "CloseParen";
+ case syntax::NodeRole::IntroducerKeyword:
+ return OS << "IntroducerKeyword";
+ case syntax::NodeRole::BodyStatement:
+ return OS << "BodyStatement";
+ case syntax::NodeRole::CaseStatement_value:
+ return OS << "CaseStatement_value";
+ case syntax::NodeRole::IfStatement_thenStatement:
+ return OS << "IfStatement_thenStatement";
+ case syntax::NodeRole::IfStatement_elseKeyword:
+ return OS << "IfStatement_elseKeyword";
+ case syntax::NodeRole::IfStatement_elseStatement:
+ return OS << "IfStatement_elseStatement";
+ case syntax::NodeRole::ReturnStatement_value:
+ return OS << "ReturnStatement_value";
+ case syntax::NodeRole::ExpressionStatement_expression:
+ return OS << "ExpressionStatement_expression";
+ case syntax::NodeRole::CompoundStatement_statement:
+ return OS << "CompoundStatement_statement";
+ case syntax::NodeRole::StaticAssertDeclaration_condition:
+ return OS << "StaticAssertDeclaration_condition";
+ case syntax::NodeRole::StaticAssertDeclaration_message:
+ return OS << "StaticAssertDeclaration_message";
+ }
+ llvm_unreachable("invalid role");
+}
+
+syntax::Leaf *syntax::SwitchStatement::switchKeyword() {
+ return llvm::cast_or_null<syntax::Leaf>(
+ findChild(syntax::NodeRole::IntroducerKeyword));
+}
+
+syntax::Statement *syntax::SwitchStatement::body() {
+ return llvm::cast_or_null<syntax::Statement>(
+ findChild(syntax::NodeRole::BodyStatement));
+}
+
+syntax::Leaf *syntax::CaseStatement::caseKeyword() {
+ return llvm::cast_or_null<syntax::Leaf>(
+ findChild(syntax::NodeRole::IntroducerKeyword));
+}
+
+syntax::Expression *syntax::CaseStatement::value() {
+ return llvm::cast_or_null<syntax::Expression>(
+ findChild(syntax::NodeRole::CaseStatement_value));
+}
+
+syntax::Statement *syntax::CaseStatement::body() {
+ return llvm::cast_or_null<syntax::Statement>(
+ findChild(syntax::NodeRole::BodyStatement));
+}
+
+syntax::Leaf *syntax::DefaultStatement::defaultKeyword() {
+ return llvm::cast_or_null<syntax::Leaf>(
+ findChild(syntax::NodeRole::IntroducerKeyword));
+}
+
+syntax::Statement *syntax::DefaultStatement::body() {
+ return llvm::cast_or_null<syntax::Statement>(
+ findChild(syntax::NodeRole::BodyStatement));
+}
+
+syntax::Leaf *syntax::IfStatement::ifKeyword() {
+ return llvm::cast_or_null<syntax::Leaf>(
+ findChild(syntax::NodeRole::IntroducerKeyword));
+}
+
+syntax::Statement *syntax::IfStatement::thenStatement() {
+ return llvm::cast_or_null<syntax::Statement>(
+ findChild(syntax::NodeRole::IfStatement_thenStatement));
+}
+
+syntax::Leaf *syntax::IfStatement::elseKeyword() {
+ return llvm::cast_or_null<syntax::Leaf>(
+ findChild(syntax::NodeRole::IfStatement_elseKeyword));
+}
+
+syntax::Statement *syntax::IfStatement::elseStatement() {
+ return llvm::cast_or_null<syntax::Statement>(
+ findChild(syntax::NodeRole::IfStatement_elseStatement));
+}
+
+syntax::Leaf *syntax::ForStatement::forKeyword() {
+ return llvm::cast_or_null<syntax::Leaf>(
+ findChild(syntax::NodeRole::IntroducerKeyword));
+}
+
+syntax::Statement *syntax::ForStatement::body() {
+ return llvm::cast_or_null<syntax::Statement>(
+ findChild(syntax::NodeRole::BodyStatement));
+}
+
+syntax::Leaf *syntax::WhileStatement::whileKeyword() {
+ return llvm::cast_or_null<syntax::Leaf>(
+ findChild(syntax::NodeRole::IntroducerKeyword));
+}
+
+syntax::Statement *syntax::WhileStatement::body() {
+ return llvm::cast_or_null<syntax::Statement>(
+ findChild(syntax::NodeRole::BodyStatement));
+}
+
+syntax::Leaf *syntax::ContinueStatement::continueKeyword() {
+ return llvm::cast_or_null<syntax::Leaf>(
+ findChild(syntax::NodeRole::IntroducerKeyword));
+}
+
+syntax::Leaf *syntax::BreakStatement::breakKeyword() {
+ return llvm::cast_or_null<syntax::Leaf>(
+ findChild(syntax::NodeRole::IntroducerKeyword));
+}
+
+syntax::Leaf *syntax::ReturnStatement::returnKeyword() {
+ return llvm::cast_or_null<syntax::Leaf>(
+ findChild(syntax::NodeRole::IntroducerKeyword));
+}
+
+syntax::Expression *syntax::ReturnStatement::value() {
+ return llvm::cast_or_null<syntax::Expression>(
+ findChild(syntax::NodeRole::ReturnStatement_value));
+}
+
+syntax::Leaf *syntax::RangeBasedForStatement::forKeyword() {
+ return llvm::cast_or_null<syntax::Leaf>(
+ findChild(syntax::NodeRole::IntroducerKeyword));
+}
+
+syntax::Statement *syntax::RangeBasedForStatement::body() {
+ return llvm::cast_or_null<syntax::Statement>(
+ findChild(syntax::NodeRole::BodyStatement));
+}
+
+syntax::Expression *syntax::ExpressionStatement::expression() {
+ return llvm::cast_or_null<syntax::Expression>(
+ findChild(syntax::NodeRole::ExpressionStatement_expression));
+}
+
syntax::Leaf *syntax::CompoundStatement::lbrace() {
return llvm::cast_or_null<syntax::Leaf>(
- findChild(NodeRole::CompoundStatement_lbrace));
+ findChild(syntax::NodeRole::OpenParen));
+}
+
+std::vector<syntax::Statement *> syntax::CompoundStatement::statements() {
+ std::vector<syntax::Statement *> Children;
+ for (auto *C = firstChild(); C; C = C->nextSibling()) {
+ if (C->role() == syntax::NodeRole::CompoundStatement_statement)
+ Children.push_back(llvm::cast<syntax::Statement>(C));
+ }
+ return Children;
}
syntax::Leaf *syntax::CompoundStatement::rbrace() {
return llvm::cast_or_null<syntax::Leaf>(
- findChild(NodeRole::CompoundStatement_rbrace));
+ findChild(syntax::NodeRole::CloseParen));
+}
+
+syntax::Expression *syntax::StaticAssertDeclaration::condition() {
+ return llvm::cast_or_null<syntax::Expression>(
+ findChild(syntax::NodeRole::StaticAssertDeclaration_condition));
+}
+
+syntax::Expression *syntax::StaticAssertDeclaration::message() {
+ return llvm::cast_or_null<syntax::Expression>(
+ findChild(syntax::NodeRole::StaticAssertDeclaration_message));
}
diff --git a/clang/lib/Tooling/Syntax/Synthesis.cpp b/clang/lib/Tooling/Syntax/Synthesis.cpp
new file mode 100644
index 000000000000..aa01a34c761f
--- /dev/null
+++ b/clang/lib/Tooling/Syntax/Synthesis.cpp
@@ -0,0 +1,45 @@
+//===- Synthesis.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/Syntax/BuildTree.h"
+
+using namespace clang;
+
+/// Exposes private syntax tree APIs required to implement node synthesis.
+/// Should not be used for anything else.
+class syntax::FactoryImpl {
+public:
+ static void setCanModify(syntax::Node *N) { N->CanModify = true; }
+
+ static void prependChildLowLevel(syntax::Tree *T, syntax::Node *Child,
+ syntax::NodeRole R) {
+ T->prependChildLowLevel(Child, R);
+ }
+};
+
+clang::syntax::Leaf *syntax::createPunctuation(clang::syntax::Arena &A,
+ clang::tok::TokenKind K) {
+ auto Tokens = A.lexBuffer(llvm::MemoryBuffer::getMemBuffer(
+ clang::tok::getPunctuatorSpelling(K)))
+ .second;
+ assert(Tokens.size() == 1);
+ assert(Tokens.front().kind() == K);
+ auto *L = new (A.allocator()) clang::syntax::Leaf(Tokens.begin());
+ FactoryImpl::setCanModify(L);
+ L->assertInvariants();
+ return L;
+}
+
+clang::syntax::EmptyStatement *
+syntax::createEmptyStatement(clang::syntax::Arena &A) {
+ auto *S = new (A.allocator()) clang::syntax::EmptyStatement;
+ FactoryImpl::setCanModify(S);
+ FactoryImpl::prependChildLowLevel(S, createPunctuation(A, clang::tok::semi),
+ NodeRole::Unknown);
+ S->assertInvariants();
+ return S;
+}
diff --git a/clang/lib/Tooling/Syntax/Tokens.cpp b/clang/lib/Tooling/Syntax/Tokens.cpp
index a2c3bc137d6b..3df1c064923a 100644
--- a/clang/lib/Tooling/Syntax/Tokens.cpp
+++ b/clang/lib/Tooling/Syntax/Tokens.cpp
@@ -67,7 +67,7 @@ FileRange syntax::Token::range(const SourceManager &SM,
auto F = First.range(SM);
auto L = Last.range(SM);
assert(F.file() == L.file() && "tokens from different files");
- assert(F.endOffset() <= L.beginOffset() && "wrong order of tokens");
+ assert((F == L || F.endOffset() <= L.beginOffset()) && "wrong order of tokens");
return FileRange(F.file(), F.beginOffset(), L.endOffset());
}
@@ -119,6 +119,28 @@ llvm::StringRef FileRange::text(const SourceManager &SM) const {
return Text.substr(Begin, length());
}
+llvm::ArrayRef<syntax::Token> TokenBuffer::expandedTokens(SourceRange R) const {
+ if (R.isInvalid())
+ return {};
+ const Token *Begin =
+ llvm::partition_point(expandedTokens(), [&](const syntax::Token &T) {
+ return SourceMgr->isBeforeInTranslationUnit(T.location(), R.getBegin());
+ });
+ const Token *End =
+ llvm::partition_point(expandedTokens(), [&](const syntax::Token &T) {
+ return !SourceMgr->isBeforeInTranslationUnit(R.getEnd(), T.location());
+ });
+ if (Begin > End)
+ return {};
+ return {Begin, End};
+}
+
+CharSourceRange FileRange::toCharRange(const SourceManager &SM) const {
+ return CharSourceRange(
+ SourceRange(SM.getComposedLoc(File, Begin), SM.getComposedLoc(File, End)),
+ /*IsTokenRange=*/false);
+}
+
std::pair<const syntax::Token *, const TokenBuffer::Mapping *>
TokenBuffer::spelledForExpandedToken(const syntax::Token *Expanded) const {
assert(Expanded);
@@ -232,6 +254,30 @@ TokenBuffer::expansionStartingAt(const syntax::Token *Spelled) const {
return E;
}
+llvm::ArrayRef<syntax::Token>
+syntax::spelledTokensTouching(SourceLocation Loc,
+ const syntax::TokenBuffer &Tokens) {
+ assert(Loc.isFileID());
+ llvm::ArrayRef<syntax::Token> All =
+ Tokens.spelledTokens(Tokens.sourceManager().getFileID(Loc));
+ auto *Right = llvm::partition_point(
+ All, [&](const syntax::Token &Tok) { return Tok.location() < Loc; });
+ bool AcceptRight = Right != All.end() && Right->location() <= Loc;
+ bool AcceptLeft = Right != All.begin() && (Right - 1)->endLocation() >= Loc;
+ return llvm::makeArrayRef(Right - (AcceptLeft ? 1 : 0),
+ Right + (AcceptRight ? 1 : 0));
+}
+
+const syntax::Token *
+syntax::spelledIdentifierTouching(SourceLocation Loc,
+ const syntax::TokenBuffer &Tokens) {
+ for (const syntax::Token &Tok : spelledTokensTouching(Loc, Tokens)) {
+ if (Tok.kind() == tok::identifier)
+ return &Tok;
+ }
+ return nullptr;
+}
+
std::vector<const syntax::Token *>
TokenBuffer::macroExpansions(FileID FID) const {
auto FileIt = Files.find(FID);
diff --git a/clang/lib/Tooling/Syntax/Tree.cpp b/clang/lib/Tooling/Syntax/Tree.cpp
index 1549b6724fa4..9a6270ec4cce 100644
--- a/clang/lib/Tooling/Syntax/Tree.cpp
+++ b/clang/lib/Tooling/Syntax/Tree.cpp
@@ -11,9 +11,27 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Casting.h"
+#include <cassert>
using namespace clang;
+namespace {
+static void traverse(const syntax::Node *N,
+ llvm::function_ref<void(const syntax::Node *)> Visit) {
+ if (auto *T = dyn_cast<syntax::Tree>(N)) {
+ for (auto *C = T->firstChild(); C; C = C->nextSibling())
+ traverse(C, Visit);
+ }
+ Visit(N);
+}
+static void traverse(syntax::Node *N,
+ llvm::function_ref<void(syntax::Node *)> Visit) {
+ traverse(static_cast<const syntax::Node *>(N), [&](const syntax::Node *N) {
+ Visit(const_cast<syntax::Node *>(N));
+ });
+}
+} // namespace
+
syntax::Arena::Arena(SourceManager &SourceMgr, const LangOptions &LangOpts,
TokenBuffer Tokens)
: SourceMgr(SourceMgr), LangOpts(LangOpts), Tokens(std::move(Tokens)) {}
@@ -40,7 +58,10 @@ bool syntax::Leaf::classof(const Node *N) {
syntax::Node::Node(NodeKind Kind)
: Parent(nullptr), NextSibling(nullptr), Kind(static_cast<unsigned>(Kind)),
- Role(static_cast<unsigned>(NodeRole::Detached)) {}
+ Role(static_cast<unsigned>(NodeRole::Detached)), Original(false),
+ CanModify(false) {}
+
+bool syntax::Node::isDetached() const { return role() == NodeRole::Detached; }
bool syntax::Tree::classof(const Node *N) { return N->kind() > NodeKind::Leaf; }
@@ -56,15 +77,53 @@ void syntax::Tree::prependChildLowLevel(Node *Child, NodeRole Role) {
this->FirstChild = Child;
}
-namespace {
-static void traverse(const syntax::Node *N,
- llvm::function_ref<void(const syntax::Node *)> Visit) {
- if (auto *T = dyn_cast<syntax::Tree>(N)) {
- for (auto *C = T->firstChild(); C; C = C->nextSibling())
- traverse(C, Visit);
+void syntax::Tree::replaceChildRangeLowLevel(Node *BeforeBegin, Node *End,
+ Node *New) {
+ assert(!BeforeBegin || BeforeBegin->Parent == this);
+
+#ifndef NDEBUG
+ for (auto *N = New; N; N = N->nextSibling()) {
+ assert(N->Parent == nullptr);
+ assert(N->role() != NodeRole::Detached && "Roles must be set");
+ // FIXME: sanity-check the role.
}
- Visit(N);
+#endif
+
+ // Detach old nodes.
+ for (auto *N = !BeforeBegin ? FirstChild : BeforeBegin->nextSibling();
+ N != End;) {
+ auto *Next = N->NextSibling;
+
+ N->Role = static_cast<unsigned>(NodeRole::Detached);
+ N->Parent = nullptr;
+ N->NextSibling = nullptr;
+ if (N->Original)
+ traverse(N, [&](Node *C) { C->Original = false; });
+
+ N = Next;
+ }
+
+ // Attach new nodes.
+ if (BeforeBegin)
+ BeforeBegin->NextSibling = New ? New : End;
+ else
+ FirstChild = New ? New : End;
+
+ if (New) {
+ auto *Last = New;
+ for (auto *N = New; N != nullptr; N = N->nextSibling()) {
+ Last = N;
+ N->Parent = this;
+ }
+ Last->NextSibling = End;
+ }
+
+ // Mark the node as modified.
+ for (auto *T = this; T && T->Original; T = T->Parent)
+ T->Original = false;
}
+
+namespace {
static void dumpTokens(llvm::raw_ostream &OS, ArrayRef<syntax::Token> Tokens,
const SourceManager &SM) {
assert(!Tokens.empty());
@@ -85,13 +144,16 @@ static void dumpTokens(llvm::raw_ostream &OS, ArrayRef<syntax::Token> Tokens,
static void dumpTree(llvm::raw_ostream &OS, const syntax::Node *N,
const syntax::Arena &A, std::vector<bool> IndentMask) {
- if (N->role() != syntax::NodeRole::Unknown) {
- // FIXME: print the symbolic name of a role.
- if (N->role() == syntax::NodeRole::Detached)
- OS << "*: ";
- else
- OS << static_cast<int>(N->role()) << ": ";
- }
+ std::string Marks;
+ if (!N->isOriginal())
+ Marks += "M";
+ if (N->role() == syntax::NodeRole::Detached)
+ Marks += "*"; // FIXME: find a nice way to print other roles.
+ if (!N->canModify())
+ Marks += "I";
+ if (!Marks.empty())
+ OS << Marks << ": ";
+
if (auto *L = llvm::dyn_cast<syntax::Leaf>(N)) {
dumpTokens(OS, *L->token(), A.sourceManager());
OS << "\n";
@@ -136,10 +198,60 @@ std::string syntax::Node::dumpTokens(const Arena &A) const {
if (!L)
return;
::dumpTokens(OS, *L->token(), A.sourceManager());
+ OS << " ";
});
return OS.str();
}
+void syntax::Node::assertInvariants() const {
+#ifndef NDEBUG
+ if (isDetached())
+ assert(parent() == nullptr);
+ else
+ assert(parent() != nullptr);
+
+ auto *T = dyn_cast<Tree>(this);
+ if (!T)
+ return;
+ for (auto *C = T->firstChild(); C; C = C->nextSibling()) {
+ if (T->isOriginal())
+ assert(C->isOriginal());
+ assert(!C->isDetached());
+ assert(C->parent() == T);
+ }
+#endif
+}
+
+void syntax::Node::assertInvariantsRecursive() const {
+#ifndef NDEBUG
+ traverse(this, [&](const syntax::Node *N) { N->assertInvariants(); });
+#endif
+}
+
+syntax::Leaf *syntax::Tree::firstLeaf() {
+ auto *T = this;
+ while (auto *C = T->firstChild()) {
+ if (auto *L = dyn_cast<syntax::Leaf>(C))
+ return L;
+ T = cast<syntax::Tree>(C);
+ }
+ return nullptr;
+}
+
+syntax::Leaf *syntax::Tree::lastLeaf() {
+ auto *T = this;
+ while (auto *C = T->firstChild()) {
+ // Find the last child.
+ while (auto *Next = C->nextSibling())
+ C = Next;
+
+ if (auto *L = dyn_cast<syntax::Leaf>(C))
+ return L;
+ T = cast<syntax::Tree>(C);
+ }
+ return nullptr;
+}
+
syntax::Node *syntax::Tree::findChild(NodeRole R) {
for (auto *C = FirstChild; C; C = C->nextSibling()) {
if (C->role() == R)
diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp
index 1d6a968331b5..4a0618c50e42 100644
--- a/clang/lib/Tooling/Tooling.cpp
+++ b/clang/lib/Tooling/Tooling.cpp
@@ -619,7 +619,7 @@ buildASTFromCode(StringRef Code, StringRef FileName,
std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs(
StringRef Code, const std::vector<std::string> &Args, StringRef FileName,
StringRef ToolName, std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- ArgumentsAdjuster Adjuster) {
+ ArgumentsAdjuster Adjuster, const FileContentMappings &VirtualMappedFiles) {
std::vector<std::unique_ptr<ASTUnit>> ASTs;
ASTBuilderAction Action(ASTs);
llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem(
@@ -636,6 +636,12 @@ std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs(
InMemoryFileSystem->addFile(FileName, 0,
llvm::MemoryBuffer::getMemBufferCopy(Code));
+ for (auto &FilenameWithContent : VirtualMappedFiles) {
+ InMemoryFileSystem->addFile(
+ FilenameWithContent.first, 0,
+ llvm::MemoryBuffer::getMemBuffer(FilenameWithContent.second));
+ }
+
if (!Invocation.run())
return nullptr;
diff --git a/clang/lib/Tooling/Transformer/RewriteRule.cpp b/clang/lib/Tooling/Transformer/RewriteRule.cpp
index 6fa558f7b2ee..20d3a371950a 100644
--- a/clang/lib/Tooling/Transformer/RewriteRule.cpp
+++ b/clang/lib/Tooling/Transformer/RewriteRule.cpp
@@ -43,7 +43,7 @@ transformer::detail::translateEdits(const MatchResult &Result,
// it as is currently done.
if (!EditRange)
return SmallVector<Transformation, 0>();
- auto Replacement = Edit.Replacement(Result);
+ auto Replacement = Edit.Replacement->eval(Result);
if (!Replacement)
return Replacement.takeError();
transformer::detail::Transformation T;
@@ -54,13 +54,35 @@ transformer::detail::translateEdits(const MatchResult &Result,
return Transformations;
}
-ASTEdit transformer::change(RangeSelector S, TextGenerator Replacement) {
+ASTEdit transformer::changeTo(RangeSelector S, TextGenerator Replacement) {
ASTEdit E;
E.TargetRange = std::move(S);
E.Replacement = std::move(Replacement);
return E;
}
+namespace {
+/// A \c TextGenerator that always returns a fixed string.
+class SimpleTextGenerator : public MatchComputation<std::string> {
+ std::string S;
+
+public:
+ SimpleTextGenerator(std::string S) : S(std::move(S)) {}
+ llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &,
+ std::string *Result) const override {
+ Result->append(S);
+ return llvm::Error::success();
+ }
+ std::string toString() const override {
+ return (llvm::Twine("text(\"") + S + "\")").str();
+ }
+};
+} // namespace
+
+ASTEdit transformer::remove(RangeSelector S) {
+ return change(std::move(S), std::make_shared<SimpleTextGenerator>(""));
+}
+
RewriteRule transformer::makeRule(DynTypedMatcher M, SmallVector<ASTEdit, 1> Edits,
TextGenerator Explanation) {
return RewriteRule{{RewriteRule::Case{
@@ -176,3 +198,7 @@ transformer::detail::findSelectedCase(const MatchResult &Result,
}
constexpr llvm::StringLiteral RewriteRule::RootID;
+
+TextGenerator tooling::text(std::string M) {
+ return std::make_shared<SimpleTextGenerator>(std::move(M));
+}
diff --git a/clang/lib/Tooling/Transformer/Stencil.cpp b/clang/lib/Tooling/Transformer/Stencil.cpp
index 984950a54e96..8710e3cdf60f 100644
--- a/clang/lib/Tooling/Transformer/Stencil.cpp
+++ b/clang/lib/Tooling/Transformer/Stencil.cpp
@@ -15,6 +15,7 @@
#include "clang/Lex/Lexer.h"
#include "clang/Tooling/Transformer/SourceCode.h"
#include "clang/Tooling/Transformer/SourceCodeBuilders.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Errc.h"
#include <atomic>
@@ -58,7 +59,9 @@ struct DebugPrintNodeData {
enum class UnaryNodeOperator {
Parens,
Deref,
- Address,
+ MaybeDeref,
+ AddressOf,
+ MaybeAddressOf,
};
// Generic container for stencil operations with a (single) node-id argument.
@@ -77,19 +80,24 @@ struct SelectorData {
// A stencil operation to build a member access `e.m` or `e->m`, as appropriate.
struct AccessData {
- AccessData(StringRef BaseId, StencilPart Member)
+ AccessData(StringRef BaseId, Stencil Member)
: BaseId(BaseId), Member(std::move(Member)) {}
std::string BaseId;
- StencilPart Member;
+ Stencil Member;
};
struct IfBoundData {
- IfBoundData(StringRef Id, StencilPart TruePart, StencilPart FalsePart)
- : Id(Id), TruePart(std::move(TruePart)), FalsePart(std::move(FalsePart)) {
- }
+ IfBoundData(StringRef Id, Stencil TrueStencil, Stencil FalseStencil)
+ : Id(Id), TrueStencil(std::move(TrueStencil)),
+ FalseStencil(std::move(FalseStencil)) {}
std::string Id;
- StencilPart TruePart;
- StencilPart FalsePart;
+ Stencil TrueStencil;
+ Stencil FalseStencil;
+};
+
+struct SequenceData {
+ SequenceData(std::vector<Stencil> Stencils) : Stencils(std::move(Stencils)) {}
+ std::vector<Stencil> Stencils;
};
std::string toStringData(const RawTextData &Data) {
@@ -115,9 +123,15 @@ std::string toStringData(const UnaryOperationData &Data) {
case UnaryNodeOperator::Deref:
OpName = "deref";
break;
- case UnaryNodeOperator::Address:
+ case UnaryNodeOperator::MaybeDeref:
+ OpName = "maybeDeref";
+ break;
+ case UnaryNodeOperator::AddressOf:
OpName = "addressOf";
break;
+ case UnaryNodeOperator::MaybeAddressOf:
+ OpName = "maybeAddressOf";
+ break;
}
return (OpName + "(\"" + Data.Id + "\")").str();
}
@@ -126,13 +140,14 @@ std::string toStringData(const SelectorData &) { return "selection(...)"; }
std::string toStringData(const AccessData &Data) {
return (llvm::Twine("access(\"") + Data.BaseId + "\", " +
- Data.Member.toString() + ")")
+ Data.Member->toString() + ")")
.str();
}
std::string toStringData(const IfBoundData &Data) {
return (llvm::Twine("ifBound(\"") + Data.Id + "\", " +
- Data.TruePart.toString() + ", " + Data.FalsePart.toString() + ")")
+ Data.TrueStencil->toString() + ", " + Data.FalseStencil->toString() +
+ ")")
.str();
}
@@ -140,6 +155,14 @@ std::string toStringData(const MatchConsumer<std::string> &) {
return "run(...)";
}
+std::string toStringData(const SequenceData &Data) {
+ llvm::SmallVector<std::string, 2> Parts;
+ Parts.reserve(Data.Stencils.size());
+ for (const auto &S : Data.Stencils)
+ Parts.push_back(S->toString());
+ return (llvm::Twine("seq(") + llvm::join(Parts, ", ") + ")").str();
+}
+
// The `evalData()` overloads evaluate the given stencil data to a string, given
// the match result, and append it to `Result`. We define an overload for each
// type of stencil data.
@@ -176,7 +199,21 @@ Error evalData(const UnaryOperationData &Data,
case UnaryNodeOperator::Deref:
Source = tooling::buildDereference(*E, *Match.Context);
break;
- case UnaryNodeOperator::Address:
+ case UnaryNodeOperator::MaybeDeref:
+ if (!E->getType()->isAnyPointerType()) {
+ *Result += tooling::getText(*E, *Match.Context);
+ return Error::success();
+ }
+ Source = tooling::buildDereference(*E, *Match.Context);
+ break;
+ case UnaryNodeOperator::AddressOf:
+ Source = tooling::buildAddressOf(*E, *Match.Context);
+ break;
+ case UnaryNodeOperator::MaybeAddressOf:
+ if (E->getType()->isAnyPointerType()) {
+ *Result += tooling::getText(*E, *Match.Context);
+ return Error::success();
+ }
Source = tooling::buildAddressOf(*E, *Match.Context);
break;
}
@@ -214,14 +251,14 @@ Error evalData(const AccessData &Data, const MatchFinder::MatchResult &Match,
errc::invalid_argument,
"Could not construct object text from ID: " + Data.BaseId);
}
- return Data.Member.eval(Match, Result);
+ return Data.Member->eval(Match, Result);
}
Error evalData(const IfBoundData &Data, const MatchFinder::MatchResult &Match,
std::string *Result) {
auto &M = Match.Nodes.getMap();
- return (M.find(Data.Id) != M.end() ? Data.TruePart : Data.FalsePart)
- .eval(Match, Result);
+ return (M.find(Data.Id) != M.end() ? Data.TrueStencil : Data.FalseStencil)
+ ->eval(Match, Result);
}
Error evalData(const MatchConsumer<std::string> &Fn,
@@ -233,13 +270,20 @@ Error evalData(const MatchConsumer<std::string> &Fn,
return Error::success();
}
-template <typename T>
-class StencilPartImpl : public StencilPartInterface {
+Error evalData(const SequenceData &Data, const MatchFinder::MatchResult &Match,
+ std::string *Result) {
+ for (const auto &S : Data.Stencils)
+ if (auto Err = S->eval(Match, Result))
+ return Err;
+ return Error::success();
+}
+
+template <typename T> class StencilImpl : public StencilInterface {
T Data;
public:
template <typename... Ps>
- explicit StencilPartImpl(Ps &&... Args) : Data(std::forward<Ps>(Args)...) {}
+ explicit StencilImpl(Ps &&... Args) : Data(std::forward<Ps>(Args)...) {}
Error eval(const MatchFinder::MatchResult &Match,
std::string *Result) const override {
@@ -250,69 +294,67 @@ public:
};
} // namespace
-StencilPart Stencil::wrap(StringRef Text) {
- return transformer::text(Text);
+Stencil transformer::detail::makeStencil(StringRef Text) { return text(Text); }
+
+Stencil transformer::detail::makeStencil(RangeSelector Selector) {
+ return selection(std::move(Selector));
}
-StencilPart Stencil::wrap(RangeSelector Selector) {
- return transformer::selection(std::move(Selector));
+Stencil transformer::text(StringRef Text) {
+ return std::make_shared<StencilImpl<RawTextData>>(Text);
}
-void Stencil::append(Stencil OtherStencil) {
- for (auto &Part : OtherStencil.Parts)
- Parts.push_back(std::move(Part));
+Stencil transformer::selection(RangeSelector Selector) {
+ return std::make_shared<StencilImpl<SelectorData>>(std::move(Selector));
}
-llvm::Expected<std::string>
-Stencil::eval(const MatchFinder::MatchResult &Match) const {
- std::string Result;
- for (const auto &Part : Parts)
- if (auto Err = Part.eval(Match, &Result))
- return std::move(Err);
- return Result;
+Stencil transformer::dPrint(StringRef Id) {
+ return std::make_shared<StencilImpl<DebugPrintNodeData>>(Id);
}
-StencilPart transformer::text(StringRef Text) {
- return StencilPart(std::make_shared<StencilPartImpl<RawTextData>>(Text));
+Stencil transformer::expression(llvm::StringRef Id) {
+ return std::make_shared<StencilImpl<UnaryOperationData>>(
+ UnaryNodeOperator::Parens, Id);
}
-StencilPart transformer::selection(RangeSelector Selector) {
- return StencilPart(
- std::make_shared<StencilPartImpl<SelectorData>>(std::move(Selector)));
+Stencil transformer::deref(llvm::StringRef ExprId) {
+ return std::make_shared<StencilImpl<UnaryOperationData>>(
+ UnaryNodeOperator::Deref, ExprId);
}
-StencilPart transformer::dPrint(StringRef Id) {
- return StencilPart(std::make_shared<StencilPartImpl<DebugPrintNodeData>>(Id));
+Stencil transformer::maybeDeref(llvm::StringRef ExprId) {
+ return std::make_shared<StencilImpl<UnaryOperationData>>(
+ UnaryNodeOperator::MaybeDeref, ExprId);
}
-StencilPart transformer::expression(llvm::StringRef Id) {
- return StencilPart(std::make_shared<StencilPartImpl<UnaryOperationData>>(
- UnaryNodeOperator::Parens, Id));
+Stencil transformer::addressOf(llvm::StringRef ExprId) {
+ return std::make_shared<StencilImpl<UnaryOperationData>>(
+ UnaryNodeOperator::AddressOf, ExprId);
}
-StencilPart transformer::deref(llvm::StringRef ExprId) {
- return StencilPart(std::make_shared<StencilPartImpl<UnaryOperationData>>(
- UnaryNodeOperator::Deref, ExprId));
+Stencil transformer::maybeAddressOf(llvm::StringRef ExprId) {
+ return std::make_shared<StencilImpl<UnaryOperationData>>(
+ UnaryNodeOperator::MaybeAddressOf, ExprId);
}
-StencilPart transformer::addressOf(llvm::StringRef ExprId) {
- return StencilPart(std::make_shared<StencilPartImpl<UnaryOperationData>>(
- UnaryNodeOperator::Address, ExprId));
+Stencil transformer::access(StringRef BaseId, Stencil Member) {
+ return std::make_shared<StencilImpl<AccessData>>(BaseId, std::move(Member));
}
-StencilPart transformer::access(StringRef BaseId, StencilPart Member) {
- return StencilPart(
- std::make_shared<StencilPartImpl<AccessData>>(BaseId, std::move(Member)));
+Stencil transformer::ifBound(StringRef Id, Stencil TrueStencil,
+ Stencil FalseStencil) {
+ return std::make_shared<StencilImpl<IfBoundData>>(Id, std::move(TrueStencil),
+ std::move(FalseStencil));
}
-StencilPart transformer::ifBound(StringRef Id, StencilPart TruePart,
- StencilPart FalsePart) {
- return StencilPart(std::make_shared<StencilPartImpl<IfBoundData>>(
- Id, std::move(TruePart), std::move(FalsePart)));
+Stencil transformer::run(MatchConsumer<std::string> Fn) {
+ return std::make_shared<StencilImpl<MatchConsumer<std::string>>>(
+ std::move(Fn));
}
-StencilPart transformer::run(MatchConsumer<std::string> Fn) {
- return StencilPart(
- std::make_shared<StencilPartImpl<MatchConsumer<std::string>>>(
- std::move(Fn)));
+Stencil transformer::catVector(std::vector<Stencil> Parts) {
+ // Only one argument, so don't wrap in sequence.
+ if (Parts.size() == 1)
+ return std::move(Parts[0]);
+ return std::make_shared<StencilImpl<SequenceData>>(std::move(Parts));
}