aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/ARCMigrate/Internals.h10
-rw-r--r--clang/lib/ARCMigrate/TransAutoreleasePool.cpp5
-rw-r--r--clang/lib/ARCMigrate/Transforms.cpp2
-rw-r--r--clang/lib/AST/ASTContext.cpp398
-rw-r--r--clang/lib/AST/ASTImporter.cpp8
-rw-r--r--clang/lib/AST/AttrImpl.cpp7
-rw-r--r--clang/lib/AST/CXXABI.h1
-rw-r--r--clang/lib/AST/CommentLexer.cpp65
-rw-r--r--clang/lib/AST/Decl.cpp7
-rw-r--r--clang/lib/AST/DeclBase.cpp18
-rw-r--r--clang/lib/AST/DeclCXX.cpp7
-rw-r--r--clang/lib/AST/DeclObjC.cpp12
-rw-r--r--clang/lib/AST/DeclPrinter.cpp27
-rw-r--r--clang/lib/AST/Expr.cpp2
-rw-r--r--clang/lib/AST/ExprConcepts.cpp6
-rw-r--r--clang/lib/AST/ExprConstant.cpp77
-rw-r--r--clang/lib/AST/FormatString.cpp1
-rw-r--r--clang/lib/AST/Interp/ByteCodeExprGen.cpp4
-rw-r--r--clang/lib/AST/Interp/ByteCodeExprGen.h2
-rw-r--r--clang/lib/AST/Interp/ByteCodeStmtGen.h4
-rw-r--r--clang/lib/AST/Interp/Context.h1
-rw-r--r--clang/lib/AST/Interp/InterpBlock.h2
-rw-r--r--clang/lib/AST/Interp/Pointer.h3
-rw-r--r--clang/lib/AST/Interp/PrimType.h50
-rw-r--r--clang/lib/AST/Interp/Program.h3
-rw-r--r--clang/lib/AST/ItaniumMangle.cpp22
-rw-r--r--clang/lib/AST/Mangle.cpp8
-rw-r--r--clang/lib/AST/MicrosoftCXXABI.cpp4
-rw-r--r--clang/lib/AST/OSLog.cpp4
-rw-r--r--clang/lib/AST/PrintfFormatString.cpp18
-rw-r--r--clang/lib/AST/RecordLayoutBuilder.cpp17
-rw-r--r--clang/lib/AST/Stmt.cpp13
-rw-r--r--clang/lib/AST/StmtOpenMP.cpp2
-rw-r--r--clang/lib/AST/StmtPrinter.cpp12
-rw-r--r--clang/lib/AST/TemplateName.cpp8
-rw-r--r--clang/lib/AST/Type.cpp2
-rw-r--r--clang/lib/AST/TypeLoc.cpp1
-rw-r--r--clang/lib/AST/TypePrinter.cpp5
-rw-r--r--clang/lib/AST/VTableBuilder.cpp2
-rw-r--r--clang/lib/ASTMatchers/Dynamic/Marshallers.h7
-rw-r--r--clang/lib/ASTMatchers/Dynamic/Registry.cpp2
-rw-r--r--clang/lib/Analysis/CFG.cpp6
-rw-r--r--clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp69
-rw-r--r--clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp318
-rw-r--r--clang/lib/Analysis/FlowSensitive/Transfer.cpp462
-rw-r--r--clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp164
-rw-r--r--clang/lib/Analysis/UninitializedValues.cpp9
-rw-r--r--clang/lib/Basic/DarwinSDKInfo.cpp19
-rw-r--r--clang/lib/Basic/Diagnostic.cpp6
-rw-r--r--clang/lib/Basic/DiagnosticIDs.cpp17
-rw-r--r--clang/lib/Basic/IdentifierTable.cpp8
-rw-r--r--clang/lib/Basic/OpenCLOptions.cpp35
-rw-r--r--clang/lib/Basic/TargetID.cpp4
-rw-r--r--clang/lib/Basic/TargetInfo.cpp5
-rw-r--r--clang/lib/Basic/Targets/AArch64.cpp57
-rw-r--r--clang/lib/Basic/Targets/AArch64.h7
-rw-r--r--clang/lib/Basic/Targets/ARM.cpp6
-rw-r--r--clang/lib/Basic/Targets/ARM.h1
-rw-r--r--clang/lib/Basic/Targets/AVR.cpp559
-rw-r--r--clang/lib/Basic/Targets/AVR.h1
-rw-r--r--clang/lib/Basic/Targets/M68k.cpp2
-rw-r--r--clang/lib/Basic/Targets/PPC.cpp43
-rw-r--r--clang/lib/Basic/Targets/PPC.h2
-rw-r--r--clang/lib/Basic/Targets/RISCV.cpp31
-rw-r--r--clang/lib/Basic/Targets/Sparc.cpp2
-rw-r--r--clang/lib/Basic/Targets/X86.h11
-rw-r--r--clang/lib/CodeGen/Address.h81
-rw-r--r--clang/lib/CodeGen/BackendUtil.cpp29
-rw-r--r--clang/lib/CodeGen/CGAtomic.cpp10
-rw-r--r--clang/lib/CodeGen/CGBlocks.cpp335
-rw-r--r--clang/lib/CodeGen/CGBlocks.h69
-rw-r--r--clang/lib/CodeGen/CGBuiltin.cpp273
-rw-r--r--clang/lib/CodeGen/CGCXXABI.cpp45
-rw-r--r--clang/lib/CodeGen/CGCXXABI.h13
-rw-r--r--clang/lib/CodeGen/CGCall.cpp51
-rw-r--r--clang/lib/CodeGen/CGCall.h11
-rw-r--r--clang/lib/CodeGen/CGClass.cpp9
-rw-r--r--clang/lib/CodeGen/CGCleanup.h1
-rw-r--r--clang/lib/CodeGen/CGCoroutine.cpp4
-rw-r--r--clang/lib/CodeGen/CGDebugInfo.cpp24
-rw-r--r--clang/lib/CodeGen/CGDebugInfo.h3
-rw-r--r--clang/lib/CodeGen/CGDecl.cpp13
-rw-r--r--clang/lib/CodeGen/CGDeclCXX.cpp1
-rw-r--r--clang/lib/CodeGen/CGExpr.cpp20
-rw-r--r--clang/lib/CodeGen/CGExprAgg.cpp9
-rw-r--r--clang/lib/CodeGen/CGExprScalar.cpp5
-rw-r--r--clang/lib/CodeGen/CGObjC.cpp2
-rw-r--r--clang/lib/CodeGen/CGObjCGNU.cpp15
-rw-r--r--clang/lib/CodeGen/CGObjCMac.cpp37
-rw-r--r--clang/lib/CodeGen/CGOpenMPRuntime.cpp122
-rw-r--r--clang/lib/CodeGen/CGOpenMPRuntime.h2
-rw-r--r--clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp29
-rw-r--r--clang/lib/CodeGen/CGRecordLayout.h4
-rw-r--r--clang/lib/CodeGen/CGRecordLayoutBuilder.cpp2
-rw-r--r--clang/lib/CodeGen/CGStmt.cpp130
-rw-r--r--clang/lib/CodeGen/CGStmtOpenMP.cpp74
-rw-r--r--clang/lib/CodeGen/CGVTables.cpp2
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.cpp46
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h31
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp36
-rw-r--r--clang/lib/CodeGen/CodeGenModule.h17
-rw-r--r--clang/lib/CodeGen/CodeGenPGO.cpp2
-rw-r--r--clang/lib/CodeGen/CodeGenTBAA.h1
-rw-r--r--clang/lib/CodeGen/CodeGenTypes.cpp14
-rw-r--r--clang/lib/CodeGen/CodeGenTypes.h5
-rw-r--r--clang/lib/CodeGen/ItaniumCXXABI.cpp60
-rw-r--r--clang/lib/CodeGen/MacroPPCallbacks.h1
-rw-r--r--clang/lib/CodeGen/MicrosoftCXXABI.cpp94
-rw-r--r--clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp1
-rw-r--r--clang/lib/CodeGen/TargetInfo.cpp46
-rw-r--r--clang/lib/CodeGen/TargetInfo.h1
-rw-r--r--clang/lib/Driver/Driver.cpp128
-rw-r--r--clang/lib/Driver/SanitizerArgs.cpp8
-rw-r--r--clang/lib/Driver/ToolChain.cpp54
-rw-r--r--clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp46
-rw-r--r--clang/lib/Driver/ToolChains/Arch/AArch64.cpp27
-rw-r--r--clang/lib/Driver/ToolChains/Arch/AArch64.h1
-rw-r--r--clang/lib/Driver/ToolChains/Arch/ARM.cpp29
-rw-r--r--clang/lib/Driver/ToolChains/Arch/ARM.h1
-rw-r--r--clang/lib/Driver/ToolChains/Clang.cpp44
-rw-r--r--clang/lib/Driver/ToolChains/Clang.h4
-rw-r--r--clang/lib/Driver/ToolChains/CommonArgs.cpp35
-rw-r--r--clang/lib/Driver/ToolChains/Cuda.cpp10
-rw-r--r--clang/lib/Driver/ToolChains/FreeBSD.cpp9
-rw-r--r--clang/lib/Driver/ToolChains/Fuchsia.cpp14
-rw-r--r--clang/lib/Driver/ToolChains/Gnu.cpp10
-rw-r--r--clang/lib/Driver/ToolChains/Linux.cpp6
-rw-r--r--clang/lib/Driver/ToolChains/Linux.h1
-rw-r--r--clang/lib/Driver/ToolChains/MSVC.cpp21
-rw-r--r--clang/lib/Driver/ToolChains/MSVC.h4
-rw-r--r--clang/lib/Driver/ToolChains/MSVCSetupApi.h9
-rw-r--r--clang/lib/Driver/ToolChains/MinGW.cpp8
-rw-r--r--clang/lib/Driver/ToolChains/PPCLinux.cpp57
-rw-r--r--clang/lib/Driver/ToolChains/PPCLinux.h7
-rw-r--r--clang/lib/Driver/ToolChains/PS4CPU.cpp2
-rw-r--r--clang/lib/Driver/ToolChains/SPIRV.cpp21
-rw-r--r--clang/lib/Driver/ToolChains/SPIRV.h12
-rw-r--r--clang/lib/Driver/ToolChains/VEToolchain.cpp3
-rw-r--r--clang/lib/Driver/ToolChains/WebAssembly.cpp2
-rw-r--r--clang/lib/Driver/ToolChains/WebAssembly.h1
-rw-r--r--clang/lib/Driver/Types.cpp1
-rw-r--r--clang/lib/Edit/RewriteObjCFoundationAPI.cpp2
-rw-r--r--clang/lib/Format/AffectedRangeManager.cpp11
-rw-r--r--clang/lib/Format/ContinuationIndenter.cpp38
-rw-r--r--clang/lib/Format/ContinuationIndenter.h27
-rw-r--r--clang/lib/Format/DefinitionBlockSeparator.cpp236
-rw-r--r--clang/lib/Format/DefinitionBlockSeparator.h41
-rw-r--r--clang/lib/Format/Format.cpp179
-rw-r--r--clang/lib/Format/FormatToken.cpp12
-rw-r--r--clang/lib/Format/FormatToken.h11
-rw-r--r--clang/lib/Format/FormatTokenLexer.cpp22
-rw-r--r--clang/lib/Format/NamespaceEndCommentsFixer.cpp9
-rw-r--r--clang/lib/Format/QualifierAlignmentFixer.cpp37
-rw-r--r--clang/lib/Format/QualifierAlignmentFixer.h22
-rw-r--r--clang/lib/Format/SortJavaScriptImports.cpp49
-rw-r--r--clang/lib/Format/TokenAnalyzer.cpp7
-rw-r--r--clang/lib/Format/TokenAnnotator.cpp158
-rw-r--r--clang/lib/Format/TokenAnnotator.h9
-rw-r--r--clang/lib/Format/UnwrappedLineFormatter.cpp109
-rw-r--r--clang/lib/Format/UnwrappedLineParser.cpp338
-rw-r--r--clang/lib/Format/UnwrappedLineParser.h30
-rw-r--r--clang/lib/Format/WhitespaceManager.cpp22
-rw-r--r--clang/lib/Format/WhitespaceManager.h5
-rw-r--r--clang/lib/Frontend/ASTUnit.cpp7
-rw-r--r--clang/lib/Frontend/CompilerInstance.cpp11
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp9
-rw-r--r--clang/lib/Frontend/ExtractAPIConsumer.cpp32
-rw-r--r--clang/lib/Frontend/FrontendActions.cpp98
-rw-r--r--clang/lib/Frontend/InitPreprocessor.cpp74
-rw-r--r--clang/lib/Frontend/MultiplexConsumer.cpp4
-rw-r--r--clang/lib/Frontend/PrintPreprocessedOutput.cpp2
-rw-r--r--clang/lib/Frontend/Rewrite/InclusionRewriter.cpp42
-rw-r--r--clang/lib/Frontend/SerializedDiagnosticPrinter.cpp3
-rw-r--r--clang/lib/Frontend/TextDiagnostic.cpp2
-rw-r--r--clang/lib/Frontend/VerifyDiagnosticConsumer.cpp3
-rw-r--r--clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp2
-rw-r--r--clang/lib/Headers/__clang_cuda_math.h2
-rw-r--r--clang/lib/Headers/__clang_hip_runtime_wrapper.h21
-rw-r--r--clang/lib/Headers/avx2intrin.h30
-rw-r--r--clang/lib/Headers/avx512bwintrin.h20
-rw-r--r--clang/lib/Headers/avx512fintrin.h72
-rw-r--r--clang/lib/Headers/avx512vlintrin.h20
-rw-r--r--clang/lib/Headers/cetintrin.h10
-rw-r--r--clang/lib/Headers/cpuid.h2
-rw-r--r--clang/lib/Headers/emmintrin.h8
-rw-r--r--clang/lib/Headers/limits.h18
-rw-r--r--clang/lib/Headers/opencl-c-base.h5
-rw-r--r--clang/lib/Headers/opencl-c.h100
-rw-r--r--clang/lib/Headers/smmintrin.h16
-rw-r--r--clang/lib/Headers/stdatomic.h9
-rw-r--r--clang/lib/Headers/stdint.h168
-rw-r--r--clang/lib/Headers/tmmintrin.h6
-rw-r--r--clang/lib/Headers/vaesintrin.h2
-rw-r--r--clang/lib/Interpreter/IncrementalParser.cpp2
-rw-r--r--clang/lib/Interpreter/IncrementalParser.h3
-rw-r--r--clang/lib/Lex/HeaderSearch.cpp156
-rw-r--r--clang/lib/Lex/InitHeaderSearch.cpp (renamed from clang/lib/Frontend/InitHeaderSearch.cpp)5
-rw-r--r--clang/lib/Lex/Lexer.cpp4
-rw-r--r--clang/lib/Lex/PPDirectives.cpp15
-rw-r--r--clang/lib/Lex/PPMacroExpansion.cpp3
-rw-r--r--clang/lib/Lex/Pragma.cpp3
-rw-r--r--clang/lib/Lex/Preprocessor.cpp7
-rw-r--r--clang/lib/Parse/ParseCXXInlineMethods.cpp22
-rw-r--r--clang/lib/Parse/ParseDecl.cpp29
-rw-r--r--clang/lib/Parse/ParseDeclCXX.cpp24
-rw-r--r--clang/lib/Parse/ParseExpr.cpp14
-rw-r--r--clang/lib/Parse/ParseExprCXX.cpp38
-rw-r--r--clang/lib/Parse/ParseInit.cpp18
-rw-r--r--clang/lib/Parse/ParseObjc.cpp18
-rw-r--r--clang/lib/Parse/ParseOpenMP.cpp122
-rw-r--r--clang/lib/Parse/ParseStmt.cpp56
-rw-r--r--clang/lib/Parse/ParseStmtAsm.cpp10
-rw-r--r--clang/lib/Parse/ParseTemplate.cpp50
-rw-r--r--clang/lib/Parse/ParseTentative.cpp6
-rw-r--r--clang/lib/Parse/Parser.cpp14
-rw-r--r--clang/lib/Rewrite/HTMLRewrite.cpp2
-rw-r--r--clang/lib/Rewrite/Rewriter.cpp1
-rw-r--r--clang/lib/Sema/AnalysisBasedWarnings.cpp2
-rw-r--r--clang/lib/Sema/CodeCompleteConsumer.cpp85
-rw-r--r--clang/lib/Sema/OpenCLBuiltins.td160
-rw-r--r--clang/lib/Sema/Scope.cpp2
-rw-r--r--clang/lib/Sema/Sema.cpp41
-rw-r--r--clang/lib/Sema/SemaCXXScopeSpec.cpp3
-rw-r--r--clang/lib/Sema/SemaChecking.cpp123
-rw-r--r--clang/lib/Sema/SemaCodeComplete.cpp453
-rw-r--r--clang/lib/Sema/SemaConcept.cpp5
-rw-r--r--clang/lib/Sema/SemaCoroutine.cpp97
-rw-r--r--clang/lib/Sema/SemaDecl.cpp140
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp105
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp2
-rw-r--r--clang/lib/Sema/SemaDeclObjC.cpp54
-rw-r--r--clang/lib/Sema/SemaExceptionSpec.cpp9
-rw-r--r--clang/lib/Sema/SemaExpr.cpp70
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp15
-rw-r--r--clang/lib/Sema/SemaExprMember.cpp12
-rw-r--r--clang/lib/Sema/SemaExprObjC.cpp4
-rw-r--r--clang/lib/Sema/SemaLookup.cpp43
-rw-r--r--clang/lib/Sema/SemaModule.cpp17
-rw-r--r--clang/lib/Sema/SemaObjCProperty.cpp8
-rw-r--r--clang/lib/Sema/SemaOpenMP.cpp45
-rw-r--r--clang/lib/Sema/SemaOverload.cpp19
-rw-r--r--clang/lib/Sema/SemaSYCL.cpp98
-rw-r--r--clang/lib/Sema/SemaStmt.cpp61
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp14
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp2
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp7
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp4
-rw-r--r--clang/lib/Sema/SemaType.cpp14
-rw-r--r--clang/lib/Sema/TreeTransform.h10
-rw-r--r--clang/lib/Serialization/ASTReader.cpp34
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp400
-rw-r--r--clang/lib/Serialization/ASTReaderInternals.h1
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp47
-rw-r--r--clang/lib/Serialization/ModuleManager.cpp22
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp1366
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp1
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h4
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h1
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/Yaml.h2
-rw-r--r--clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Core/ProgramState.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Core/SValBuilder.cpp94
-rw-r--r--clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Frontend/ModelInjector.h3
-rw-r--r--clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp247
-rw-r--r--clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp2
-rw-r--r--clang/lib/Tooling/InterpolatingCompilationDatabase.cpp3
-rw-r--r--clang/lib/Tooling/Syntax/Tree.cpp7
-rw-r--r--clang/lib/Tooling/Transformer/Parsing.cpp1
-rw-r--r--clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp84
-rw-r--r--clang/lib/Tooling/Transformer/Stencil.cpp72
276 files changed, 7998 insertions, 3983 deletions
diff --git a/clang/lib/ARCMigrate/Internals.h b/clang/lib/ARCMigrate/Internals.h
index ed0136e4867a..8b482738cc89 100644
--- a/clang/lib/ARCMigrate/Internals.h
+++ b/clang/lib/ARCMigrate/Internals.h
@@ -154,13 +154,11 @@ public:
std::vector<SourceLocation> &ARCMTMacroLocs;
Optional<bool> EnableCFBridgeFns;
- MigrationPass(ASTContext &Ctx, LangOptions::GCMode OrigGCMode,
- Sema &sema, TransformActions &TA,
- const CapturedDiagList &capturedDiags,
+ MigrationPass(ASTContext &Ctx, LangOptions::GCMode OrigGCMode, Sema &sema,
+ TransformActions &TA, const CapturedDiagList &capturedDiags,
std::vector<SourceLocation> &ARCMTMacroLocs)
- : Ctx(Ctx), OrigGCMode(OrigGCMode), MigOptions(),
- SemaRef(sema), TA(TA), CapturedDiags(capturedDiags),
- ARCMTMacroLocs(ARCMTMacroLocs) { }
+ : Ctx(Ctx), OrigGCMode(OrigGCMode), SemaRef(sema), TA(TA),
+ CapturedDiags(capturedDiags), ARCMTMacroLocs(ARCMTMacroLocs) {}
const CapturedDiagList &getDiags() const { return CapturedDiags; }
diff --git a/clang/lib/ARCMigrate/TransAutoreleasePool.cpp b/clang/lib/ARCMigrate/TransAutoreleasePool.cpp
index 393adcd85a3f..47587d81850a 100644
--- a/clang/lib/ARCMigrate/TransAutoreleasePool.cpp
+++ b/clang/lib/ARCMigrate/TransAutoreleasePool.cpp
@@ -229,8 +229,9 @@ private:
bool IsFollowedBySimpleReturnStmt;
SmallVector<ObjCMessageExpr *, 4> Releases;
- PoolScope() : PoolVar(nullptr), CompoundParent(nullptr), Begin(), End(),
- IsFollowedBySimpleReturnStmt(false) { }
+ PoolScope()
+ : PoolVar(nullptr), CompoundParent(nullptr),
+ IsFollowedBySimpleReturnStmt(false) {}
SourceRange getIndentedRange() const {
Stmt::child_iterator rangeS = Begin;
diff --git a/clang/lib/ARCMigrate/Transforms.cpp b/clang/lib/ARCMigrate/Transforms.cpp
index ca48160d9c85..a08b0d084bb6 100644
--- a/clang/lib/ARCMigrate/Transforms.cpp
+++ b/clang/lib/ARCMigrate/Transforms.cpp
@@ -417,7 +417,7 @@ bool MigrationContext::rewritePropertyAttribute(StringRef fromAttr,
if (tok.is(tok::r_paren))
return false;
- while (1) {
+ while (true) {
if (tok.isNot(tok::raw_identifier)) return false;
if (tok.getRawIdentifier() == fromAttr) {
if (!toAttr.empty()) {
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 008b703d4c1a..8a780250b6d8 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -6147,6 +6147,376 @@ bool ASTContext::hasSameTemplateName(TemplateName X, TemplateName Y) {
return X.getAsVoidPointer() == Y.getAsVoidPointer();
}
+bool ASTContext::isSameTemplateParameter(NamedDecl *X, NamedDecl *Y) {
+ if (X->getKind() != Y->getKind())
+ return false;
+
+ if (auto *TX = dyn_cast<TemplateTypeParmDecl>(X)) {
+ auto *TY = cast<TemplateTypeParmDecl>(Y);
+ if (TX->isParameterPack() != TY->isParameterPack())
+ return false;
+ if (TX->hasTypeConstraint() != TY->hasTypeConstraint())
+ return false;
+ const TypeConstraint *TXTC = TX->getTypeConstraint();
+ const TypeConstraint *TYTC = TY->getTypeConstraint();
+ if (!TXTC != !TYTC)
+ return false;
+ if (TXTC && TYTC) {
+ auto *NCX = TXTC->getNamedConcept();
+ auto *NCY = TYTC->getNamedConcept();
+ if (!NCX || !NCY || !isSameEntity(NCX, NCY))
+ return false;
+ if (TXTC->hasExplicitTemplateArgs() != TYTC->hasExplicitTemplateArgs())
+ return false;
+ if (TXTC->hasExplicitTemplateArgs()) {
+ auto *TXTCArgs = TXTC->getTemplateArgsAsWritten();
+ auto *TYTCArgs = TYTC->getTemplateArgsAsWritten();
+ if (TXTCArgs->NumTemplateArgs != TYTCArgs->NumTemplateArgs)
+ return false;
+ llvm::FoldingSetNodeID XID, YID;
+ for (auto &ArgLoc : TXTCArgs->arguments())
+ ArgLoc.getArgument().Profile(XID, X->getASTContext());
+ for (auto &ArgLoc : TYTCArgs->arguments())
+ ArgLoc.getArgument().Profile(YID, Y->getASTContext());
+ if (XID != YID)
+ return false;
+ }
+ }
+ return true;
+ }
+
+ if (auto *TX = dyn_cast<NonTypeTemplateParmDecl>(X)) {
+ auto *TY = cast<NonTypeTemplateParmDecl>(Y);
+ return TX->isParameterPack() == TY->isParameterPack() &&
+ TX->getASTContext().hasSameType(TX->getType(), TY->getType());
+ }
+
+ auto *TX = cast<TemplateTemplateParmDecl>(X);
+ auto *TY = cast<TemplateTemplateParmDecl>(Y);
+ return TX->isParameterPack() == TY->isParameterPack() &&
+ isSameTemplateParameterList(TX->getTemplateParameters(),
+ TY->getTemplateParameters());
+}
+
+bool ASTContext::isSameTemplateParameterList(TemplateParameterList *X,
+ TemplateParameterList *Y) {
+ if (X->size() != Y->size())
+ return false;
+
+ for (unsigned I = 0, N = X->size(); I != N; ++I)
+ if (!isSameTemplateParameter(X->getParam(I), Y->getParam(I)))
+ return false;
+
+ const Expr *XRC = X->getRequiresClause();
+ const Expr *YRC = Y->getRequiresClause();
+ if (!XRC != !YRC)
+ return false;
+ if (XRC) {
+ llvm::FoldingSetNodeID XRCID, YRCID;
+ XRC->Profile(XRCID, *this, /*Canonical=*/true);
+ YRC->Profile(YRCID, *this, /*Canonical=*/true);
+ if (XRCID != YRCID)
+ return false;
+ }
+
+ return true;
+}
+
+static NamespaceDecl *getNamespace(const NestedNameSpecifier *X) {
+ if (auto *NS = X->getAsNamespace())
+ return NS;
+ if (auto *NAS = X->getAsNamespaceAlias())
+ return NAS->getNamespace();
+ return nullptr;
+}
+
+static bool isSameQualifier(const NestedNameSpecifier *X,
+ const NestedNameSpecifier *Y) {
+ if (auto *NSX = getNamespace(X)) {
+ auto *NSY = getNamespace(Y);
+ if (!NSY || NSX->getCanonicalDecl() != NSY->getCanonicalDecl())
+ return false;
+ } else if (X->getKind() != Y->getKind())
+ return false;
+
+ // FIXME: For namespaces and types, we're permitted to check that the entity
+ // is named via the same tokens. We should probably do so.
+ switch (X->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ if (X->getAsIdentifier() != Y->getAsIdentifier())
+ return false;
+ break;
+ case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::NamespaceAlias:
+ // We've already checked that we named the same namespace.
+ break;
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ if (X->getAsType()->getCanonicalTypeInternal() !=
+ Y->getAsType()->getCanonicalTypeInternal())
+ return false;
+ break;
+ case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super:
+ return true;
+ }
+
+ // Recurse into earlier portion of NNS, if any.
+ auto *PX = X->getPrefix();
+ auto *PY = Y->getPrefix();
+ if (PX && PY)
+ return isSameQualifier(PX, PY);
+ return !PX && !PY;
+}
+
+/// Determine whether the attributes we can overload on are identical for A and
+/// B. Will ignore any overloadable attrs represented in the type of A and B.
+static bool hasSameOverloadableAttrs(const FunctionDecl *A,
+ const FunctionDecl *B) {
+ // Note that pass_object_size attributes are represented in the function's
+ // ExtParameterInfo, so we don't need to check them here.
+
+ llvm::FoldingSetNodeID Cand1ID, Cand2ID;
+ auto AEnableIfAttrs = A->specific_attrs<EnableIfAttr>();
+ auto BEnableIfAttrs = B->specific_attrs<EnableIfAttr>();
+
+ for (auto Pair : zip_longest(AEnableIfAttrs, BEnableIfAttrs)) {
+ Optional<EnableIfAttr *> Cand1A = std::get<0>(Pair);
+ Optional<EnableIfAttr *> Cand2A = std::get<1>(Pair);
+
+ // Return false if the number of enable_if attributes is different.
+ if (!Cand1A || !Cand2A)
+ return false;
+
+ Cand1ID.clear();
+ Cand2ID.clear();
+
+ (*Cand1A)->getCond()->Profile(Cand1ID, A->getASTContext(), true);
+ (*Cand2A)->getCond()->Profile(Cand2ID, B->getASTContext(), true);
+
+ // Return false if any of the enable_if expressions of A and B are
+ // different.
+ if (Cand1ID != Cand2ID)
+ return false;
+ }
+ return true;
+}
+
+bool ASTContext::isSameEntity(NamedDecl *X, NamedDecl *Y) {
+ if (X == Y)
+ return true;
+
+ if (X->getDeclName() != Y->getDeclName())
+ return false;
+
+ // Must be in the same context.
+ //
+ // Note that we can't use DeclContext::Equals here, because the DeclContexts
+ // could be two different declarations of the same function. (We will fix the
+ // semantic DC to refer to the primary definition after merging.)
+ if (!declaresSameEntity(cast<Decl>(X->getDeclContext()->getRedeclContext()),
+ cast<Decl>(Y->getDeclContext()->getRedeclContext())))
+ return false;
+
+ // Two typedefs refer to the same entity if they have the same underlying
+ // type.
+ if (const auto *TypedefX = dyn_cast<TypedefNameDecl>(X))
+ if (const auto *TypedefY = dyn_cast<TypedefNameDecl>(Y))
+ return hasSameType(TypedefX->getUnderlyingType(),
+ TypedefY->getUnderlyingType());
+
+ // Must have the same kind.
+ if (X->getKind() != Y->getKind())
+ return false;
+
+ // Objective-C classes and protocols with the same name always match.
+ if (isa<ObjCInterfaceDecl>(X) || isa<ObjCProtocolDecl>(X))
+ return true;
+
+ if (isa<ClassTemplateSpecializationDecl>(X)) {
+ // No need to handle these here: we merge them when adding them to the
+ // template.
+ return false;
+ }
+
+ // Compatible tags match.
+ if (const auto *TagX = dyn_cast<TagDecl>(X)) {
+ const auto *TagY = cast<TagDecl>(Y);
+ return (TagX->getTagKind() == TagY->getTagKind()) ||
+ ((TagX->getTagKind() == TTK_Struct ||
+ TagX->getTagKind() == TTK_Class ||
+ TagX->getTagKind() == TTK_Interface) &&
+ (TagY->getTagKind() == TTK_Struct ||
+ TagY->getTagKind() == TTK_Class ||
+ TagY->getTagKind() == TTK_Interface));
+ }
+
+ // Functions with the same type and linkage match.
+ // FIXME: This needs to cope with merging of prototyped/non-prototyped
+ // functions, etc.
+ if (const auto *FuncX = dyn_cast<FunctionDecl>(X)) {
+ const auto *FuncY = cast<FunctionDecl>(Y);
+ if (const auto *CtorX = dyn_cast<CXXConstructorDecl>(X)) {
+ const auto *CtorY = cast<CXXConstructorDecl>(Y);
+ if (CtorX->getInheritedConstructor() &&
+ !isSameEntity(CtorX->getInheritedConstructor().getConstructor(),
+ CtorY->getInheritedConstructor().getConstructor()))
+ return false;
+ }
+
+ if (FuncX->isMultiVersion() != FuncY->isMultiVersion())
+ return false;
+
+ // Multiversioned functions with different feature strings are represented
+ // as separate declarations.
+ if (FuncX->isMultiVersion()) {
+ const auto *TAX = FuncX->getAttr<TargetAttr>();
+ const auto *TAY = FuncY->getAttr<TargetAttr>();
+ assert(TAX && TAY && "Multiversion Function without target attribute");
+
+ if (TAX->getFeaturesStr() != TAY->getFeaturesStr())
+ return false;
+ }
+
+ const Expr *XRC = FuncX->getTrailingRequiresClause();
+ const Expr *YRC = FuncY->getTrailingRequiresClause();
+ if (!XRC != !YRC)
+ return false;
+ if (XRC) {
+ llvm::FoldingSetNodeID XRCID, YRCID;
+ XRC->Profile(XRCID, *this, /*Canonical=*/true);
+ YRC->Profile(YRCID, *this, /*Canonical=*/true);
+ if (XRCID != YRCID)
+ return false;
+ }
+
+ auto GetTypeAsWritten = [](const FunctionDecl *FD) {
+ // Map to the first declaration that we've already merged into this one.
+ // The TSI of redeclarations might not match (due to calling conventions
+ // being inherited onto the type but not the TSI), but the TSI type of
+ // the first declaration of the function should match across modules.
+ FD = FD->getCanonicalDecl();
+ return FD->getTypeSourceInfo() ? FD->getTypeSourceInfo()->getType()
+ : FD->getType();
+ };
+ QualType XT = GetTypeAsWritten(FuncX), YT = GetTypeAsWritten(FuncY);
+ if (!hasSameType(XT, YT)) {
+ // We can get functions with different types on the redecl chain in C++17
+ // if they have differing exception specifications and at least one of
+ // the excpetion specs is unresolved.
+ auto *XFPT = XT->getAs<FunctionProtoType>();
+ auto *YFPT = YT->getAs<FunctionProtoType>();
+ if (getLangOpts().CPlusPlus17 && XFPT && YFPT &&
+ (isUnresolvedExceptionSpec(XFPT->getExceptionSpecType()) ||
+ isUnresolvedExceptionSpec(YFPT->getExceptionSpecType())) &&
+ hasSameFunctionTypeIgnoringExceptionSpec(XT, YT))
+ return true;
+ return false;
+ }
+
+ return FuncX->getLinkageInternal() == FuncY->getLinkageInternal() &&
+ hasSameOverloadableAttrs(FuncX, FuncY);
+ }
+
+ // Variables with the same type and linkage match.
+ if (const auto *VarX = dyn_cast<VarDecl>(X)) {
+ const auto *VarY = cast<VarDecl>(Y);
+ if (VarX->getLinkageInternal() == VarY->getLinkageInternal()) {
+ if (hasSameType(VarX->getType(), VarY->getType()))
+ return true;
+
+ // We can get decls with different types on the redecl chain. Eg.
+ // template <typename T> struct S { static T Var[]; }; // #1
+ // template <typename T> T S<T>::Var[sizeof(T)]; // #2
+ // Only? happens when completing an incomplete array type. In this case
+ // when comparing #1 and #2 we should go through their element type.
+ const ArrayType *VarXTy = getAsArrayType(VarX->getType());
+ const ArrayType *VarYTy = getAsArrayType(VarY->getType());
+ if (!VarXTy || !VarYTy)
+ return false;
+ if (VarXTy->isIncompleteArrayType() || VarYTy->isIncompleteArrayType())
+ return hasSameType(VarXTy->getElementType(), VarYTy->getElementType());
+ }
+ return false;
+ }
+
+ // Namespaces with the same name and inlinedness match.
+ if (const auto *NamespaceX = dyn_cast<NamespaceDecl>(X)) {
+ const auto *NamespaceY = cast<NamespaceDecl>(Y);
+ return NamespaceX->isInline() == NamespaceY->isInline();
+ }
+
+ // Identical template names and kinds match if their template parameter lists
+ // and patterns match.
+ if (const auto *TemplateX = dyn_cast<TemplateDecl>(X)) {
+ const auto *TemplateY = cast<TemplateDecl>(Y);
+ return isSameEntity(TemplateX->getTemplatedDecl(),
+ TemplateY->getTemplatedDecl()) &&
+ isSameTemplateParameterList(TemplateX->getTemplateParameters(),
+ TemplateY->getTemplateParameters());
+ }
+
+ // Fields with the same name and the same type match.
+ if (const auto *FDX = dyn_cast<FieldDecl>(X)) {
+ const auto *FDY = cast<FieldDecl>(Y);
+ // FIXME: Also check the bitwidth is odr-equivalent, if any.
+ return hasSameType(FDX->getType(), FDY->getType());
+ }
+
+ // Indirect fields with the same target field match.
+ if (const auto *IFDX = dyn_cast<IndirectFieldDecl>(X)) {
+ const auto *IFDY = cast<IndirectFieldDecl>(Y);
+ return IFDX->getAnonField()->getCanonicalDecl() ==
+ IFDY->getAnonField()->getCanonicalDecl();
+ }
+
+ // Enumerators with the same name match.
+ if (isa<EnumConstantDecl>(X))
+ // FIXME: Also check the value is odr-equivalent.
+ return true;
+
+ // Using shadow declarations with the same target match.
+ if (const auto *USX = dyn_cast<UsingShadowDecl>(X)) {
+ const auto *USY = cast<UsingShadowDecl>(Y);
+ return USX->getTargetDecl() == USY->getTargetDecl();
+ }
+
+ // Using declarations with the same qualifier match. (We already know that
+ // the name matches.)
+ if (const auto *UX = dyn_cast<UsingDecl>(X)) {
+ const auto *UY = cast<UsingDecl>(Y);
+ return isSameQualifier(UX->getQualifier(), UY->getQualifier()) &&
+ UX->hasTypename() == UY->hasTypename() &&
+ UX->isAccessDeclaration() == UY->isAccessDeclaration();
+ }
+ if (const auto *UX = dyn_cast<UnresolvedUsingValueDecl>(X)) {
+ const auto *UY = cast<UnresolvedUsingValueDecl>(Y);
+ return isSameQualifier(UX->getQualifier(), UY->getQualifier()) &&
+ UX->isAccessDeclaration() == UY->isAccessDeclaration();
+ }
+ if (const auto *UX = dyn_cast<UnresolvedUsingTypenameDecl>(X)) {
+ return isSameQualifier(
+ UX->getQualifier(),
+ cast<UnresolvedUsingTypenameDecl>(Y)->getQualifier());
+ }
+
+ // Using-pack declarations are only created by instantiation, and match if
+ // they're instantiated from matching UnresolvedUsing...Decls.
+ if (const auto *UX = dyn_cast<UsingPackDecl>(X)) {
+ return declaresSameEntity(
+ UX->getInstantiatedFromUsingDecl(),
+ cast<UsingPackDecl>(Y)->getInstantiatedFromUsingDecl());
+ }
+
+ // Namespace alias definitions with the same target match.
+ if (const auto *NAX = dyn_cast<NamespaceAliasDecl>(X)) {
+ const auto *NAY = cast<NamespaceAliasDecl>(Y);
+ return NAX->getNamespace()->Equals(NAY->getNamespace());
+ }
+
+ return false;
+}
+
TemplateArgument
ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
switch (Arg.getKind()) {
@@ -8476,8 +8846,8 @@ static TypedefDecl *CreateHexagonBuiltinVaListDecl(const ASTContext *Context) {
FieldDecl *Field = FieldDecl::Create(
const_cast<ASTContext &>(*Context), VaListTagDecl, SourceLocation(),
SourceLocation(), &Context->Idents.get(FieldNames[i]), FieldTypes[i],
- /*TInfo=*/0,
- /*BitWidth=*/0,
+ /*TInfo=*/nullptr,
+ /*BitWidth=*/nullptr,
/*Mutable=*/false, ICIS_NoInit);
Field->setAccess(AS_public);
VaListTagDecl->addDecl(Field);
@@ -9819,12 +10189,13 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
// designates the object or function denoted by the reference, and the
// expression is an lvalue unless the reference is an rvalue reference and
// the expression is a function call (possibly inside parentheses).
- if (LangOpts.OpenMP && LHS->getAs<ReferenceType>() &&
- RHS->getAs<ReferenceType>() && LHS->getTypeClass() == RHS->getTypeClass())
- return mergeTypes(LHS->getAs<ReferenceType>()->getPointeeType(),
- RHS->getAs<ReferenceType>()->getPointeeType(),
+ auto *LHSRefTy = LHS->getAs<ReferenceType>();
+ auto *RHSRefTy = RHS->getAs<ReferenceType>();
+ if (LangOpts.OpenMP && LHSRefTy && RHSRefTy &&
+ LHS->getTypeClass() == RHS->getTypeClass())
+ return mergeTypes(LHSRefTy->getPointeeType(), RHSRefTy->getPointeeType(),
OfBlockPointer, Unqualified, BlockReturnType);
- if (LHS->getAs<ReferenceType>() || RHS->getAs<ReferenceType>())
+ if (LHSRefTy || RHSRefTy)
return {};
if (Unqualified) {
@@ -10311,7 +10682,7 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const {
// For _BitInt, return an unsigned _BitInt with same width.
if (const auto *EITy = T->getAs<BitIntType>())
- return getBitIntType(/*IsUnsigned=*/true, EITy->getNumBits());
+ return getBitIntType(/*Unsigned=*/true, EITy->getNumBits());
// For enums, get the underlying integer type of the enum, and let the general
// integer type signchanging code handle it.
@@ -10379,7 +10750,7 @@ QualType ASTContext::getCorrespondingSignedType(QualType T) const {
// For _BitInt, return a signed _BitInt with same width.
if (const auto *EITy = T->getAs<BitIntType>())
- return getBitIntType(/*IsUnsigned=*/false, EITy->getNumBits());
+ return getBitIntType(/*Unsigned=*/false, EITy->getNumBits());
// For enums, get the underlying integer type of the enum, and let the general
// integer type signchanging code handle it.
@@ -11574,6 +11945,15 @@ uint64_t ASTContext::getTargetNullPointerValue(QualType QT) const {
return getTargetInfo().getNullPointerValue(AS);
}
+unsigned ASTContext::getTargetAddressSpace(QualType T) const {
+ return T->isFunctionType() ? getTargetInfo().getProgramAddressSpace()
+ : getTargetAddressSpace(T.getQualifiers());
+}
+
+unsigned ASTContext::getTargetAddressSpace(Qualifiers Q) const {
+ return getTargetAddressSpace(Q.getAddressSpace());
+}
+
unsigned ASTContext::getTargetAddressSpace(LangAS AS) const {
if (isTargetAddressSpace(AS))
return toTargetAddressSpace(AS);
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 7f78da10e0b3..457465e87d93 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -8409,8 +8409,8 @@ Expected<TypeSourceInfo *> ASTImporter::Import(TypeSourceInfo *FromTSI) {
// and destructed after it is created. The construction already performs the
// import of the data.
template <typename T> struct AttrArgImporter {
- AttrArgImporter<T>(const AttrArgImporter<T> &) = delete;
- AttrArgImporter<T>(AttrArgImporter<T> &&) = default;
+ AttrArgImporter(const AttrArgImporter<T> &) = delete;
+ AttrArgImporter(AttrArgImporter<T> &&) = default;
AttrArgImporter<T> &operator=(const AttrArgImporter<T> &) = delete;
AttrArgImporter<T> &operator=(AttrArgImporter<T> &&) = default;
@@ -8429,8 +8429,8 @@ private:
// is used by the attribute classes. This object should be created once for the
// array data to be imported (the array size is not imported, just copied).
template <typename T> struct AttrArgArrayImporter {
- AttrArgArrayImporter<T>(const AttrArgArrayImporter<T> &) = delete;
- AttrArgArrayImporter<T>(AttrArgArrayImporter<T> &&) = default;
+ AttrArgArrayImporter(const AttrArgArrayImporter<T> &) = delete;
+ AttrArgArrayImporter(AttrArgArrayImporter<T> &&) = default;
AttrArgArrayImporter<T> &operator=(const AttrArgArrayImporter<T> &) = delete;
AttrArgArrayImporter<T> &operator=(AttrArgArrayImporter<T> &&) = default;
diff --git a/clang/lib/AST/AttrImpl.cpp b/clang/lib/AST/AttrImpl.cpp
index c2f13cf63830..7b8acfcd92be 100644
--- a/clang/lib/AST/AttrImpl.cpp
+++ b/clang/lib/AST/AttrImpl.cpp
@@ -139,6 +139,13 @@ void OMPDeclareTargetDeclAttr::printPrettyPragma(
OS << " device_type(" << ConvertDevTypeTyToStr(getDevType()) << ")";
if (getMapType() != MT_To)
OS << ' ' << ConvertMapTypeTyToStr(getMapType());
+ if (Expr *E = getIndirectExpr()) {
+ OS << " indirect(";
+ E->printPretty(OS, nullptr, Policy);
+ OS << ")";
+ } else if (getIndirect()) {
+ OS << " indirect";
+ }
}
llvm::Optional<OMPDeclareTargetDeclAttr *>
diff --git a/clang/lib/AST/CXXABI.h b/clang/lib/AST/CXXABI.h
index ca9424bcb7a4..9258a53fefeb 100644
--- a/clang/lib/AST/CXXABI.h
+++ b/clang/lib/AST/CXXABI.h
@@ -21,7 +21,6 @@ namespace clang {
class ASTContext;
class CXXConstructorDecl;
class DeclaratorDecl;
-class Expr;
class MangleContext;
class MangleNumberingContext;
class MemberPointerType;
diff --git a/clang/lib/AST/CommentLexer.cpp b/clang/lib/AST/CommentLexer.cpp
index 93531c06192d..61ce8979f13f 100644
--- a/clang/lib/AST/CommentLexer.cpp
+++ b/clang/lib/AST/CommentLexer.cpp
@@ -94,31 +94,12 @@ void Lexer::skipLineStartingDecorations() {
if (BufferPtr == CommentEnd)
return;
- switch (*BufferPtr) {
- case ' ':
- case '\t':
- case '\f':
- case '\v': {
- const char *NewBufferPtr = BufferPtr;
- NewBufferPtr++;
- if (NewBufferPtr == CommentEnd)
+ const char *NewBufferPtr = BufferPtr;
+ while (isHorizontalWhitespace(*NewBufferPtr))
+ if (++NewBufferPtr == CommentEnd)
return;
-
- char C = *NewBufferPtr;
- while (isHorizontalWhitespace(C)) {
- NewBufferPtr++;
- if (NewBufferPtr == CommentEnd)
- return;
- C = *NewBufferPtr;
- }
- if (C == '*')
- BufferPtr = NewBufferPtr + 1;
- break;
- }
- case '*':
- BufferPtr++;
- break;
- }
+ if (*NewBufferPtr == '*')
+ BufferPtr = NewBufferPtr + 1;
}
namespace {
@@ -289,6 +270,29 @@ void Lexer::formTokenWithChars(Token &Result, const char *TokEnd,
BufferPtr = TokEnd;
}
+const char *Lexer::skipTextToken() {
+ const char *TokenPtr = BufferPtr;
+ assert(TokenPtr < CommentEnd);
+ StringRef TokStartSymbols = ParseCommands ? "\n\r\\@\"&<" : "\n\r";
+
+again:
+ size_t End =
+ StringRef(TokenPtr, CommentEnd - TokenPtr).find_first_of(TokStartSymbols);
+ if (End == StringRef::npos)
+ return CommentEnd;
+
+ // Doxygen doesn't recognize any commands in a one-line double quotation.
+ // If we don't find an ending quotation mark, we pretend it never began.
+ if (*(TokenPtr + End) == '\"') {
+ TokenPtr += End + 1;
+ End = StringRef(TokenPtr, CommentEnd - TokenPtr).find_first_of("\n\r\"");
+ if (End != StringRef::npos && *(TokenPtr + End) == '\"')
+ TokenPtr += End + 1;
+ goto again;
+ }
+ return TokenPtr + End;
+}
+
void Lexer::lexCommentText(Token &T) {
assert(CommentState == LCS_InsideBCPLComment ||
CommentState == LCS_InsideCComment);
@@ -309,17 +313,8 @@ void Lexer::lexCommentText(Token &T) {
skipLineStartingDecorations();
return;
- default: {
- StringRef TokStartSymbols = ParseCommands ? "\n\r\\@&<" : "\n\r";
- size_t End = StringRef(TokenPtr, CommentEnd - TokenPtr)
- .find_first_of(TokStartSymbols);
- if (End != StringRef::npos)
- TokenPtr += End;
- else
- TokenPtr = CommentEnd;
- formTextToken(T, TokenPtr);
- return;
- }
+ default:
+ return formTextToken(T, skipTextToken());
}
};
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index e63560f1b6fe..b2ee34f20cf7 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -786,6 +786,7 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
//
// Note that we don't want to make the variable non-external
// because of this, but unique-external linkage suits us.
+
if (Context.getLangOpts().CPlusPlus && !isFirstInExternCContext(Var) &&
!IgnoreVarTypeLinkage) {
LinkageInfo TypeLV = getLVForType(*Var->getType(), computation);
@@ -912,10 +913,6 @@ 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;
}
@@ -1069,6 +1066,7 @@ LinkageComputer::getLVForClassMember(const NamedDecl *D,
// Finally, merge in information from the class.
LV.mergeMaybeWithVisibility(classLV, considerClassVisibility);
+
return LV;
}
@@ -3251,7 +3249,6 @@ bool FunctionDecl::isGlobal() const {
if (const auto *Namespace = cast<NamespaceDecl>(DC)) {
if (!Namespace->getDeclName())
return false;
- break;
}
}
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index 064012ba865c..9ee1cc083086 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -995,6 +995,15 @@ bool Decl::AccessDeclContextCheck() const {
return true;
}
+bool Decl::isInExportDeclContext() const {
+ const DeclContext *DC = getLexicalDeclContext();
+
+ while (DC && !isa<ExportDecl>(DC))
+ DC = DC->getLexicalParent();
+
+ return DC && isa<ExportDecl>(DC);
+}
+
static Decl::Kind getKind(const Decl *D) { return D->getKind(); }
static Decl::Kind getKind(const DeclContext *DC) { return DC->getDeclKind(); }
@@ -1212,7 +1221,8 @@ bool DeclContext::Encloses(const DeclContext *DC) const {
return getPrimaryContext()->Encloses(DC);
for (; DC; DC = DC->getParent())
- if (!isa<LinkageSpecDecl>(DC) && DC->getPrimaryContext() == this)
+ if (!isa<LinkageSpecDecl>(DC) && !isa<ExportDecl>(DC) &&
+ DC->getPrimaryContext() == this)
return true;
return false;
}
@@ -1643,9 +1653,9 @@ void DeclContext::buildLookupImpl(DeclContext *DCtx, bool Internal) {
DeclContext::lookup_result
DeclContext::lookup(DeclarationName Name) const {
- assert(getDeclKind() != Decl::LinkageSpec &&
- getDeclKind() != Decl::Export &&
- "should not perform lookups into transparent contexts");
+ // For transparent DeclContext, we should lookup in their enclosing context.
+ if (getDeclKind() == Decl::LinkageSpec || getDeclKind() == Decl::Export)
+ return getParent()->lookup(Name);
const DeclContext *PrimaryContext = getPrimaryContext();
if (PrimaryContext != this)
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 1780358cc348..0cf6e60b2a6c 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -79,10 +79,9 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
HasBasesWithFields(false), HasBasesWithNonStaticDataMembers(false),
HasPrivateFields(false), HasProtectedFields(false),
HasPublicFields(false), HasMutableFields(false), HasVariantMembers(false),
- HasOnlyCMembers(true), HasInClassInitializer(false),
+ HasOnlyCMembers(true), HasInitMethod(false), HasInClassInitializer(false),
HasUninitializedReferenceMember(false), HasUninitializedFields(false),
- HasInheritedConstructor(false),
- HasInheritedDefaultConstructor(false),
+ HasInheritedConstructor(false), HasInheritedDefaultConstructor(false),
HasInheritedAssignment(false),
NeedOverloadResolutionForCopyConstructor(false),
NeedOverloadResolutionForMoveConstructor(false),
@@ -3272,7 +3271,7 @@ void MSGuidDecl::anchor() {}
MSGuidDecl::MSGuidDecl(DeclContext *DC, QualType T, Parts P)
: ValueDecl(Decl::MSGuid, DC, SourceLocation(), DeclarationName(), T),
- PartVal(P), APVal() {}
+ PartVal(P) {}
MSGuidDecl *MSGuidDecl::Create(const ASTContext &C, QualType T, Parts P) {
DeclContext *DC = C.getTranslationUnitDecl();
diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp
index ba827a79c022..f15dd78929e2 100644
--- a/clang/lib/AST/DeclObjC.cpp
+++ b/clang/lib/AST/DeclObjC.cpp
@@ -232,6 +232,18 @@ ObjCPropertyDecl::getDefaultSynthIvarName(ASTContext &Ctx) const {
return &Ctx.Idents.get(ivarName.str());
}
+ObjCPropertyDecl *ObjCContainerDecl::getProperty(const IdentifierInfo *Id,
+ bool IsInstance) const {
+ for (auto *LookupResult : lookup(Id)) {
+ if (auto *Prop = dyn_cast<ObjCPropertyDecl>(LookupResult)) {
+ if (Prop->isInstanceProperty() == IsInstance) {
+ return Prop;
+ }
+ }
+ }
+ return nullptr;
+}
+
/// FindPropertyDeclaration - Finds declaration of the property given its name
/// in 'PropertyId' and returns it. It returns 0, if not found.
ObjCPropertyDecl *ObjCContainerDecl::FindPropertyDeclaration(
diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index 044eb8f8f8e5..c3f1d1544f79 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -588,7 +588,7 @@ static void printExplicitSpecifier(ExplicitSpecifier ES, llvm::raw_ostream &Out,
}
EOut << " ";
EOut.flush();
- Out << EOut.str();
+ Out << Proto;
}
void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
@@ -731,7 +731,6 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
FT->getNoexceptExpr()->printPretty(EOut, nullptr, SubPolicy,
Indentation, "\n", &Context);
EOut.flush();
- Proto += EOut.str();
Proto += ")";
}
}
@@ -885,7 +884,10 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
}
}
- printDeclType(T, D->getName());
+ printDeclType(T, (isa<ParmVarDecl>(D) && Policy.CleanUglifiedParameters &&
+ D->getIdentifier())
+ ? D->getIdentifier()->deuglifiedName()
+ : D->getName());
Expr *Init = D->getInit();
if (!Policy.SuppressInitializers && Init) {
bool ImplicitInit = false;
@@ -1131,8 +1133,12 @@ void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) {
else if (TTP->getDeclName())
Out << ' ';
- if (TTP->getDeclName())
- Out << TTP->getDeclName();
+ if (TTP->getDeclName()) {
+ if (Policy.CleanUglifiedParameters && TTP->getIdentifier())
+ Out << TTP->getIdentifier()->deuglifiedName();
+ else
+ Out << TTP->getDeclName();
+ }
} else if (auto *TD = D->getTemplatedDecl())
Visit(TD);
else if (const auto *Concept = dyn_cast<ConceptDecl>(D)) {
@@ -1742,8 +1748,12 @@ void DeclPrinter::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *TTP) {
else if (TTP->getDeclName())
Out << ' ';
- if (TTP->getDeclName())
- Out << TTP->getDeclName();
+ if (TTP->getDeclName()) {
+ if (Policy.CleanUglifiedParameters && TTP->getIdentifier())
+ Out << TTP->getIdentifier()->deuglifiedName();
+ else
+ Out << TTP->getDeclName();
+ }
if (TTP->hasDefaultArgument()) {
Out << " = ";
@@ -1755,7 +1765,8 @@ void DeclPrinter::VisitNonTypeTemplateParmDecl(
const NonTypeTemplateParmDecl *NTTP) {
StringRef Name;
if (IdentifierInfo *II = NTTP->getIdentifier())
- Name = II->getName();
+ Name =
+ Policy.CleanUglifiedParameters ? II->deuglifiedName() : II->getName();
printDeclType(NTTP->getType(), Name, NTTP->isParameterPack());
if (NTTP->hasDefaultArgument()) {
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 2530beb89d17..45e94847caee 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -1281,7 +1281,7 @@ StringLiteral::getLocationOfByte(unsigned ByteNo, const SourceManager &SM,
StringOffset = *StartTokenByteOffset;
ByteNo -= StringOffset;
}
- while (1) {
+ while (true) {
assert(TokNo < getNumConcatenated() && "Invalid byte number!");
SourceLocation StrTokLoc = getStrTokenLoc(TokNo);
diff --git a/clang/lib/AST/ExprConcepts.cpp b/clang/lib/AST/ExprConcepts.cpp
index 8cb8625e2a1a..c17453fb45fb 100644
--- a/clang/lib/AST/ExprConcepts.cpp
+++ b/clang/lib/AST/ExprConcepts.cpp
@@ -57,9 +57,9 @@ ConceptSpecializationExpr::ConceptSpecializationExpr(
}
ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty,
- unsigned NumTemplateArgs)
- : Expr(ConceptSpecializationExprClass, Empty), ConceptReference(),
- NumTemplateArgs(NumTemplateArgs) { }
+ unsigned NumTemplateArgs)
+ : Expr(ConceptSpecializationExprClass, Empty),
+ NumTemplateArgs(NumTemplateArgs) {}
void ConceptSpecializationExpr::setTemplateArguments(
ArrayRef<TemplateArgument> Converted) {
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 469339e8cd62..f9416e8e215d 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -1706,8 +1706,8 @@ namespace {
struct MemberPtr {
MemberPtr() {}
- explicit MemberPtr(const ValueDecl *Decl) :
- DeclAndIsDerivedMember(Decl, false), Path() {}
+ explicit MemberPtr(const ValueDecl *Decl)
+ : DeclAndIsDerivedMember(Decl, false) {}
/// The member or (direct or indirect) field referred to by this member
/// pointer, or 0 if this is a null member pointer.
@@ -4933,8 +4933,13 @@ static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info,
if (SS->getConditionVariable() &&
!EvaluateDecl(Info, SS->getConditionVariable()))
return ESR_Failed;
- if (!EvaluateInteger(SS->getCond(), Value, Info))
- return ESR_Failed;
+ if (SS->getCond()->isValueDependent()) {
+ if (!EvaluateDependentExpr(SS->getCond(), Info))
+ return ESR_Failed;
+ } else {
+ if (!EvaluateInteger(SS->getCond(), Value, Info))
+ return ESR_Failed;
+ }
if (!CondScope.destroy())
return ESR_Failed;
}
@@ -6037,7 +6042,7 @@ static bool EvaluateArgs(ArrayRef<const Expr *> Args, CallRef Call,
unsigned ASTIdx = Idx.getASTIndex();
if (ASTIdx >= Args.size())
continue;
- ForbiddenNullArgs[ASTIdx] = 1;
+ ForbiddenNullArgs[ASTIdx] = true;
}
}
}
@@ -10434,6 +10439,15 @@ bool VectorExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
if (!Evaluate(SubExprValue, Info, SubExpr))
return false;
+ // FIXME: This vector evaluator someday needs to be changed to be LValue
+ // aware/keep LValue information around, rather than dealing with just vector
+ // types directly. Until then, we cannot handle cases where the operand to
+ // these unary operators is an LValue. The only case I've been able to see
+ // cause this is operator++ assigning to a member expression (only valid in
+ // altivec compilations) in C mode, so this shouldn't limit us too much.
+ if (SubExprValue.isLValue())
+ return false;
+
assert(SubExprValue.getVectorLength() == VD->getNumElements() &&
"Vector length doesn't match type?");
@@ -10680,28 +10694,55 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
bool HadZeroInit = Value->hasValue();
if (const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(Type)) {
- unsigned N = CAT->getSize().getZExtValue();
+ unsigned FinalSize = CAT->getSize().getZExtValue();
// Preserve the array filler if we had prior zero-initialization.
APValue Filler =
HadZeroInit && Value->hasArrayFiller() ? Value->getArrayFiller()
: APValue();
- *Value = APValue(APValue::UninitArray(), N, N);
-
- if (HadZeroInit)
- for (unsigned I = 0; I != N; ++I)
- Value->getArrayInitializedElt(I) = Filler;
+ *Value = APValue(APValue::UninitArray(), 0, FinalSize);
+ if (FinalSize == 0)
+ return true;
- // Initialize the elements.
LValue ArrayElt = Subobject;
ArrayElt.addArray(Info, E, CAT);
- for (unsigned I = 0; I != N; ++I)
- if (!VisitCXXConstructExpr(E, ArrayElt, &Value->getArrayInitializedElt(I),
- CAT->getElementType()) ||
- !HandleLValueArrayAdjustment(Info, E, ArrayElt, CAT->getElementType(),
- 1))
- return false;
+ // We do the whole initialization in two passes, first for just one element,
+ // then for the whole array. It's possible we may find out we can't do const
+ // init in the first pass, in which case we avoid allocating a potentially
+ // large array. We don't do more passes because expanding array requires
+ // copying the data, which is wasteful.
+ for (const unsigned N : {1u, FinalSize}) {
+ unsigned OldElts = Value->getArrayInitializedElts();
+ if (OldElts == N)
+ break;
+
+ // Expand the array to appropriate size.
+ APValue NewValue(APValue::UninitArray(), N, FinalSize);
+ for (unsigned I = 0; I < OldElts; ++I)
+ NewValue.getArrayInitializedElt(I).swap(
+ Value->getArrayInitializedElt(I));
+ Value->swap(NewValue);
+
+ if (HadZeroInit)
+ for (unsigned I = OldElts; I < N; ++I)
+ Value->getArrayInitializedElt(I) = Filler;
+
+ // Initialize the elements.
+ for (unsigned I = OldElts; I < N; ++I) {
+ if (!VisitCXXConstructExpr(E, ArrayElt,
+ &Value->getArrayInitializedElt(I),
+ CAT->getElementType()) ||
+ !HandleLValueArrayAdjustment(Info, E, ArrayElt,
+ CAT->getElementType(), 1))
+ return false;
+ // When checking for const initilization any diagnostic is considered
+ // an error.
+ if (Info.EvalStatus.Diag && !Info.EvalStatus.Diag->empty() &&
+ !Info.keepEvaluatingAfterFailure())
+ return false;
+ }
+ }
return true;
}
diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp
index 83b952116a5e..102bcca96a38 100644
--- a/clang/lib/AST/FormatString.cpp
+++ b/clang/lib/AST/FormatString.cpp
@@ -21,7 +21,6 @@ using clang::analyze_format_string::FormatStringHandler;
using clang::analyze_format_string::FormatSpecifier;
using clang::analyze_format_string::LengthModifier;
using clang::analyze_format_string::OptionalAmount;
-using clang::analyze_format_string::PositionContext;
using clang::analyze_format_string::ConversionSpecifier;
using namespace clang;
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index 5c8cb4274260..da538aa332ff 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -207,13 +207,13 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
template <class Emitter>
bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
- OptionScope<Emitter> Scope(this, /*discardResult=*/true);
+ OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/true);
return this->Visit(E);
}
template <class Emitter>
bool ByteCodeExprGen<Emitter>::visit(const Expr *E) {
- OptionScope<Emitter> Scope(this, /*discardResult=*/false);
+ OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/false);
return this->Visit(E);
}
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index 716f28551e58..124a6ff03f18 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -28,8 +28,6 @@ namespace clang {
class QualType;
namespace interp {
-class Function;
-class State;
template <class Emitter> class LocalScope;
template <class Emitter> class RecordScope;
diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.h b/clang/lib/AST/Interp/ByteCodeStmtGen.h
index d9c0b64ed4b8..3bc665b84b4d 100644
--- a/clang/lib/AST/Interp/ByteCodeStmtGen.h
+++ b/clang/lib/AST/Interp/ByteCodeStmtGen.h
@@ -25,11 +25,7 @@
#include "llvm/ADT/Optional.h"
namespace clang {
-class QualType;
-
namespace interp {
-class Function;
-class State;
template <class Emitter> class LoopScope;
template <class Emitter> class SwitchScope;
diff --git a/clang/lib/AST/Interp/Context.h b/clang/lib/AST/Interp/Context.h
index 4f25ff977b81..0627d9fb14f5 100644
--- a/clang/lib/AST/Interp/Context.h
+++ b/clang/lib/AST/Interp/Context.h
@@ -23,7 +23,6 @@
namespace clang {
class ASTContext;
class LangOptions;
-class Stmt;
class FunctionDecl;
class VarDecl;
diff --git a/clang/lib/AST/Interp/InterpBlock.h b/clang/lib/AST/Interp/InterpBlock.h
index 0ccdef221c83..2d5386e60b8c 100644
--- a/clang/lib/AST/Interp/InterpBlock.h
+++ b/clang/lib/AST/Interp/InterpBlock.h
@@ -25,10 +25,8 @@ namespace clang {
namespace interp {
class Block;
class DeadBlock;
-class Context;
class InterpState;
class Pointer;
-class Function;
enum PrimType : unsigned;
/// A memory block, either on the stack or in the heap.
diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h
index f2f6e0e76018..587531aec82a 100644
--- a/clang/lib/AST/Interp/Pointer.h
+++ b/clang/lib/AST/Interp/Pointer.h
@@ -26,10 +26,7 @@ namespace clang {
namespace interp {
class Block;
class DeadBlock;
-class Context;
-class InterpState;
class Pointer;
-class Function;
enum PrimType : unsigned;
/// A pointer to a memory block, live or dead.
diff --git a/clang/lib/AST/Interp/PrimType.h b/clang/lib/AST/Interp/PrimType.h
index f5f4f8e5c32d..de4bf9bf802e 100644
--- a/clang/lib/AST/Interp/PrimType.h
+++ b/clang/lib/AST/Interp/PrimType.h
@@ -81,35 +81,27 @@ inline bool isPrimitiveIntegral(PrimType Type) {
/// Helper macro to simplify type switches.
/// The macro implicitly exposes a type T in the scope of the inner block.
#define TYPE_SWITCH_CASE(Name, B) \
- case Name: { using T = PrimConv<Name>::T; do {B;} while(0); break; }
+ case Name: { using T = PrimConv<Name>::T; B; break; }
#define TYPE_SWITCH(Expr, B) \
- switch (Expr) { \
- TYPE_SWITCH_CASE(PT_Sint8, B) \
- TYPE_SWITCH_CASE(PT_Uint8, B) \
- TYPE_SWITCH_CASE(PT_Sint16, B) \
- TYPE_SWITCH_CASE(PT_Uint16, B) \
- TYPE_SWITCH_CASE(PT_Sint32, B) \
- TYPE_SWITCH_CASE(PT_Uint32, B) \
- TYPE_SWITCH_CASE(PT_Sint64, B) \
- TYPE_SWITCH_CASE(PT_Uint64, B) \
- TYPE_SWITCH_CASE(PT_Bool, B) \
- TYPE_SWITCH_CASE(PT_Ptr, B) \
- }
+ do { \
+ switch (Expr) { \
+ TYPE_SWITCH_CASE(PT_Sint8, B) \
+ TYPE_SWITCH_CASE(PT_Uint8, B) \
+ TYPE_SWITCH_CASE(PT_Sint16, B) \
+ TYPE_SWITCH_CASE(PT_Uint16, B) \
+ TYPE_SWITCH_CASE(PT_Sint32, B) \
+ TYPE_SWITCH_CASE(PT_Uint32, B) \
+ TYPE_SWITCH_CASE(PT_Sint64, B) \
+ TYPE_SWITCH_CASE(PT_Uint64, B) \
+ TYPE_SWITCH_CASE(PT_Bool, B) \
+ TYPE_SWITCH_CASE(PT_Ptr, B) \
+ } \
+ } while (0)
#define COMPOSITE_TYPE_SWITCH(Expr, B, D) \
- switch (Expr) { \
- TYPE_SWITCH_CASE(PT_Ptr, B) \
- default: do { D; } while(0); break; \
- }
-#define INT_TYPE_SWITCH(Expr, B) \
- switch (Expr) { \
- TYPE_SWITCH_CASE(PT_Sint8, B) \
- TYPE_SWITCH_CASE(PT_Uint8, B) \
- TYPE_SWITCH_CASE(PT_Sint16, B) \
- TYPE_SWITCH_CASE(PT_Uint16, B) \
- TYPE_SWITCH_CASE(PT_Sint32, B) \
- TYPE_SWITCH_CASE(PT_Uint32, B) \
- TYPE_SWITCH_CASE(PT_Sint64, B) \
- TYPE_SWITCH_CASE(PT_Uint64, B) \
- default: llvm_unreachable("not an integer"); \
- }
+ do { \
+ switch (Expr) { \
+ TYPE_SWITCH_CASE(PT_Ptr, B) \
+ default: { D; break; } \
+ } \
+ } while (0)
#endif
diff --git a/clang/lib/AST/Interp/Program.h b/clang/lib/AST/Interp/Program.h
index c81ec777a5fe..ca985af8ad30 100644
--- a/clang/lib/AST/Interp/Program.h
+++ b/clang/lib/AST/Interp/Program.h
@@ -29,15 +29,12 @@ namespace clang {
class RecordDecl;
class Expr;
class FunctionDecl;
-class Stmt;
class StringLiteral;
class VarDecl;
namespace interp {
class Context;
-class State;
class Record;
-class Scope;
/// The program contains and links the bytecode for all functions.
class Program {
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 7afc1250a36f..2e734e2b28cd 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -659,8 +659,7 @@ bool ItaniumMangleContextImpl::isUniqueInternalLinkageDecl(
}
bool ItaniumMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) {
- const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
- if (FD) {
+ if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
LanguageLinkage L = FD->getLanguageLinkage();
// Overloadable functions need mangling.
if (FD->hasAttr<OverloadableAttr>())
@@ -696,21 +695,24 @@ bool ItaniumMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) {
if (!getASTContext().getLangOpts().CPlusPlus)
return false;
- const VarDecl *VD = dyn_cast<VarDecl>(D);
- if (VD && !isa<DecompositionDecl>(D)) {
+ if (const auto *VD = dyn_cast<VarDecl>(D)) {
+ // Decompositions are mangled.
+ if (isa<DecompositionDecl>(VD))
+ return true;
+
// C variables are not mangled.
if (VD->isExternC())
return false;
- // Variables at global scope with non-internal linkage are not mangled
+ // Variables at global scope with non-internal linkage are not mangled.
const DeclContext *DC = getEffectiveDeclContext(D);
// Check for extern variable declared locally.
if (DC->isFunctionOrMethod() && D->hasLinkage())
- while (!DC->isNamespace() && !DC->isTranslationUnit())
+ while (!DC->isFileContext())
DC = getEffectiveParentContext(DC);
if (DC->isTranslationUnit() && D->getFormalLinkage() != InternalLinkage &&
!CXXNameMangler::shouldHaveAbiTags(*this, VD) &&
- !isa<VarTemplateSpecializationDecl>(D))
+ !isa<VarTemplateSpecializationDecl>(VD))
return false;
}
@@ -5889,9 +5891,11 @@ void CXXNameMangler::mangleTemplateParameter(unsigned Depth, unsigned Index) {
}
void CXXNameMangler::mangleSeqID(unsigned SeqID) {
- if (SeqID == 1)
+ if (SeqID == 0) {
+ // Nothing.
+ } else if (SeqID == 1) {
Out << '0';
- else if (SeqID > 1) {
+ } else {
SeqID--;
// <seq-id> is encoded in base-36, using digits and upper case letters.
diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp
index 54dbf484f377..984da9909ce2 100644
--- a/clang/lib/AST/Mangle.cpp
+++ b/clang/lib/AST/Mangle.cpp
@@ -225,11 +225,17 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
if (!MD->isStatic())
++ArgWords;
- for (const auto &AT : Proto->param_types())
+ for (const auto &AT : Proto->param_types()) {
+ // If an argument type is incomplete there is no way to get its size to
+ // correctly encode into the mangling scheme.
+ // Follow GCCs behaviour by simply breaking out of the loop.
+ if (AT->isIncompleteType())
+ break;
// Size should be aligned to pointer size.
ArgWords +=
llvm::alignTo(ASTContext.getTypeSize(AT), TI.getPointerWidth(0)) /
TI.getPointerWidth(0);
+ }
Out << ((TI.getPointerWidth(0) / 8) * ArgWords);
}
diff --git a/clang/lib/AST/MicrosoftCXXABI.cpp b/clang/lib/AST/MicrosoftCXXABI.cpp
index 53d7e0b042ff..b7dc0e62e66a 100644
--- a/clang/lib/AST/MicrosoftCXXABI.cpp
+++ b/clang/lib/AST/MicrosoftCXXABI.cpp
@@ -36,8 +36,8 @@ class MicrosoftNumberingContext : public MangleNumberingContext {
public:
MicrosoftNumberingContext()
- : MangleNumberingContext(), LambdaManglingNumber(0),
- StaticLocalNumber(0), StaticThreadlocalNumber(0) {}
+ : LambdaManglingNumber(0), StaticLocalNumber(0),
+ StaticThreadlocalNumber(0) {}
unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override {
return ++LambdaManglingNumber;
diff --git a/clang/lib/AST/OSLog.cpp b/clang/lib/AST/OSLog.cpp
index 094c0102854b..4cc5def0651f 100644
--- a/clang/lib/AST/OSLog.cpp
+++ b/clang/lib/AST/OSLog.cpp
@@ -56,8 +56,8 @@ public:
}
bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
- const char *StartSpecifier,
- unsigned SpecifierLen) override {
+ const char *StartSpecifier, unsigned SpecifierLen,
+ const TargetInfo &) override {
if (!FS.consumesDataArgument() &&
FS.getConversionSpecifier().getKind() !=
clang::analyze_format_string::ConversionSpecifier::PrintErrno)
diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp
index e2569c9e20df..c6c41abc7e9a 100644
--- a/clang/lib/AST/PrintfFormatString.cpp
+++ b/clang/lib/AST/PrintfFormatString.cpp
@@ -428,7 +428,7 @@ bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,
continue;
// We have a format specifier. Pass it to the callback.
if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(),
- I - FSR.getStart()))
+ I - FSR.getStart(), Target))
return true;
}
assert(I == E && "Format string not exhausted");
@@ -711,8 +711,8 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
CS.setKind(ConversionSpecifier::sArg);
// Disable irrelevant flags
- HasAlternativeForm = 0;
- HasLeadingZeroes = 0;
+ HasAlternativeForm = false;
+ HasLeadingZeroes = false;
// Set the long length modifier for wide characters
if (QT->getPointeeType()->isWideCharType())
@@ -878,9 +878,9 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
CS.setKind(ConversionSpecifier::cArg);
LM.setKind(LengthModifier::None);
Precision.setHowSpecified(OptionalAmount::NotSpecified);
- HasAlternativeForm = 0;
- HasLeadingZeroes = 0;
- HasPlusPrefix = 0;
+ HasAlternativeForm = false;
+ HasLeadingZeroes = false;
+ HasPlusPrefix = false;
}
// Test for Floating type first as LongDouble can pass isUnsignedIntegerType
else if (QT->isRealFloatingType()) {
@@ -888,12 +888,12 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
}
else if (QT->isSignedIntegerType()) {
CS.setKind(ConversionSpecifier::dArg);
- HasAlternativeForm = 0;
+ HasAlternativeForm = false;
}
else if (QT->isUnsignedIntegerType()) {
CS.setKind(ConversionSpecifier::uArg);
- HasAlternativeForm = 0;
- HasPlusPrefix = 0;
+ HasAlternativeForm = false;
+ HasPlusPrefix = false;
} else {
llvm_unreachable("Unexpected type");
}
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp
index 3e39ec1c718d..61a30ead165e 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -2021,6 +2021,7 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
CharUnits UnpackedFieldAlign =
!DefaultsToAIXPowerAlignment ? FieldAlign : PreferredAlign;
CharUnits UnpackedFieldOffset = FieldOffset;
+ CharUnits OriginalFieldAlign = UnpackedFieldAlign;
if (FieldPacked) {
FieldAlign = CharUnits::One();
@@ -2105,6 +2106,22 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
// Remember max struct/class ABI-specified alignment.
UnadjustedAlignment = std::max(UnadjustedAlignment, FieldAlign);
UpdateAlignment(FieldAlign, UnpackedFieldAlign, PreferredAlign);
+
+ // For checking the alignment of inner fields against
+ // the alignment of its parent record.
+ if (const RecordDecl *RD = D->getParent()) {
+ // Check if packed attribute or pragma pack is present.
+ if (RD->hasAttr<PackedAttr>() || !MaxFieldAlignment.isZero())
+ if (FieldAlign < OriginalFieldAlign)
+ if (D->getType()->isRecordType()) {
+ // If the offset is a multiple of the alignment of
+ // the type, raise the warning.
+ // TODO: Takes no account the alignment of the outer struct
+ if (FieldOffset % OriginalFieldAlign != 0)
+ Diag(D->getLocation(), diag::warn_unaligned_access)
+ << Context.getTypeDeclType(RD) << D->getName() << D->getType();
+ }
+ }
}
void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp
index 4f76f6ec12ed..be19d3b2cce2 100644
--- a/clang/lib/AST/Stmt.cpp
+++ b/clang/lib/AST/Stmt.cpp
@@ -568,21 +568,20 @@ void GCCAsmStmt::setOutputsAndInputsAndClobbers(const ASTContext &C,
/// translate this into a numeric value needed to reference the same operand.
/// This returns -1 if the operand name is invalid.
int GCCAsmStmt::getNamedOperand(StringRef SymbolicName) const {
- unsigned NumPlusOperands = 0;
-
// Check if this is an output operand.
- for (unsigned i = 0, e = getNumOutputs(); i != e; ++i) {
+ unsigned NumOutputs = getNumOutputs();
+ for (unsigned i = 0; i != NumOutputs; ++i)
if (getOutputName(i) == SymbolicName)
return i;
- }
- for (unsigned i = 0, e = getNumInputs(); i != e; ++i)
+ unsigned NumInputs = getNumInputs();
+ for (unsigned i = 0; i != NumInputs; ++i)
if (getInputName(i) == SymbolicName)
- return getNumOutputs() + NumPlusOperands + i;
+ return NumOutputs + i;
for (unsigned i = 0, e = getNumLabels(); i != e; ++i)
if (getLabelName(i) == SymbolicName)
- return i + getNumOutputs() + getNumInputs();
+ return NumOutputs + NumInputs + getNumPlusOperands() + i;
// Not found.
return -1;
diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp
index b336a0637d5e..8a9f73d3dbf0 100644
--- a/clang/lib/AST/StmtOpenMP.cpp
+++ b/clang/lib/AST/StmtOpenMP.cpp
@@ -518,7 +518,7 @@ OMPSectionDirective *OMPSectionDirective::Create(const ASTContext &C,
bool HasCancel) {
auto *Dir =
createDirective<OMPSectionDirective>(C, llvm::None, AssociatedStmt,
- /*NumChildre=*/0, StartLoc, EndLoc);
+ /*NumChildren=*/0, StartLoc, EndLoc);
Dir->setHasCancel(HasCancel);
return Dir;
}
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index b65a38d1e566..adc0720fe000 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -1030,7 +1030,12 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) {
Qualifier->print(OS, Policy);
if (Node->hasTemplateKeyword())
OS << "template ";
- OS << Node->getNameInfo();
+ if (Policy.CleanUglifiedParameters &&
+ isa<ParmVarDecl, NonTypeTemplateParmDecl>(Node->getDecl()) &&
+ Node->getDecl()->getIdentifier())
+ OS << Node->getDecl()->getIdentifier()->deuglifiedName();
+ else
+ Node->getNameInfo().printName(OS, Policy);
if (Node->hasExplicitTemplateArgs()) {
const TemplateParameterList *TPL = nullptr;
if (!Node->hadMultipleCandidates())
@@ -2069,7 +2074,10 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
} else {
NeedComma = true;
}
- std::string ParamStr = P->getNameAsString();
+ std::string ParamStr =
+ (Policy.CleanUglifiedParameters && P->getIdentifier())
+ ? P->getIdentifier()->deuglifiedName().str()
+ : P->getNameAsString();
P->getOriginalType().print(OS, Policy, ParamStr);
}
if (Method->isVariadic()) {
diff --git a/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp
index c8bd74f0b5bb..05d7d58b71c4 100644
--- a/clang/lib/AST/TemplateName.cpp
+++ b/clang/lib/AST/TemplateName.cpp
@@ -223,8 +223,12 @@ bool TemplateName::containsUnexpandedParameterPack() const {
void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
Qualified Qual) const {
if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>())
- if (Qual == Qualified::Fully &&
- getDependence() != TemplateNameDependenceScope::DependentInstantiation)
+ if (Policy.CleanUglifiedParameters &&
+ isa<TemplateTemplateParmDecl>(Template) && Template->getIdentifier())
+ OS << Template->getIdentifier()->deuglifiedName();
+ else if (Qual == Qualified::Fully &&
+ getDependence() !=
+ TemplateNameDependenceScope::DependentInstantiation)
Template->printQualifiedName(OS, Policy);
else
OS << *Template;
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index c771fe264b0c..774b3e94159d 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -194,7 +194,7 @@ void ConstantArrayType::Profile(llvm::FoldingSetNodeID &ID,
ID.AddInteger(ArraySize.getZExtValue());
ID.AddInteger(SizeMod);
ID.AddInteger(TypeQuals);
- ID.AddBoolean(SizeExpr != 0);
+ ID.AddBoolean(SizeExpr != nullptr);
if (SizeExpr)
SizeExpr->Profile(ID, Context, true);
}
diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp
index c3ed08d5a8b3..13aa54c48f66 100644
--- a/clang/lib/AST/TypeLoc.cpp
+++ b/clang/lib/AST/TypeLoc.cpp
@@ -622,6 +622,7 @@ void AutoTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) {
setFoundDecl(nullptr);
setRAngleLoc(Loc);
setLAngleLoc(Loc);
+ setRParenLoc(Loc);
TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(),
getTypePtr()->getArgs(),
getArgInfos(), Loc);
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 2a33a69f288d..bba323f651aa 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -280,7 +280,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
case Type::Attributed: {
// We still want to print the address_space before the type if it is an
// address_space attribute.
- const auto *AttrTy = cast<AttributedType>(T);
+ const auto *AttrTy = cast<AttributedType>(UnderlyingType);
CanPrefixQualifiers = AttrTy->getAttrKind() == attr::AddressSpace;
}
}
@@ -1418,7 +1418,8 @@ void TypePrinter::printTemplateTypeParmBefore(const TemplateTypeParmType *T,
}
OS << "auto";
} else if (IdentifierInfo *Id = T->getIdentifier())
- OS << Id->getName();
+ OS << (Policy.CleanUglifiedParameters ? Id->deuglifiedName()
+ : Id->getName());
else
OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex();
diff --git a/clang/lib/AST/VTableBuilder.cpp b/clang/lib/AST/VTableBuilder.cpp
index f938565c3cb4..24586d6b70d4 100644
--- a/clang/lib/AST/VTableBuilder.cpp
+++ b/clang/lib/AST/VTableBuilder.cpp
@@ -2328,7 +2328,7 @@ ItaniumVTableContext::computeVTableRelatedInformation(const CXXRecordDecl *RD) {
return;
ItaniumVTableBuilder Builder(*this, RD, CharUnits::Zero(),
- /*MostDerivedClassIsVirtual=*/0, RD);
+ /*MostDerivedClassIsVirtual=*/false, RD);
Entry = CreateVTableLayout(Builder);
MethodVTableIndices.insert(Builder.vtable_indices_begin(),
diff --git a/clang/lib/ASTMatchers/Dynamic/Marshallers.h b/clang/lib/ASTMatchers/Dynamic/Marshallers.h
index fa9d42247e24..3e9c4f31b84d 100644
--- a/clang/lib/ASTMatchers/Dynamic/Marshallers.h
+++ b/clang/lib/ASTMatchers/Dynamic/Marshallers.h
@@ -524,8 +524,9 @@ variadicMatcherDescriptor(StringRef MatcherName, SourceRange NameRange,
}
return {};
}
- InnerArgs.set_size(i + 1);
- InnerArgsPtr[i] = new (&InnerArgs[i]) ArgT(ArgTraits::get(Value));
+ assert(InnerArgs.size() < InnerArgs.capacity());
+ InnerArgs.emplace_back(ArgTraits::get(Value));
+ InnerArgsPtr[i] = &InnerArgs[i];
}
return outvalueToVariantMatcher(Func(InnerArgsPtr));
}
@@ -1166,4 +1167,4 @@ std::unique_ptr<MatcherDescriptor> makeMatcherAutoMarshall(
} // namespace ast_matchers
} // namespace clang
-#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H
+#endif // LLVM_CLANG_LIB_ASTMATCHERS_DYNAMIC_MARSHALLERS_H
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index 4f3efdb0a663..47db6b51966a 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -404,7 +404,9 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(isComparisonOperator);
REGISTER_MATCHER(isConst);
REGISTER_MATCHER(isConstQualified);
+ REGISTER_MATCHER(isConsteval);
REGISTER_MATCHER(isConstexpr);
+ REGISTER_MATCHER(isConstinit);
REGISTER_MATCHER(isCopyAssignmentOperator);
REGISTER_MATCHER(isCopyConstructor);
REGISTER_MATCHER(isDefaultConstructor);
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index 9ef3b5b6277a..8246854dc1b5 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -531,9 +531,7 @@ class CFGBuilder {
public:
explicit CFGBuilder(ASTContext *astContext,
const CFG::BuildOptions &buildOpts)
- : Context(astContext), cfg(new CFG()), // crew a new CFG
- ConstructionContextMap(), BuildOpts(buildOpts) {}
-
+ : Context(astContext), cfg(new CFG()), BuildOpts(buildOpts) {}
// buildCFG - Used by external clients to construct the CFG.
std::unique_ptr<CFG> buildCFG(const Decl *D, Stmt *Statement);
@@ -3354,7 +3352,7 @@ CFGBlock *CFGBuilder::VisitGCCAsmStmt(GCCAsmStmt *G, AddStmtChoice asc) {
// Save "Succ" in BackpatchBlocks. In the backpatch processing, "Succ" is
// used to avoid adding "Succ" again.
BackpatchBlocks.push_back(JumpSource(Succ, ScopePos));
- return Block;
+ return VisitChildren(G);
}
CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
diff --git a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
new file mode 100644
index 000000000000..3ad2ed640cc1
--- /dev/null
+++ b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
@@ -0,0 +1,69 @@
+//===- ControlFlowContext.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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a ControlFlowContext class that is used by dataflow
+// analyses that run over Control-Flow Graphs (CFGs).
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Stmt.h"
+#include "clang/Analysis/CFG.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Support/Error.h"
+#include <utility>
+
+namespace clang {
+namespace dataflow {
+
+/// Returns a map from statements to basic blocks that contain them.
+static llvm::DenseMap<const Stmt *, const CFGBlock *>
+buildStmtToBasicBlockMap(const CFG &Cfg) {
+ llvm::DenseMap<const Stmt *, const CFGBlock *> StmtToBlock;
+ for (const CFGBlock *Block : Cfg) {
+ if (Block == nullptr)
+ continue;
+
+ for (const CFGElement &Element : *Block) {
+ auto Stmt = Element.getAs<CFGStmt>();
+ if (!Stmt.hasValue())
+ continue;
+
+ StmtToBlock[Stmt.getValue().getStmt()] = Block;
+ }
+ }
+ return StmtToBlock;
+}
+
+llvm::Expected<ControlFlowContext>
+ControlFlowContext::build(const Decl *D, Stmt *S, ASTContext *C) {
+ CFG::BuildOptions Options;
+ Options.PruneTriviallyFalseEdges = false;
+ Options.AddImplicitDtors = true;
+ Options.AddTemporaryDtors = true;
+ Options.AddInitializers = true;
+ Options.AddCXXDefaultInitExprInCtors = true;
+
+ // Ensure that all sub-expressions in basic blocks are evaluated.
+ Options.setAllAlwaysAdd();
+
+ auto Cfg = CFG::buildCFG(D, S, C, Options);
+ if (Cfg == nullptr)
+ return llvm::createStringError(
+ std::make_error_code(std::errc::invalid_argument),
+ "CFG::buildCFG failed");
+
+ llvm::DenseMap<const Stmt *, const CFGBlock *> StmtToBlock =
+ buildStmtToBasicBlockMap(*Cfg);
+ return ControlFlowContext(std::move(Cfg), std::move(StmtToBlock));
+}
+
+} // namespace dataflow
+} // namespace clang
diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
new file mode 100644
index 000000000000..938f7338b640
--- /dev/null
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -0,0 +1,318 @@
+//===-- DataflowEnvironment.cpp ---------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines an Environment class that is used by dataflow analyses
+// that run over Control-Flow Graphs (CFGs) to keep track of the state of the
+// program at given program points.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Type.h"
+#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
+#include "clang/Analysis/FlowSensitive/StorageLocation.h"
+#include "clang/Analysis/FlowSensitive/Value.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <memory>
+#include <utility>
+
+namespace clang {
+namespace dataflow {
+
+/// Returns a map consisting of key-value entries that are present in both maps.
+template <typename K, typename V>
+llvm::DenseMap<K, V> intersectDenseMaps(const llvm::DenseMap<K, V> &Map1,
+ const llvm::DenseMap<K, V> &Map2) {
+ llvm::DenseMap<K, V> Result;
+ for (auto &Entry : Map1) {
+ auto It = Map2.find(Entry.first);
+ if (It != Map2.end() && Entry.second == It->second)
+ Result.insert({Entry.first, Entry.second});
+ }
+ return Result;
+}
+
+Environment::Environment(DataflowAnalysisContext &DACtx,
+ const DeclContext &DeclCtx)
+ : Environment(DACtx) {
+ if (const auto *FuncDecl = dyn_cast<FunctionDecl>(&DeclCtx)) {
+ for (const auto *ParamDecl : FuncDecl->parameters()) {
+ assert(ParamDecl != nullptr);
+ auto &ParamLoc = createStorageLocation(*ParamDecl);
+ setStorageLocation(*ParamDecl, ParamLoc);
+ if (Value *ParamVal = createValue(ParamDecl->getType()))
+ setValue(ParamLoc, *ParamVal);
+ }
+ }
+
+ if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(&DeclCtx)) {
+ if (!MethodDecl->isStatic()) {
+ QualType ThisPointeeType = MethodDecl->getThisObjectType();
+ // FIXME: Add support for union types.
+ if (!ThisPointeeType->isUnionType()) {
+ auto &ThisPointeeLoc = createStorageLocation(ThisPointeeType);
+ DACtx.setThisPointeeStorageLocation(ThisPointeeLoc);
+ if (Value *ThisPointeeVal = createValue(ThisPointeeType))
+ setValue(ThisPointeeLoc, *ThisPointeeVal);
+ }
+ }
+ }
+}
+
+bool Environment::operator==(const Environment &Other) const {
+ assert(DACtx == Other.DACtx);
+ return DeclToLoc == Other.DeclToLoc && LocToVal == Other.LocToVal;
+}
+
+LatticeJoinEffect Environment::join(const Environment &Other,
+ Environment::Merger &Merger) {
+ assert(DACtx == Other.DACtx);
+
+ auto Effect = LatticeJoinEffect::Unchanged;
+
+ const unsigned DeclToLocSizeBefore = DeclToLoc.size();
+ DeclToLoc = intersectDenseMaps(DeclToLoc, Other.DeclToLoc);
+ if (DeclToLocSizeBefore != DeclToLoc.size())
+ Effect = LatticeJoinEffect::Changed;
+
+ const unsigned ExprToLocSizeBefore = ExprToLoc.size();
+ ExprToLoc = intersectDenseMaps(ExprToLoc, Other.ExprToLoc);
+ if (ExprToLocSizeBefore != ExprToLoc.size())
+ Effect = LatticeJoinEffect::Changed;
+
+ llvm::DenseMap<const StorageLocation *, Value *> MergedLocToVal;
+ for (auto &Entry : LocToVal) {
+ const StorageLocation *Loc = Entry.first;
+ assert(Loc != nullptr);
+
+ Value *Val = Entry.second;
+ assert(Val != nullptr);
+
+ auto It = Other.LocToVal.find(Loc);
+ if (It == Other.LocToVal.end())
+ continue;
+ assert(It->second != nullptr);
+
+ if (It->second == Val) {
+ MergedLocToVal.insert({Loc, Val});
+ continue;
+ }
+
+ // FIXME: Consider destroying `MergedValue` immediately if `Merger::merge`
+ // returns false to avoid storing unneeded values in `DACtx`.
+ if (Value *MergedVal = createValue(Loc->getType()))
+ if (Merger.merge(Loc->getType(), *Val, *It->second, *MergedVal, *this))
+ MergedLocToVal.insert({Loc, MergedVal});
+ }
+ const unsigned LocToValSizeBefore = LocToVal.size();
+ LocToVal = std::move(MergedLocToVal);
+ if (LocToValSizeBefore != LocToVal.size())
+ Effect = LatticeJoinEffect::Changed;
+
+ return Effect;
+}
+
+StorageLocation &Environment::createStorageLocation(QualType Type) {
+ assert(!Type.isNull());
+ if (Type->isStructureOrClassType() || Type->isUnionType()) {
+ // FIXME: Explore options to avoid eager initialization of fields as some of
+ // them might not be needed for a particular analysis.
+ llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
+ for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
+ FieldLocs.insert({Field, &createStorageLocation(Field->getType())});
+ }
+ return takeOwnership(
+ std::make_unique<AggregateStorageLocation>(Type, std::move(FieldLocs)));
+ }
+ return takeOwnership(std::make_unique<ScalarStorageLocation>(Type));
+}
+
+StorageLocation &Environment::createStorageLocation(const VarDecl &D) {
+ // Evaluated declarations are always assigned the same storage locations to
+ // ensure that the environment stabilizes across loop iterations. Storage
+ // locations for evaluated declarations are stored in the analysis context.
+ if (auto *Loc = DACtx->getStorageLocation(D))
+ return *Loc;
+ auto &Loc = createStorageLocation(D.getType());
+ DACtx->setStorageLocation(D, Loc);
+ return Loc;
+}
+
+StorageLocation &Environment::createStorageLocation(const Expr &E) {
+ // Evaluated expressions are always assigned the same storage locations to
+ // ensure that the environment stabilizes across loop iterations. Storage
+ // locations for evaluated expressions are stored in the analysis context.
+ if (auto *Loc = DACtx->getStorageLocation(E))
+ return *Loc;
+ auto &Loc = createStorageLocation(E.getType());
+ DACtx->setStorageLocation(E, Loc);
+ return Loc;
+}
+
+void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) {
+ assert(DeclToLoc.find(&D) == DeclToLoc.end());
+ DeclToLoc[&D] = &Loc;
+}
+
+StorageLocation *Environment::getStorageLocation(const ValueDecl &D,
+ SkipPast SP) const {
+ auto It = DeclToLoc.find(&D);
+ return It == DeclToLoc.end() ? nullptr : &skip(*It->second, SP);
+}
+
+void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) {
+ assert(ExprToLoc.find(&E) == ExprToLoc.end());
+ ExprToLoc[&E] = &Loc;
+}
+
+StorageLocation *Environment::getStorageLocation(const Expr &E,
+ SkipPast SP) const {
+ auto It = ExprToLoc.find(&E);
+ return It == ExprToLoc.end() ? nullptr : &skip(*It->second, SP);
+}
+
+StorageLocation *Environment::getThisPointeeStorageLocation() const {
+ return DACtx->getThisPointeeStorageLocation();
+}
+
+void Environment::setValue(const StorageLocation &Loc, Value &Val) {
+ LocToVal[&Loc] = &Val;
+
+ if (auto *StructVal = dyn_cast<StructValue>(&Val)) {
+ auto &AggregateLoc = *cast<AggregateStorageLocation>(&Loc);
+
+ const QualType Type = AggregateLoc.getType();
+ assert(Type->isStructureOrClassType());
+
+ for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
+ assert(Field != nullptr);
+ setValue(AggregateLoc.getChild(*Field), StructVal->getChild(*Field));
+ }
+ }
+}
+
+Value *Environment::getValue(const StorageLocation &Loc) const {
+ auto It = LocToVal.find(&Loc);
+ return It == LocToVal.end() ? nullptr : It->second;
+}
+
+Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const {
+ auto *Loc = getStorageLocation(D, SP);
+ if (Loc == nullptr)
+ return nullptr;
+ return getValue(*Loc);
+}
+
+Value *Environment::getValue(const Expr &E, SkipPast SP) const {
+ auto *Loc = getStorageLocation(E, SP);
+ if (Loc == nullptr)
+ return nullptr;
+ return getValue(*Loc);
+}
+
+Value *Environment::createValue(QualType Type) {
+ llvm::DenseSet<QualType> Visited;
+ return createValueUnlessSelfReferential(Type, Visited);
+}
+
+Value *Environment::createValueUnlessSelfReferential(
+ QualType Type, llvm::DenseSet<QualType> &Visited) {
+ assert(!Type.isNull());
+
+ if (Type->isIntegerType()) {
+ return &takeOwnership(std::make_unique<IntegerValue>());
+ }
+
+ if (Type->isReferenceType()) {
+ QualType PointeeType = Type->getAs<ReferenceType>()->getPointeeType();
+ auto &PointeeLoc = createStorageLocation(PointeeType);
+
+ if (!Visited.contains(PointeeType.getCanonicalType())) {
+ Visited.insert(PointeeType.getCanonicalType());
+ Value *PointeeVal =
+ createValueUnlessSelfReferential(PointeeType, Visited);
+ Visited.erase(PointeeType.getCanonicalType());
+
+ if (PointeeVal != nullptr)
+ setValue(PointeeLoc, *PointeeVal);
+ }
+
+ return &takeOwnership(std::make_unique<ReferenceValue>(PointeeLoc));
+ }
+
+ if (Type->isPointerType()) {
+ QualType PointeeType = Type->getAs<PointerType>()->getPointeeType();
+ auto &PointeeLoc = createStorageLocation(PointeeType);
+
+ if (!Visited.contains(PointeeType.getCanonicalType())) {
+ Visited.insert(PointeeType.getCanonicalType());
+ Value *PointeeVal =
+ createValueUnlessSelfReferential(PointeeType, Visited);
+ Visited.erase(PointeeType.getCanonicalType());
+
+ if (PointeeVal != nullptr)
+ setValue(PointeeLoc, *PointeeVal);
+ }
+
+ return &takeOwnership(std::make_unique<PointerValue>(PointeeLoc));
+ }
+
+ if (Type->isStructureOrClassType()) {
+ // FIXME: Initialize only fields that are accessed in the context that is
+ // being analyzed.
+ llvm::DenseMap<const ValueDecl *, Value *> FieldValues;
+ for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
+ assert(Field != nullptr);
+
+ QualType FieldType = Field->getType();
+ if (Visited.contains(FieldType.getCanonicalType()))
+ continue;
+
+ Visited.insert(FieldType.getCanonicalType());
+ FieldValues.insert(
+ {Field, createValueUnlessSelfReferential(FieldType, Visited)});
+ Visited.erase(FieldType.getCanonicalType());
+ }
+
+ return &takeOwnership(
+ std::make_unique<StructValue>(std::move(FieldValues)));
+ }
+
+ return nullptr;
+}
+
+StorageLocation &Environment::skip(StorageLocation &Loc, SkipPast SP) const {
+ switch (SP) {
+ case SkipPast::None:
+ return Loc;
+ case SkipPast::Reference:
+ // References cannot be chained so we only need to skip past one level of
+ // indirection.
+ if (auto *Val = dyn_cast_or_null<ReferenceValue>(getValue(Loc)))
+ return Val->getPointeeLoc();
+ return Loc;
+ case SkipPast::ReferenceThenPointer:
+ StorageLocation &LocPastRef = skip(Loc, SkipPast::Reference);
+ if (auto *Val = dyn_cast_or_null<PointerValue>(getValue(LocPastRef)))
+ return Val->getPointeeLoc();
+ return LocPastRef;
+ }
+ llvm_unreachable("bad SkipPast kind");
+}
+
+const StorageLocation &Environment::skip(const StorageLocation &Loc,
+ SkipPast SP) const {
+ return skip(*const_cast<StorageLocation *>(&Loc), SP);
+}
+
+} // namespace dataflow
+} // namespace clang
diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
new file mode 100644
index 000000000000..51a86b727e33
--- /dev/null
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -0,0 +1,462 @@
+//===-- Transfer.cpp --------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines transfer functions that evaluate program statements and
+// update an environment accordingly.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/FlowSensitive/Transfer.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/OperationKinds.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
+#include "clang/Basic/OperatorKinds.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Casting.h"
+#include <cassert>
+#include <memory>
+#include <tuple>
+
+namespace clang {
+namespace dataflow {
+
+static const Expr *skipExprWithCleanups(const Expr *E) {
+ if (auto *C = dyn_cast_or_null<ExprWithCleanups>(E))
+ return C->getSubExpr();
+ return E;
+}
+
+class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
+public:
+ TransferVisitor(Environment &Env) : Env(Env) {}
+
+ void VisitBinaryOperator(const BinaryOperator *S) {
+ if (S->getOpcode() == BO_Assign) {
+ // The CFG does not contain `ParenExpr` as top-level statements in basic
+ // blocks, however sub-expressions can still be of that type.
+ assert(S->getLHS() != nullptr);
+ const Expr *LHS = S->getLHS()->IgnoreParens();
+
+ assert(LHS != nullptr);
+ auto *LHSLoc = Env.getStorageLocation(*LHS, SkipPast::Reference);
+ if (LHSLoc == nullptr)
+ return;
+
+ // The CFG does not contain `ParenExpr` as top-level statements in basic
+ // blocks, however sub-expressions can still be of that type.
+ assert(S->getRHS() != nullptr);
+ const Expr *RHS = S->getRHS()->IgnoreParens();
+
+ assert(RHS != nullptr);
+ Value *RHSVal = Env.getValue(*RHS, SkipPast::Reference);
+ if (RHSVal == nullptr)
+ return;
+
+ // Assign a value to the storage location of the left-hand side.
+ Env.setValue(*LHSLoc, *RHSVal);
+
+ // Assign a storage location for the whole expression.
+ Env.setStorageLocation(*S, *LHSLoc);
+ }
+ // FIXME: Add support for BO_EQ, BO_NE.
+ }
+
+ void VisitDeclRefExpr(const DeclRefExpr *S) {
+ assert(S->getDecl() != nullptr);
+ auto *DeclLoc = Env.getStorageLocation(*S->getDecl(), SkipPast::None);
+ if (DeclLoc == nullptr)
+ return;
+
+ if (S->getDecl()->getType()->isReferenceType()) {
+ Env.setStorageLocation(*S, *DeclLoc);
+ } else {
+ auto &Loc = Env.createStorageLocation(*S);
+ auto &Val = Env.takeOwnership(std::make_unique<ReferenceValue>(*DeclLoc));
+ Env.setStorageLocation(*S, Loc);
+ Env.setValue(Loc, Val);
+ }
+ }
+
+ void VisitDeclStmt(const DeclStmt *S) {
+ // Group decls are converted into single decls in the CFG so the cast below
+ // is safe.
+ const auto &D = *cast<VarDecl>(S->getSingleDecl());
+ auto &Loc = Env.createStorageLocation(D);
+ Env.setStorageLocation(D, Loc);
+
+ const Expr *InitExpr = D.getInit();
+ if (InitExpr == nullptr) {
+ // No initializer expression - associate `Loc` with a new value.
+ if (Value *Val = Env.createValue(D.getType()))
+ Env.setValue(Loc, *Val);
+ return;
+ }
+
+ // The CFG does not contain `ParenExpr` as top-level statements in basic
+ // blocks, however sub-expressions can still be of that type.
+ InitExpr = skipExprWithCleanups(D.getInit()->IgnoreParens());
+ assert(InitExpr != nullptr);
+
+ if (D.getType()->isReferenceType()) {
+ // Initializing a reference variable - do not create a reference to
+ // reference.
+ if (auto *InitExprLoc =
+ Env.getStorageLocation(*InitExpr, SkipPast::Reference)) {
+ auto &Val =
+ Env.takeOwnership(std::make_unique<ReferenceValue>(*InitExprLoc));
+ Env.setValue(Loc, Val);
+ } else {
+ // FIXME: The initializer expression must always be assigned a value.
+ // Replace this with an assert when we have sufficient coverage of
+ // language features.
+ if (Value *Val = Env.createValue(D.getType()))
+ Env.setValue(Loc, *Val);
+ }
+ return;
+ }
+
+ if (auto *InitExprVal = Env.getValue(*InitExpr, SkipPast::None)) {
+ Env.setValue(Loc, *InitExprVal);
+ } else if (!D.getType()->isStructureOrClassType()) {
+ // FIXME: The initializer expression must always be assigned a value.
+ // Replace this with an assert when we have sufficient coverage of
+ // language features.
+ if (Value *Val = Env.createValue(D.getType()))
+ Env.setValue(Loc, *Val);
+ } else {
+ llvm_unreachable("structs and classes must always be assigned values");
+ }
+ }
+
+ void VisitImplicitCastExpr(const ImplicitCastExpr *S) {
+ // The CFG does not contain `ParenExpr` as top-level statements in basic
+ // blocks, however sub-expressions can still be of that type.
+ assert(S->getSubExpr() != nullptr);
+ const Expr *SubExpr = S->getSubExpr()->IgnoreParens();
+ assert(SubExpr != nullptr);
+
+ switch (S->getCastKind()) {
+ case CK_LValueToRValue: {
+ auto *SubExprVal = Env.getValue(*SubExpr, SkipPast::Reference);
+ if (SubExprVal == nullptr)
+ break;
+
+ auto &ExprLoc = Env.createStorageLocation(*S);
+ Env.setStorageLocation(*S, ExprLoc);
+ Env.setValue(ExprLoc, *SubExprVal);
+ break;
+ }
+ case CK_NoOp: {
+ // FIXME: Consider making `Environment::getStorageLocation` skip noop
+ // expressions (this and other similar expressions in the file) instead of
+ // assigning them storage locations.
+ auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
+ if (SubExprLoc == nullptr)
+ break;
+
+ Env.setStorageLocation(*S, *SubExprLoc);
+ break;
+ }
+ default:
+ // FIXME: Add support for CK_UserDefinedConversion,
+ // CK_ConstructorConversion, CK_UncheckedDerivedToBase.
+ break;
+ }
+ }
+
+ void VisitUnaryOperator(const UnaryOperator *S) {
+ // The CFG does not contain `ParenExpr` as top-level statements in basic
+ // blocks, however sub-expressions can still be of that type.
+ assert(S->getSubExpr() != nullptr);
+ const Expr *SubExpr = S->getSubExpr()->IgnoreParens();
+ assert(SubExpr != nullptr);
+
+ switch (S->getOpcode()) {
+ case UO_Deref: {
+ // Skip past a reference to handle dereference of a dependent pointer.
+ const auto *SubExprVal = cast_or_null<PointerValue>(
+ Env.getValue(*SubExpr, SkipPast::Reference));
+ if (SubExprVal == nullptr)
+ break;
+
+ auto &Loc = Env.createStorageLocation(*S);
+ Env.setStorageLocation(*S, Loc);
+ Env.setValue(Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(
+ SubExprVal->getPointeeLoc())));
+ break;
+ }
+ case UO_AddrOf: {
+ // Do not form a pointer to a reference. If `SubExpr` is assigned a
+ // `ReferenceValue` then form a value that points to the location of its
+ // pointee.
+ StorageLocation *PointeeLoc =
+ Env.getStorageLocation(*SubExpr, SkipPast::Reference);
+ if (PointeeLoc == nullptr)
+ break;
+
+ auto &PointerLoc = Env.createStorageLocation(*S);
+ auto &PointerVal =
+ Env.takeOwnership(std::make_unique<PointerValue>(*PointeeLoc));
+ Env.setStorageLocation(*S, PointerLoc);
+ Env.setValue(PointerLoc, PointerVal);
+ break;
+ }
+ default:
+ // FIXME: Add support for UO_LNot.
+ break;
+ }
+ }
+
+ void VisitCXXThisExpr(const CXXThisExpr *S) {
+ auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation();
+ assert(ThisPointeeLoc != nullptr);
+
+ auto &Loc = Env.createStorageLocation(*S);
+ Env.setStorageLocation(*S, Loc);
+ Env.setValue(Loc, Env.takeOwnership(
+ std::make_unique<PointerValue>(*ThisPointeeLoc)));
+ }
+
+ void VisitMemberExpr(const MemberExpr *S) {
+ ValueDecl *Member = S->getMemberDecl();
+ assert(Member != nullptr);
+
+ // FIXME: Consider assigning pointer values to function member expressions.
+ if (Member->isFunctionOrFunctionTemplate())
+ return;
+
+ // The receiver can be either a value or a pointer to a value. Skip past the
+ // indirection to handle both cases.
+ auto *BaseLoc = cast_or_null<AggregateStorageLocation>(
+ Env.getStorageLocation(*S->getBase(), SkipPast::ReferenceThenPointer));
+ if (BaseLoc == nullptr)
+ return;
+
+ // FIXME: Add support for union types.
+ if (BaseLoc->getType()->isUnionType())
+ return;
+
+ auto &MemberLoc = BaseLoc->getChild(*Member);
+ if (MemberLoc.getType()->isReferenceType()) {
+ Env.setStorageLocation(*S, MemberLoc);
+ } else {
+ auto &Loc = Env.createStorageLocation(*S);
+ Env.setStorageLocation(*S, Loc);
+ Env.setValue(
+ Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(MemberLoc)));
+ }
+ }
+
+ void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) {
+ const Expr *InitExpr = S->getExpr();
+ assert(InitExpr != nullptr);
+
+ Value *InitExprVal = Env.getValue(*InitExpr, SkipPast::None);
+ if (InitExprVal == nullptr)
+ return;
+
+ const FieldDecl *Field = S->getField();
+ assert(Field != nullptr);
+
+ auto &ThisLoc =
+ *cast<AggregateStorageLocation>(Env.getThisPointeeStorageLocation());
+ auto &FieldLoc = ThisLoc.getChild(*Field);
+ Env.setValue(FieldLoc, *InitExprVal);
+ }
+
+ void VisitCXXConstructExpr(const CXXConstructExpr *S) {
+ const CXXConstructorDecl *ConstructorDecl = S->getConstructor();
+ assert(ConstructorDecl != nullptr);
+
+ if (ConstructorDecl->isCopyOrMoveConstructor()) {
+ assert(S->getNumArgs() == 1);
+
+ const Expr *Arg = S->getArg(0);
+ assert(Arg != nullptr);
+
+ if (S->isElidable()) {
+ auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::Reference);
+ if (ArgLoc == nullptr)
+ return;
+
+ Env.setStorageLocation(*S, *ArgLoc);
+ } else if (auto *ArgVal = Env.getValue(*Arg, SkipPast::Reference)) {
+ auto &Loc = Env.createStorageLocation(*S);
+ Env.setStorageLocation(*S, Loc);
+ Env.setValue(Loc, *ArgVal);
+ }
+ return;
+ }
+
+ auto &Loc = Env.createStorageLocation(*S);
+ Env.setStorageLocation(*S, Loc);
+ if (Value *Val = Env.createValue(S->getType()))
+ Env.setValue(Loc, *Val);
+ }
+
+ void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
+ if (S->getOperator() == OO_Equal) {
+ assert(S->getNumArgs() == 2);
+
+ const Expr *Arg0 = S->getArg(0);
+ assert(Arg0 != nullptr);
+
+ const Expr *Arg1 = S->getArg(1);
+ assert(Arg1 != nullptr);
+
+ // Evaluate only copy and move assignment operators.
+ auto *Arg0Type = Arg0->getType()->getUnqualifiedDesugaredType();
+ auto *Arg1Type = Arg1->getType()->getUnqualifiedDesugaredType();
+ if (Arg0Type != Arg1Type)
+ return;
+
+ auto *ObjectLoc = Env.getStorageLocation(*Arg0, SkipPast::Reference);
+ if (ObjectLoc == nullptr)
+ return;
+
+ auto *Val = Env.getValue(*Arg1, SkipPast::Reference);
+ if (Val == nullptr)
+ return;
+
+ Env.setValue(*ObjectLoc, *Val);
+ }
+ }
+
+ void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) {
+ if (S->getCastKind() == CK_ConstructorConversion) {
+ // The CFG does not contain `ParenExpr` as top-level statements in basic
+ // blocks, however sub-expressions can still be of that type.
+ assert(S->getSubExpr() != nullptr);
+ const Expr *SubExpr = S->getSubExpr();
+ assert(SubExpr != nullptr);
+
+ auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
+ if (SubExprLoc == nullptr)
+ return;
+
+ Env.setStorageLocation(*S, *SubExprLoc);
+ }
+ }
+
+ void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) {
+ auto &Loc = Env.createStorageLocation(*S);
+ Env.setStorageLocation(*S, Loc);
+ if (Value *Val = Env.createValue(S->getType()))
+ Env.setValue(Loc, *Val);
+ }
+
+ void VisitCallExpr(const CallExpr *S) {
+ if (S->isCallToStdMove()) {
+ assert(S->getNumArgs() == 1);
+
+ const Expr *Arg = S->getArg(0);
+ assert(Arg != nullptr);
+
+ auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::None);
+ if (ArgLoc == nullptr)
+ return;
+
+ Env.setStorageLocation(*S, *ArgLoc);
+ }
+ }
+
+ void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) {
+ const Expr *SubExpr = S->getSubExpr();
+ assert(SubExpr != nullptr);
+
+ auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
+ if (SubExprLoc == nullptr)
+ return;
+
+ Env.setStorageLocation(*S, *SubExprLoc);
+ }
+
+ void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) {
+ const Expr *SubExpr = S->getSubExpr();
+ assert(SubExpr != nullptr);
+
+ auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
+ if (SubExprLoc == nullptr)
+ return;
+
+ Env.setStorageLocation(*S, *SubExprLoc);
+ }
+
+ void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) {
+ if (S->getCastKind() == CK_NoOp) {
+ const Expr *SubExpr = S->getSubExpr();
+ assert(SubExpr != nullptr);
+
+ auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
+ if (SubExprLoc == nullptr)
+ return;
+
+ Env.setStorageLocation(*S, *SubExprLoc);
+ }
+ }
+
+ void VisitConditionalOperator(const ConditionalOperator *S) {
+ // FIXME: Revisit this once flow conditions are added to the framework. For
+ // `a = b ? c : d` we can add `b => a == c && !b => a == d` to the flow
+ // condition.
+ auto &Loc = Env.createStorageLocation(*S);
+ Env.setStorageLocation(*S, Loc);
+ if (Value *Val = Env.createValue(S->getType()))
+ Env.setValue(Loc, *Val);
+ }
+
+ void VisitInitListExpr(const InitListExpr *S) {
+ QualType Type = S->getType();
+
+ auto &Loc = Env.createStorageLocation(*S);
+ Env.setStorageLocation(*S, Loc);
+
+ auto *Val = Env.createValue(Type);
+ if (Val == nullptr)
+ return;
+
+ Env.setValue(Loc, *Val);
+
+ if (Type->isStructureOrClassType()) {
+ for (auto IT : llvm::zip(Type->getAsRecordDecl()->fields(), S->inits())) {
+ const FieldDecl *Field = std::get<0>(IT);
+ assert(Field != nullptr);
+
+ const Expr *Init = std::get<1>(IT);
+ assert(Init != nullptr);
+
+ if (Value *InitVal = Env.getValue(*Init, SkipPast::None))
+ cast<StructValue>(Val)->setChild(*Field, *InitVal);
+ }
+ }
+ // FIXME: Implement array initialization.
+ }
+
+ void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) {
+ auto &Loc = Env.createStorageLocation(*S);
+ Env.setStorageLocation(*S, Loc);
+ Env.setValue(Loc, Env.getBoolLiteralValue(S->getValue()));
+ }
+
+private:
+ Environment &Env;
+};
+
+void transfer(const Stmt &S, Environment &Env) {
+ assert(!isa<ParenExpr>(&S));
+ TransferVisitor(Env).Visit(&S);
+}
+
+} // namespace dataflow
+} // namespace clang
diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
index 413e8d14bf0a..aaf6a834f5b3 100644
--- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
+++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
@@ -11,14 +11,19 @@
//
//===----------------------------------------------------------------------===//
+#include <memory>
#include <utility>
#include <vector>
+#include "clang/AST/DeclCXX.h"
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
#include "clang/Analysis/FlowSensitive/DataflowWorklist.h"
+#include "clang/Analysis/FlowSensitive/Transfer.h"
#include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h"
+#include "clang/Analysis/FlowSensitive/Value.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/Optional.h"
#include "llvm/Support/raw_ostream.h"
@@ -35,15 +40,44 @@ namespace dataflow {
/// already been transferred. States in `BlockStates` that are set to
/// `llvm::None` represent basic blocks that are not evaluated yet.
static TypeErasedDataflowAnalysisState computeBlockInputState(
+ const ControlFlowContext &CFCtx,
std::vector<llvm::Optional<TypeErasedDataflowAnalysisState>> &BlockStates,
const CFGBlock &Block, const Environment &InitEnv,
TypeErasedDataflowAnalysis &Analysis) {
- // FIXME: Consider passing `Block` to `Analysis.typeErasedInitialElement()`
- // to enable building analyses like computation of dominators that initialize
- // the state of each basic block differently.
- TypeErasedDataflowAnalysisState State = {Analysis.typeErasedInitialElement(),
- InitEnv};
- for (const CFGBlock *Pred : Block.preds()) {
+ llvm::DenseSet<const CFGBlock *> Preds;
+ Preds.insert(Block.pred_begin(), Block.pred_end());
+ if (Block.getTerminator().isTemporaryDtorsBranch()) {
+ // This handles a special case where the code that produced the CFG includes
+ // a conditional operator with a branch that constructs a temporary and
+ // calls a destructor annotated as noreturn. The CFG models this as follows:
+ //
+ // B1 (contains the condition of the conditional operator) - succs: B2, B3
+ // B2 (contains code that does not call a noreturn destructor) - succs: B4
+ // B3 (contains code that calls a noreturn destructor) - succs: B4
+ // B4 (has temporary destructor terminator) - succs: B5, B6
+ // B5 (noreturn block that is associated with the noreturn destructor call)
+ // B6 (contains code that follows the conditional operator statement)
+ //
+ // The first successor (B5 above) of a basic block with a temporary
+ // destructor terminator (B4 above) is the block that evaluates the
+ // destructor. If that block has a noreturn element then the predecessor
+ // block that constructed the temporary object (B3 above) is effectively a
+ // noreturn block and its state should not be used as input for the state
+ // of the block that has a temporary destructor terminator (B4 above). This
+ // holds regardless of which branch of the ternary operator calls the
+ // noreturn destructor. However, it doesn't cases where a nested ternary
+ // operator includes a branch that contains a noreturn destructor call.
+ //
+ // See `NoreturnDestructorTest` for concrete examples.
+ if (Block.succ_begin()->getReachableBlock()->hasNoReturnElement()) {
+ auto StmtBlock = CFCtx.getStmtToBlock().find(Block.getTerminatorStmt());
+ assert(StmtBlock != CFCtx.getStmtToBlock().end());
+ Preds.erase(StmtBlock->getSecond());
+ }
+ }
+
+ llvm::Optional<TypeErasedDataflowAnalysisState> MaybeState;
+ for (const CFGBlock *Pred : Preds) {
// Skip if the `Block` is unreachable or control flow cannot get past it.
if (!Pred || Pred->hasNoReturnElement())
continue;
@@ -57,13 +91,79 @@ static TypeErasedDataflowAnalysisState computeBlockInputState(
const TypeErasedDataflowAnalysisState &PredState =
MaybePredState.getValue();
- Analysis.joinTypeErased(State.Lattice, PredState.Lattice);
- State.Env.join(PredState.Env);
+ if (MaybeState.hasValue()) {
+ Analysis.joinTypeErased(MaybeState->Lattice, PredState.Lattice);
+ MaybeState->Env.join(PredState.Env, Analysis);
+ } else {
+ MaybeState = PredState;
+ }
+ }
+ if (!MaybeState.hasValue()) {
+ // FIXME: Consider passing `Block` to `Analysis.typeErasedInitialElement()`
+ // to enable building analyses like computation of dominators that
+ // initialize the state of each basic block differently.
+ MaybeState.emplace(Analysis.typeErasedInitialElement(), InitEnv);
+ }
+ return *MaybeState;
+}
+
+/// Transfers `State` by evaluating `CfgStmt` in the context of `Analysis`.
+/// `HandleTransferredStmt` (if provided) will be applied to `CfgStmt`, after it
+/// is evaluated.
+static void
+transferCFGStmt(const CFGStmt &CfgStmt, TypeErasedDataflowAnalysis &Analysis,
+ TypeErasedDataflowAnalysisState &State,
+ std::function<void(const CFGStmt &,
+ const TypeErasedDataflowAnalysisState &)>
+ HandleTransferredStmt) {
+ const Stmt *S = CfgStmt.getStmt();
+ assert(S != nullptr);
+
+ if (Analysis.applyBuiltinTransfer())
+ transfer(*S, State.Env);
+ Analysis.transferTypeErased(S, State.Lattice, State.Env);
+
+ if (HandleTransferredStmt != nullptr)
+ HandleTransferredStmt(CfgStmt, State);
+}
+
+/// Transfers `State` by evaluating `CfgInit`.
+static void transferCFGInitializer(const CFGInitializer &CfgInit,
+ TypeErasedDataflowAnalysisState &State) {
+ const auto &ThisLoc = *cast<AggregateStorageLocation>(
+ State.Env.getThisPointeeStorageLocation());
+
+ const CXXCtorInitializer *Initializer = CfgInit.getInitializer();
+ assert(Initializer != nullptr);
+
+ auto *InitStmt = Initializer->getInit();
+ assert(InitStmt != nullptr);
+
+ auto *InitStmtLoc =
+ State.Env.getStorageLocation(*InitStmt, SkipPast::Reference);
+ if (InitStmtLoc == nullptr)
+ return;
+
+ auto *InitStmtVal = State.Env.getValue(*InitStmtLoc);
+ if (InitStmtVal == nullptr)
+ return;
+
+ const FieldDecl *Member = Initializer->getMember();
+ assert(Member != nullptr);
+
+ if (Member->getType()->isReferenceType()) {
+ auto &MemberLoc = ThisLoc.getChild(*Member);
+ State.Env.setValue(MemberLoc,
+ State.Env.takeOwnership(
+ std::make_unique<ReferenceValue>(*InitStmtLoc)));
+ } else {
+ auto &MemberLoc = ThisLoc.getChild(*Member);
+ State.Env.setValue(MemberLoc, *InitStmtVal);
}
- return State;
}
TypeErasedDataflowAnalysisState transferBlock(
+ const ControlFlowContext &CFCtx,
std::vector<llvm::Optional<TypeErasedDataflowAnalysisState>> &BlockStates,
const CFGBlock &Block, const Environment &InitEnv,
TypeErasedDataflowAnalysis &Analysis,
@@ -71,39 +171,37 @@ TypeErasedDataflowAnalysisState transferBlock(
const TypeErasedDataflowAnalysisState &)>
HandleTransferredStmt) {
TypeErasedDataflowAnalysisState State =
- computeBlockInputState(BlockStates, Block, InitEnv, Analysis);
+ computeBlockInputState(CFCtx, BlockStates, Block, InitEnv, Analysis);
for (const CFGElement &Element : Block) {
- // FIXME: Evaluate other kinds of `CFGElement`.
- const llvm::Optional<CFGStmt> Stmt = Element.getAs<CFGStmt>();
- if (!Stmt.hasValue())
- continue;
-
- // FIXME: Evaluate the statement contained in `Stmt`.
-
- State.Lattice = Analysis.transferTypeErased(Stmt.getValue().getStmt(),
- State.Lattice, State.Env);
- if (HandleTransferredStmt != nullptr)
- HandleTransferredStmt(Stmt.getValue(), State);
+ switch (Element.getKind()) {
+ case CFGElement::Statement:
+ transferCFGStmt(*Element.getAs<CFGStmt>(), Analysis, State,
+ HandleTransferredStmt);
+ break;
+ case CFGElement::Initializer:
+ if (Analysis.applyBuiltinTransfer())
+ transferCFGInitializer(*Element.getAs<CFGInitializer>(), State);
+ break;
+ default:
+ // FIXME: Evaluate other kinds of `CFGElement`.
+ break;
+ }
}
return State;
}
std::vector<llvm::Optional<TypeErasedDataflowAnalysisState>>
-runTypeErasedDataflowAnalysis(const CFG &Cfg,
+runTypeErasedDataflowAnalysis(const ControlFlowContext &CFCtx,
TypeErasedDataflowAnalysis &Analysis,
const Environment &InitEnv) {
- // FIXME: Consider enforcing that `Cfg` meets the requirements that
- // are specified in the header. This could be done by remembering
- // what options were used to build `Cfg` and asserting on them here.
-
- PostOrderCFGView POV(&Cfg);
- ForwardDataflowWorklist Worklist(Cfg, &POV);
+ PostOrderCFGView POV(&CFCtx.getCFG());
+ ForwardDataflowWorklist Worklist(CFCtx.getCFG(), &POV);
std::vector<llvm::Optional<TypeErasedDataflowAnalysisState>> BlockStates;
- BlockStates.resize(Cfg.size(), llvm::None);
+ BlockStates.resize(CFCtx.getCFG().size(), llvm::None);
// The entry basic block doesn't contain statements so it can be skipped.
- const CFGBlock &Entry = Cfg.getEntry();
+ const CFGBlock &Entry = CFCtx.getCFG().getEntry();
BlockStates[Entry.getBlockID()] = {Analysis.typeErasedInitialElement(),
InitEnv};
Worklist.enqueueSuccessors(&Entry);
@@ -114,8 +212,8 @@ runTypeErasedDataflowAnalysis(const CFG &Cfg,
// FIXME: Consider making the maximum number of iterations configurable.
// FIXME: Set up statistics (see llvm/ADT/Statistic.h) to count average number
// of iterations, number of functions that time out, etc.
- unsigned Iterations = 0;
- static constexpr unsigned MaxIterations = 1 << 16;
+ uint32_t Iterations = 0;
+ static constexpr uint32_t MaxIterations = 1 << 16;
while (const CFGBlock *Block = Worklist.dequeue()) {
if (++Iterations > MaxIterations) {
llvm::errs() << "Maximum number of iterations reached, giving up.\n";
@@ -125,7 +223,7 @@ runTypeErasedDataflowAnalysis(const CFG &Cfg,
const llvm::Optional<TypeErasedDataflowAnalysisState> &OldBlockState =
BlockStates[Block->getBlockID()];
TypeErasedDataflowAnalysisState NewBlockState =
- transferBlock(BlockStates, *Block, InitEnv, Analysis);
+ transferBlock(CFCtx, BlockStates, *Block, InitEnv, Analysis);
if (OldBlockState.hasValue() &&
Analysis.isEqualTypeErased(OldBlockState.getValue().Lattice,
diff --git a/clang/lib/Analysis/UninitializedValues.cpp b/clang/lib/Analysis/UninitializedValues.cpp
index a38ae34f4b81..811146e50b45 100644
--- a/clang/lib/Analysis/UninitializedValues.cpp
+++ b/clang/lib/Analysis/UninitializedValues.cpp
@@ -819,12 +819,11 @@ void TransferFunctions::VisitGCCAsmStmt(GCCAsmStmt *as) {
while (const auto *UO = dyn_cast<UnaryOperator>(Ex))
Ex = stripCasts(C, UO->getSubExpr());
+ // Mark the variable as potentially uninitialized for those cases where
+ // it's used on an indirect path, where it's not guaranteed to be
+ // defined.
if (const VarDecl *VD = findVar(Ex).getDecl())
- if (vals[VD] != Initialized)
- // If the variable isn't initialized by the time we get here, then we
- // mark it as potentially uninitialized for those cases where it's used
- // on an indirect path, where it's not guaranteed to be defined.
- vals[VD] = MayUninitialized;
+ vals[VD] = MayUninitialized;
}
}
diff --git a/clang/lib/Basic/DarwinSDKInfo.cpp b/clang/lib/Basic/DarwinSDKInfo.cpp
index fe35f77782c9..64bcb45a4cd8 100644
--- a/clang/lib/Basic/DarwinSDKInfo.cpp
+++ b/clang/lib/Basic/DarwinSDKInfo.cpp
@@ -84,6 +84,25 @@ DarwinSDKInfo::parseDarwinSDKSettingsJSON(const llvm::json::Object *Obj) {
llvm::DenseMap<OSEnvPair::StorageType, Optional<RelatedTargetVersionMapping>>
VersionMappings;
if (const auto *VM = Obj->getObject("VersionMap")) {
+ // FIXME: Generalize this out beyond iOS-deriving targets.
+ // Look for ios_<targetos> version mapping for targets that derive from ios.
+ for (const auto &KV : *VM) {
+ auto Pair = StringRef(KV.getFirst()).split("_");
+ if (Pair.first.compare_insensitive("ios") == 0) {
+ llvm::Triple TT(llvm::Twine("--") + Pair.second.lower());
+ if (TT.getOS() != llvm::Triple::UnknownOS) {
+ auto Mapping = RelatedTargetVersionMapping::parseJSON(
+ *KV.getSecond().getAsObject(), *MaximumDeploymentVersion);
+ if (Mapping)
+ VersionMappings[OSEnvPair(llvm::Triple::IOS,
+ llvm::Triple::UnknownEnvironment,
+ TT.getOS(),
+ llvm::Triple::UnknownEnvironment)
+ .Value] = std::move(Mapping);
+ }
+ }
+ }
+
if (const auto *Mapping = VM->getObject("macOS_iOSMac")) {
auto VersionMap = RelatedTargetVersionMapping::parseJSON(
*Mapping, *MaximumDeploymentVersion);
diff --git a/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp
index 9b7ad96b949f..ac4b9d2cd5a2 100644
--- a/clang/lib/Basic/Diagnostic.cpp
+++ b/clang/lib/Basic/Diagnostic.cpp
@@ -374,6 +374,12 @@ void DiagnosticsEngine::setSeverity(diag::kind Diag, diag::Severity Map,
DiagnosticMapping Mapping = makeUserMapping(Map, L);
Mapping.setUpgradedFromWarning(WasUpgradedFromWarning);
+ // Make sure we propagate the NoWarningAsError flag from an existing
+ // mapping (which may be the default mapping).
+ DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
+ Mapping.setNoWarningAsError(Info.hasNoWarningAsError() ||
+ Mapping.hasNoWarningAsError());
+
// Common case; setting all the diagnostics of a group in one place.
if ((L.isInvalid() || L == DiagStatesByLoc.getCurDiagStateLoc()) &&
DiagStatesByLoc.getCurDiagState()) {
diff --git a/clang/lib/Basic/DiagnosticIDs.cpp b/clang/lib/Basic/DiagnosticIDs.cpp
index a9f2d09924cd..87db131992e4 100644
--- a/clang/lib/Basic/DiagnosticIDs.cpp
+++ b/clang/lib/Basic/DiagnosticIDs.cpp
@@ -33,7 +33,7 @@ struct StaticDiagInfoRec;
// platforms. See "How To Write Shared Libraries" by Ulrich Drepper.
struct StaticDiagInfoDescriptionStringTable {
#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
- SHOWINSYSHEADER, DEFERRABLE, CATEGORY) \
+ SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
char ENUM##_desc[sizeof(DESC)];
// clang-format off
#include "clang/Basic/DiagnosticCommonKinds.inc"
@@ -54,7 +54,7 @@ struct StaticDiagInfoDescriptionStringTable {
const StaticDiagInfoDescriptionStringTable StaticDiagInfoDescriptions = {
#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
- SHOWINSYSHEADER, DEFERRABLE, CATEGORY) \
+ SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
DESC,
// clang-format off
#include "clang/Basic/DiagnosticCommonKinds.inc"
@@ -79,7 +79,7 @@ extern const StaticDiagInfoRec StaticDiagInfo[];
// StaticDiagInfoRec would have extra padding on 64-bit platforms.
const uint32_t StaticDiagInfoDescriptionOffsets[] = {
#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
- SHOWINSYSHEADER, DEFERRABLE, CATEGORY) \
+ SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
offsetof(StaticDiagInfoDescriptionStringTable, ENUM##_desc),
// clang-format off
#include "clang/Basic/DiagnosticCommonKinds.inc"
@@ -115,6 +115,7 @@ struct StaticDiagInfoRec {
uint8_t Category : 6;
uint8_t WarnNoWerror : 1;
uint8_t WarnShowInSystemHeader : 1;
+ uint8_t WarnShowInSystemMacro : 1;
uint16_t OptionGroupIndex : 15;
uint16_t Deferrable : 1;
@@ -170,7 +171,7 @@ VALIDATE_DIAG_SIZE(REFACTORING)
const StaticDiagInfoRec StaticDiagInfo[] = {
// clang-format off
#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
- SHOWINSYSHEADER, DEFERRABLE, CATEGORY) \
+ SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
{ \
diag::ENUM, \
DEFAULT_SEVERITY, \
@@ -179,6 +180,7 @@ const StaticDiagInfoRec StaticDiagInfo[] = {
CATEGORY, \
NOWERROR, \
SHOWINSYSHEADER, \
+ SHOWINSYSMACRO, \
GROUP, \
DEFERRABLE, \
STR_SIZE(DESC, uint16_t)},
@@ -586,6 +588,13 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
Diag.getSourceManager().getExpansionLoc(Loc)))
return diag::Severity::Ignored;
+ // We also ignore warnings due to system macros
+ bool ShowInSystemMacro =
+ !GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemMacro;
+ if (State->SuppressSystemWarnings && !ShowInSystemMacro && Loc.isValid() &&
+ Diag.getSourceManager().isInSystemMacro(Loc))
+ return diag::Severity::Ignored;
+
return Result;
}
diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp
index d811aeec84a0..b86cb7af69bd 100644
--- a/clang/lib/Basic/IdentifierTable.cpp
+++ b/clang/lib/Basic/IdentifierTable.cpp
@@ -309,6 +309,14 @@ IdentifierInfo::isReserved(const LangOptions &LangOpts) const {
return ReservedIdentifierStatus::NotReserved;
}
+StringRef IdentifierInfo::deuglifiedName() const {
+ StringRef Name = getName();
+ if (Name.size() >= 2 && Name.front() == '_' &&
+ (Name[1] == '_' || (Name[1] >= 'A' && Name[1] <= 'Z')))
+ return Name.ltrim('_');
+ return Name;
+}
+
tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const {
// We use a perfect hash function here involving the length of the keyword,
// the first and third character. For preprocessor ID's there are no
diff --git a/clang/lib/Basic/OpenCLOptions.cpp b/clang/lib/Basic/OpenCLOptions.cpp
index b7408f39bdab..7e89b3f1b804 100644
--- a/clang/lib/Basic/OpenCLOptions.cpp
+++ b/clang/lib/Basic/OpenCLOptions.cpp
@@ -12,6 +12,17 @@
namespace clang {
+const OpenCLOptions::FeatureDepList OpenCLOptions::DependentFeaturesList = {
+ {"__opencl_c_read_write_images", "__opencl_c_images"},
+ {"__opencl_c_3d_image_writes", "__opencl_c_images"},
+ {"__opencl_c_pipes", "__opencl_c_generic_address_space"},
+ {"__opencl_c_device_enqueue", "__opencl_c_generic_address_space"},
+ {"__opencl_c_device_enqueue", "__opencl_c_program_scope_global_variables"}};
+
+const llvm::StringMap<llvm::StringRef> OpenCLOptions::FeatureExtensionMap = {
+ {"cl_khr_fp64", "__opencl_c_fp64"},
+ {"cl_khr_3d_image_writes", "__opencl_c_3d_image_writes"}};
+
bool OpenCLOptions::isKnown(llvm::StringRef Ext) const {
return OptMap.find(Ext) != OptMap.end();
}
@@ -108,33 +119,23 @@ void OpenCLOptions::disableAll() {
bool OpenCLOptions::diagnoseUnsupportedFeatureDependencies(
const TargetInfo &TI, DiagnosticsEngine &Diags) {
- // Feature pairs. First feature in a pair requires the second one to be
- // supported.
- static const llvm::StringMap<llvm::StringRef> DependentFeaturesMap = {
- {"__opencl_c_read_write_images", "__opencl_c_images"},
- {"__opencl_c_3d_image_writes", "__opencl_c_images"},
- {"__opencl_c_pipes", "__opencl_c_generic_address_space"}};
-
auto OpenCLFeaturesMap = TI.getSupportedOpenCLOpts();
bool IsValid = true;
- for (auto &FeaturePair : DependentFeaturesMap)
- if (TI.hasFeatureEnabled(OpenCLFeaturesMap, FeaturePair.getKey()) &&
- !TI.hasFeatureEnabled(OpenCLFeaturesMap, FeaturePair.getValue())) {
+ for (auto &FeaturePair : DependentFeaturesList) {
+ auto Feature = FeaturePair.first;
+ auto Dep = FeaturePair.second;
+ if (TI.hasFeatureEnabled(OpenCLFeaturesMap, Feature) &&
+ !TI.hasFeatureEnabled(OpenCLFeaturesMap, Dep)) {
IsValid = false;
- Diags.Report(diag::err_opencl_feature_requires)
- << FeaturePair.getKey() << FeaturePair.getValue();
+ Diags.Report(diag::err_opencl_feature_requires) << Feature << Dep;
}
+ }
return IsValid;
}
bool OpenCLOptions::diagnoseFeatureExtensionDifferences(
const TargetInfo &TI, DiagnosticsEngine &Diags) {
- // Extensions and equivalent feature pairs.
- static const llvm::StringMap<llvm::StringRef> FeatureExtensionMap = {
- {"cl_khr_fp64", "__opencl_c_fp64"},
- {"cl_khr_3d_image_writes", "__opencl_c_3d_image_writes"}};
-
auto OpenCLFeaturesMap = TI.getSupportedOpenCLOpts();
bool IsValid = true;
diff --git a/clang/lib/Basic/TargetID.cpp b/clang/lib/Basic/TargetID.cpp
index 59d416f0e015..3b8f4c13b9bf 100644
--- a/clang/lib/Basic/TargetID.cpp
+++ b/clang/lib/Basic/TargetID.cpp
@@ -15,7 +15,7 @@
namespace clang {
-static const llvm::SmallVector<llvm::StringRef, 4>
+static llvm::SmallVector<llvm::StringRef, 4>
getAllPossibleAMDGPUTargetIDFeatures(const llvm::Triple &T,
llvm::StringRef Proc) {
// Entries in returned vector should be in alphabetical order.
@@ -33,7 +33,7 @@ getAllPossibleAMDGPUTargetIDFeatures(const llvm::Triple &T,
return Ret;
}
-const llvm::SmallVector<llvm::StringRef, 4>
+llvm::SmallVector<llvm::StringRef, 4>
getAllPossibleTargetIDFeatures(const llvm::Triple &T,
llvm::StringRef Processor) {
llvm::SmallVector<llvm::StringRef, 4> Ret;
diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp
index 646bbe8b7387..e3a2f30febe7 100644
--- a/clang/lib/Basic/TargetInfo.cpp
+++ b/clang/lib/Basic/TargetInfo.cpp
@@ -25,7 +25,7 @@ using namespace clang;
static const LangASMap DefaultAddrSpaceMap = {0};
// TargetInfo Constructor.
-TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) {
+TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) {
// Set defaults. Defaults are set for a 32-bit RISC platform, like PPC or
// SPARC. These should be overridden by concrete targets as needed.
BigEndian = !T.isLittleEndian();
@@ -150,6 +150,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) {
PlatformMinVersion = VersionTuple();
MaxOpenCLWorkGroupSize = 1024;
+ ProgramAddrSpace = 0;
}
// Out of line virtual dtor for TargetInfo.
@@ -421,6 +422,8 @@ void TargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) {
OpenCLFeaturesMap, "__opencl_c_generic_address_space");
Opts.OpenCLPipes =
hasFeatureEnabled(OpenCLFeaturesMap, "__opencl_c_pipes");
+ Opts.Blocks =
+ hasFeatureEnabled(OpenCLFeaturesMap, "__opencl_c_device_enqueue");
}
}
diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index 4089a393b762..8e23cc4c421a 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -45,6 +45,7 @@ static StringRef getArchVersionString(llvm::AArch64::ArchKind Kind) {
case llvm::AArch64::ArchKind::ARMV9A:
case llvm::AArch64::ArchKind::ARMV9_1A:
case llvm::AArch64::ArchKind::ARMV9_2A:
+ case llvm::AArch64::ArchKind::ARMV9_3A:
return "9";
default:
return "8";
@@ -223,6 +224,12 @@ void AArch64TargetInfo::getTargetDefinesARMV87A(const LangOptions &Opts,
getTargetDefinesARMV86A(Opts, Builder);
}
+void AArch64TargetInfo::getTargetDefinesARMV88A(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ // Also include the Armv8.7 defines
+ getTargetDefinesARMV87A(Opts, Builder);
+}
+
void AArch64TargetInfo::getTargetDefinesARMV9A(const LangOptions &Opts,
MacroBuilder &Builder) const {
// Armv9-A maps to Armv8.5-A
@@ -241,6 +248,12 @@ void AArch64TargetInfo::getTargetDefinesARMV92A(const LangOptions &Opts,
getTargetDefinesARMV87A(Opts, Builder);
}
+void AArch64TargetInfo::getTargetDefinesARMV93A(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ // Armv9.3-A maps to Armv8.8-A
+ getTargetDefinesARMV88A(Opts, Builder);
+}
+
void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
// Target identification.
@@ -446,6 +459,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
case llvm::AArch64::ArchKind::ARMV8_7A:
getTargetDefinesARMV87A(Opts, Builder);
break;
+ case llvm::AArch64::ArchKind::ARMV8_8A:
+ getTargetDefinesARMV88A(Opts, Builder);
+ break;
case llvm::AArch64::ArchKind::ARMV9A:
getTargetDefinesARMV9A(Opts, Builder);
break;
@@ -455,6 +471,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
case llvm::AArch64::ArchKind::ARMV9_2A:
getTargetDefinesARMV92A(Opts, Builder);
break;
+ case llvm::AArch64::ArchKind::ARMV9_3A:
+ getTargetDefinesARMV93A(Opts, Builder);
+ break;
}
// All of the __sync_(bool|val)_compare_and_swap_(1|2|4|8) builtins work.
@@ -524,6 +543,8 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasMatmulFP64 = false;
HasMatmulFP32 = false;
HasLSE = false;
+ HasHBC = false;
+ HasMOPS = false;
ArchKind = llvm::AArch64::ArchKind::INVALID;
@@ -532,36 +553,36 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
FPU |= NeonMode;
if (Feature == "+sve") {
FPU |= SveMode;
- HasFullFP16 = 1;
+ HasFullFP16 = true;
}
if (Feature == "+sve2") {
FPU |= SveMode;
- HasFullFP16 = 1;
- HasSVE2 = 1;
+ HasFullFP16 = true;
+ HasSVE2 = true;
}
if (Feature == "+sve2-aes") {
FPU |= SveMode;
- HasFullFP16 = 1;
- HasSVE2 = 1;
- HasSVE2AES = 1;
+ HasFullFP16 = true;
+ HasSVE2 = true;
+ HasSVE2AES = true;
}
if (Feature == "+sve2-sha3") {
FPU |= SveMode;
- HasFullFP16 = 1;
- HasSVE2 = 1;
- HasSVE2SHA3 = 1;
+ HasFullFP16 = true;
+ HasSVE2 = true;
+ HasSVE2SHA3 = true;
}
if (Feature == "+sve2-sm4") {
FPU |= SveMode;
- HasFullFP16 = 1;
- HasSVE2 = 1;
- HasSVE2SM4 = 1;
+ HasFullFP16 = true;
+ HasSVE2 = true;
+ HasSVE2SM4 = true;
}
if (Feature == "+sve2-bitperm") {
FPU |= SveMode;
- HasFullFP16 = 1;
- HasSVE2 = 1;
- HasSVE2BitPerm = 1;
+ HasFullFP16 = true;
+ HasSVE2 = true;
+ HasSVE2BitPerm = true;
}
if (Feature == "+f32mm") {
FPU |= SveMode;
@@ -603,12 +624,16 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
ArchKind = llvm::AArch64::ArchKind::ARMV8_6A;
if (Feature == "+v8.7a")
ArchKind = llvm::AArch64::ArchKind::ARMV8_7A;
+ if (Feature == "+v8.8a")
+ ArchKind = llvm::AArch64::ArchKind::ARMV8_8A;
if (Feature == "+v9a")
ArchKind = llvm::AArch64::ArchKind::ARMV9A;
if (Feature == "+v9.1a")
ArchKind = llvm::AArch64::ArchKind::ARMV9_1A;
if (Feature == "+v9.2a")
ArchKind = llvm::AArch64::ArchKind::ARMV9_2A;
+ if (Feature == "+v9.3a")
+ ArchKind = llvm::AArch64::ArchKind::ARMV9_3A;
if (Feature == "+v8r")
ArchKind = llvm::AArch64::ArchKind::ARMV8R;
if (Feature == "+fullfp16")
@@ -635,6 +660,8 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasRandGen = true;
if (Feature == "+flagm")
HasFlagM = true;
+ if (Feature == "+hbc")
+ HasHBC = true;
}
setDataLayout();
diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h
index 74745df3be8d..ebddce0c1c73 100644
--- a/clang/lib/Basic/Targets/AArch64.h
+++ b/clang/lib/Basic/Targets/AArch64.h
@@ -15,6 +15,7 @@
#include "OSTargets.h"
#include "clang/Basic/TargetBuiltins.h"
+#include "llvm/Support/AArch64TargetParser.h"
#include "llvm/Support/TargetParser.h"
namespace clang {
@@ -53,6 +54,8 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
bool HasMatmulFP32;
bool HasLSE;
bool HasFlagM;
+ bool HasHBC;
+ bool HasMOPS;
llvm::AArch64::ArchKind ArchKind;
@@ -92,12 +95,16 @@ public:
MacroBuilder &Builder) const;
void getTargetDefinesARMV87A(const LangOptions &Opts,
MacroBuilder &Builder) const;
+ void getTargetDefinesARMV88A(const LangOptions &Opts,
+ MacroBuilder &Builder) const;
void getTargetDefinesARMV9A(const LangOptions &Opts,
MacroBuilder &Builder) const;
void getTargetDefinesARMV91A(const LangOptions &Opts,
MacroBuilder &Builder) const;
void getTargetDefinesARMV92A(const LangOptions &Opts,
MacroBuilder &Builder) const;
+ void getTargetDefinesARMV93A(const LangOptions &Opts,
+ MacroBuilder &Builder) const;
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override;
diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp
index c619d6cde41d..478a0233398d 100644
--- a/clang/lib/Basic/Targets/ARM.cpp
+++ b/clang/lib/Basic/Targets/ARM.cpp
@@ -212,12 +212,16 @@ StringRef ARMTargetInfo::getCPUAttr() const {
return "8_6A";
case llvm::ARM::ArchKind::ARMV8_7A:
return "8_7A";
+ case llvm::ARM::ArchKind::ARMV8_8A:
+ return "8_8A";
case llvm::ARM::ArchKind::ARMV9A:
return "9A";
case llvm::ARM::ArchKind::ARMV9_1A:
return "9_1A";
case llvm::ARM::ArchKind::ARMV9_2A:
return "9_2A";
+ case llvm::ARM::ArchKind::ARMV9_3A:
+ return "9_3A";
case llvm::ARM::ArchKind::ARMV8MBaseline:
return "8M_BASE";
case llvm::ARM::ArchKind::ARMV8MMainline:
@@ -930,9 +934,11 @@ void ARMTargetInfo::getTargetDefines(const LangOptions &Opts,
case llvm::ARM::ArchKind::ARMV8_4A:
case llvm::ARM::ArchKind::ARMV8_5A:
case llvm::ARM::ArchKind::ARMV8_6A:
+ case llvm::ARM::ArchKind::ARMV8_8A:
case llvm::ARM::ArchKind::ARMV9A:
case llvm::ARM::ArchKind::ARMV9_1A:
case llvm::ARM::ArchKind::ARMV9_2A:
+ case llvm::ARM::ArchKind::ARMV9_3A:
getTargetDefinesARMV83A(Opts, Builder);
break;
}
diff --git a/clang/lib/Basic/Targets/ARM.h b/clang/lib/Basic/Targets/ARM.h
index 40c658f3f40e..f074dac57f9b 100644
--- a/clang/lib/Basic/Targets/ARM.h
+++ b/clang/lib/Basic/Targets/ARM.h
@@ -18,6 +18,7 @@
#include "clang/Basic/TargetOptions.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ARMTargetParser.h"
#include "llvm/Support/TargetParser.h"
namespace clang {
diff --git a/clang/lib/Basic/Targets/AVR.cpp b/clang/lib/Basic/Targets/AVR.cpp
index 50b0fc07b311..6266ed72cd5c 100644
--- a/clang/lib/Basic/Targets/AVR.cpp
+++ b/clang/lib/Basic/Targets/AVR.cpp
@@ -24,281 +24,282 @@ namespace targets {
struct LLVM_LIBRARY_VISIBILITY MCUInfo {
const char *Name;
const char *DefineName;
+ const int NumFlashBanks; // -1 means the device does not support LPM/ELPM.
};
// This list should be kept up-to-date with AVRDevices.td in LLVM.
static MCUInfo AVRMcus[] = {
- {"at90s1200", "__AVR_AT90S1200__"},
- {"attiny11", "__AVR_ATtiny11__"},
- {"attiny12", "__AVR_ATtiny12__"},
- {"attiny15", "__AVR_ATtiny15__"},
- {"attiny28", "__AVR_ATtiny28__"},
- {"at90s2313", "__AVR_AT90S2313__"},
- {"at90s2323", "__AVR_AT90S2323__"},
- {"at90s2333", "__AVR_AT90S2333__"},
- {"at90s2343", "__AVR_AT90S2343__"},
- {"attiny22", "__AVR_ATtiny22__"},
- {"attiny26", "__AVR_ATtiny26__"},
- {"at86rf401", "__AVR_AT86RF401__"},
- {"at90s4414", "__AVR_AT90S4414__"},
- {"at90s4433", "__AVR_AT90S4433__"},
- {"at90s4434", "__AVR_AT90S4434__"},
- {"at90s8515", "__AVR_AT90S8515__"},
- {"at90c8534", "__AVR_AT90c8534__"},
- {"at90s8535", "__AVR_AT90S8535__"},
- {"ata5272", "__AVR_ATA5272__"},
- {"attiny13", "__AVR_ATtiny13__"},
- {"attiny13a", "__AVR_ATtiny13A__"},
- {"attiny2313", "__AVR_ATtiny2313__"},
- {"attiny2313a", "__AVR_ATtiny2313A__"},
- {"attiny24", "__AVR_ATtiny24__"},
- {"attiny24a", "__AVR_ATtiny24A__"},
- {"attiny4313", "__AVR_ATtiny4313__"},
- {"attiny44", "__AVR_ATtiny44__"},
- {"attiny44a", "__AVR_ATtiny44A__"},
- {"attiny84", "__AVR_ATtiny84__"},
- {"attiny84a", "__AVR_ATtiny84A__"},
- {"attiny25", "__AVR_ATtiny25__"},
- {"attiny45", "__AVR_ATtiny45__"},
- {"attiny85", "__AVR_ATtiny85__"},
- {"attiny261", "__AVR_ATtiny261__"},
- {"attiny261a", "__AVR_ATtiny261A__"},
- {"attiny441", "__AVR_ATtiny441__"},
- {"attiny461", "__AVR_ATtiny461__"},
- {"attiny461a", "__AVR_ATtiny461A__"},
- {"attiny841", "__AVR_ATtiny841__"},
- {"attiny861", "__AVR_ATtiny861__"},
- {"attiny861a", "__AVR_ATtiny861A__"},
- {"attiny87", "__AVR_ATtiny87__"},
- {"attiny43u", "__AVR_ATtiny43U__"},
- {"attiny48", "__AVR_ATtiny48__"},
- {"attiny88", "__AVR_ATtiny88__"},
- {"attiny828", "__AVR_ATtiny828__"},
- {"at43usb355", "__AVR_AT43USB355__"},
- {"at76c711", "__AVR_AT76C711__"},
- {"atmega103", "__AVR_ATmega103__"},
- {"at43usb320", "__AVR_AT43USB320__"},
- {"attiny167", "__AVR_ATtiny167__"},
- {"at90usb82", "__AVR_AT90USB82__"},
- {"at90usb162", "__AVR_AT90USB162__"},
- {"ata5505", "__AVR_ATA5505__"},
- {"atmega8u2", "__AVR_ATmega8U2__"},
- {"atmega16u2", "__AVR_ATmega16U2__"},
- {"atmega32u2", "__AVR_ATmega32U2__"},
- {"attiny1634", "__AVR_ATtiny1634__"},
- {"atmega8", "__AVR_ATmega8__"},
- {"ata6289", "__AVR_ATA6289__"},
- {"atmega8a", "__AVR_ATmega8A__"},
- {"ata6285", "__AVR_ATA6285__"},
- {"ata6286", "__AVR_ATA6286__"},
- {"atmega48", "__AVR_ATmega48__"},
- {"atmega48a", "__AVR_ATmega48A__"},
- {"atmega48pa", "__AVR_ATmega48PA__"},
- {"atmega48pb", "__AVR_ATmega48PB__"},
- {"atmega48p", "__AVR_ATmega48P__"},
- {"atmega88", "__AVR_ATmega88__"},
- {"atmega88a", "__AVR_ATmega88A__"},
- {"atmega88p", "__AVR_ATmega88P__"},
- {"atmega88pa", "__AVR_ATmega88PA__"},
- {"atmega88pb", "__AVR_ATmega88PB__"},
- {"atmega8515", "__AVR_ATmega8515__"},
- {"atmega8535", "__AVR_ATmega8535__"},
- {"atmega8hva", "__AVR_ATmega8HVA__"},
- {"at90pwm1", "__AVR_AT90PWM1__"},
- {"at90pwm2", "__AVR_AT90PWM2__"},
- {"at90pwm2b", "__AVR_AT90PWM2B__"},
- {"at90pwm3", "__AVR_AT90PWM3__"},
- {"at90pwm3b", "__AVR_AT90PWM3B__"},
- {"at90pwm81", "__AVR_AT90PWM81__"},
- {"ata5790", "__AVR_ATA5790__"},
- {"ata5795", "__AVR_ATA5795__"},
- {"atmega16", "__AVR_ATmega16__"},
- {"atmega16a", "__AVR_ATmega16A__"},
- {"atmega161", "__AVR_ATmega161__"},
- {"atmega162", "__AVR_ATmega162__"},
- {"atmega163", "__AVR_ATmega163__"},
- {"atmega164a", "__AVR_ATmega164A__"},
- {"atmega164p", "__AVR_ATmega164P__"},
- {"atmega164pa", "__AVR_ATmega164PA__"},
- {"atmega165", "__AVR_ATmega165__"},
- {"atmega165a", "__AVR_ATmega165A__"},
- {"atmega165p", "__AVR_ATmega165P__"},
- {"atmega165pa", "__AVR_ATmega165PA__"},
- {"atmega168", "__AVR_ATmega168__"},
- {"atmega168a", "__AVR_ATmega168A__"},
- {"atmega168p", "__AVR_ATmega168P__"},
- {"atmega168pa", "__AVR_ATmega168PA__"},
- {"atmega168pb", "__AVR_ATmega168PB__"},
- {"atmega169", "__AVR_ATmega169__"},
- {"atmega169a", "__AVR_ATmega169A__"},
- {"atmega169p", "__AVR_ATmega169P__"},
- {"atmega169pa", "__AVR_ATmega169PA__"},
- {"atmega32", "__AVR_ATmega32__"},
- {"atmega32a", "__AVR_ATmega32A__"},
- {"atmega323", "__AVR_ATmega323__"},
- {"atmega324a", "__AVR_ATmega324A__"},
- {"atmega324p", "__AVR_ATmega324P__"},
- {"atmega324pa", "__AVR_ATmega324PA__"},
- {"atmega324pb", "__AVR_ATmega324PB__"},
- {"atmega325", "__AVR_ATmega325__"},
- {"atmega325a", "__AVR_ATmega325A__"},
- {"atmega325p", "__AVR_ATmega325P__"},
- {"atmega325pa", "__AVR_ATmega325PA__"},
- {"atmega3250", "__AVR_ATmega3250__"},
- {"atmega3250a", "__AVR_ATmega3250A__"},
- {"atmega3250p", "__AVR_ATmega3250P__"},
- {"atmega3250pa", "__AVR_ATmega3250PA__"},
- {"atmega328", "__AVR_ATmega328__"},
- {"atmega328p", "__AVR_ATmega328P__"},
- {"atmega328pb", "__AVR_ATmega328PB__"},
- {"atmega329", "__AVR_ATmega329__"},
- {"atmega329a", "__AVR_ATmega329A__"},
- {"atmega329p", "__AVR_ATmega329P__"},
- {"atmega329pa", "__AVR_ATmega329PA__"},
- {"atmega3290", "__AVR_ATmega3290__"},
- {"atmega3290a", "__AVR_ATmega3290A__"},
- {"atmega3290p", "__AVR_ATmega3290P__"},
- {"atmega3290pa", "__AVR_ATmega3290PA__"},
- {"atmega406", "__AVR_ATmega406__"},
- {"atmega64", "__AVR_ATmega64__"},
- {"atmega64a", "__AVR_ATmega64A__"},
- {"atmega640", "__AVR_ATmega640__"},
- {"atmega644", "__AVR_ATmega644__"},
- {"atmega644a", "__AVR_ATmega644A__"},
- {"atmega644p", "__AVR_ATmega644P__"},
- {"atmega644pa", "__AVR_ATmega644PA__"},
- {"atmega645", "__AVR_ATmega645__"},
- {"atmega645a", "__AVR_ATmega645A__"},
- {"atmega645p", "__AVR_ATmega645P__"},
- {"atmega649", "__AVR_ATmega649__"},
- {"atmega649a", "__AVR_ATmega649A__"},
- {"atmega649p", "__AVR_ATmega649P__"},
- {"atmega6450", "__AVR_ATmega6450__"},
- {"atmega6450a", "__AVR_ATmega6450A__"},
- {"atmega6450p", "__AVR_ATmega6450P__"},
- {"atmega6490", "__AVR_ATmega6490__"},
- {"atmega6490a", "__AVR_ATmega6490A__"},
- {"atmega6490p", "__AVR_ATmega6490P__"},
- {"atmega64rfr2", "__AVR_ATmega64RFR2__"},
- {"atmega644rfr2", "__AVR_ATmega644RFR2__"},
- {"atmega16hva", "__AVR_ATmega16HVA__"},
- {"atmega16hva2", "__AVR_ATmega16HVA2__"},
- {"atmega16hvb", "__AVR_ATmega16HVB__"},
- {"atmega16hvbrevb", "__AVR_ATmega16HVBREVB__"},
- {"atmega32hvb", "__AVR_ATmega32HVB__"},
- {"atmega32hvbrevb", "__AVR_ATmega32HVBREVB__"},
- {"atmega64hve", "__AVR_ATmega64HVE__"},
- {"at90can32", "__AVR_AT90CAN32__"},
- {"at90can64", "__AVR_AT90CAN64__"},
- {"at90pwm161", "__AVR_AT90PWM161__"},
- {"at90pwm216", "__AVR_AT90PWM216__"},
- {"at90pwm316", "__AVR_AT90PWM316__"},
- {"atmega32c1", "__AVR_ATmega32C1__"},
- {"atmega64c1", "__AVR_ATmega64C1__"},
- {"atmega16m1", "__AVR_ATmega16M1__"},
- {"atmega32m1", "__AVR_ATmega32M1__"},
- {"atmega64m1", "__AVR_ATmega64M1__"},
- {"atmega16u4", "__AVR_ATmega16U4__"},
- {"atmega32u4", "__AVR_ATmega32U4__"},
- {"atmega32u6", "__AVR_ATmega32U6__"},
- {"at90usb646", "__AVR_AT90USB646__"},
- {"at90usb647", "__AVR_AT90USB647__"},
- {"at90scr100", "__AVR_AT90SCR100__"},
- {"at94k", "__AVR_AT94K__"},
- {"m3000", "__AVR_AT000__"},
- {"atmega128", "__AVR_ATmega128__"},
- {"atmega128a", "__AVR_ATmega128A__"},
- {"atmega1280", "__AVR_ATmega1280__"},
- {"atmega1281", "__AVR_ATmega1281__"},
- {"atmega1284", "__AVR_ATmega1284__"},
- {"atmega1284p", "__AVR_ATmega1284P__"},
- {"atmega128rfa1", "__AVR_ATmega128RFA1__"},
- {"atmega128rfr2", "__AVR_ATmega128RFR2__"},
- {"atmega1284rfr2", "__AVR_ATmega1284RFR2__"},
- {"at90can128", "__AVR_AT90CAN128__"},
- {"at90usb1286", "__AVR_AT90USB1286__"},
- {"at90usb1287", "__AVR_AT90USB1287__"},
- {"atmega2560", "__AVR_ATmega2560__"},
- {"atmega2561", "__AVR_ATmega2561__"},
- {"atmega256rfr2", "__AVR_ATmega256RFR2__"},
- {"atmega2564rfr2", "__AVR_ATmega2564RFR2__"},
- {"atxmega16a4", "__AVR_ATxmega16A4__"},
- {"atxmega16a4u", "__AVR_ATxmega16A4U__"},
- {"atxmega16c4", "__AVR_ATxmega16C4__"},
- {"atxmega16d4", "__AVR_ATxmega16D4__"},
- {"atxmega32a4", "__AVR_ATxmega32A4__"},
- {"atxmega32a4u", "__AVR_ATxmega32A4U__"},
- {"atxmega32c4", "__AVR_ATxmega32C4__"},
- {"atxmega32d4", "__AVR_ATxmega32D4__"},
- {"atxmega32e5", "__AVR_ATxmega32E5__"},
- {"atxmega16e5", "__AVR_ATxmega16E5__"},
- {"atxmega8e5", "__AVR_ATxmega8E5__"},
- {"atxmega32x1", "__AVR_ATxmega32X1__"},
- {"atxmega64a3", "__AVR_ATxmega64A3__"},
- {"atxmega64a3u", "__AVR_ATxmega64A3U__"},
- {"atxmega64a4u", "__AVR_ATxmega64A4U__"},
- {"atxmega64b1", "__AVR_ATxmega64B1__"},
- {"atxmega64b3", "__AVR_ATxmega64B3__"},
- {"atxmega64c3", "__AVR_ATxmega64C3__"},
- {"atxmega64d3", "__AVR_ATxmega64D3__"},
- {"atxmega64d4", "__AVR_ATxmega64D4__"},
- {"atxmega64a1", "__AVR_ATxmega64A1__"},
- {"atxmega64a1u", "__AVR_ATxmega64A1U__"},
- {"atxmega128a3", "__AVR_ATxmega128A3__"},
- {"atxmega128a3u", "__AVR_ATxmega128A3U__"},
- {"atxmega128b1", "__AVR_ATxmega128B1__"},
- {"atxmega128b3", "__AVR_ATxmega128B3__"},
- {"atxmega128c3", "__AVR_ATxmega128C3__"},
- {"atxmega128d3", "__AVR_ATxmega128D3__"},
- {"atxmega128d4", "__AVR_ATxmega128D4__"},
- {"atxmega192a3", "__AVR_ATxmega192A3__"},
- {"atxmega192a3u", "__AVR_ATxmega192A3U__"},
- {"atxmega192c3", "__AVR_ATxmega192C3__"},
- {"atxmega192d3", "__AVR_ATxmega192D3__"},
- {"atxmega256a3", "__AVR_ATxmega256A3__"},
- {"atxmega256a3u", "__AVR_ATxmega256A3U__"},
- {"atxmega256a3b", "__AVR_ATxmega256A3B__"},
- {"atxmega256a3bu", "__AVR_ATxmega256A3BU__"},
- {"atxmega256c3", "__AVR_ATxmega256C3__"},
- {"atxmega256d3", "__AVR_ATxmega256D3__"},
- {"atxmega384c3", "__AVR_ATxmega384C3__"},
- {"atxmega384d3", "__AVR_ATxmega384D3__"},
- {"atxmega128a1", "__AVR_ATxmega128A1__"},
- {"atxmega128a1u", "__AVR_ATxmega128A1U__"},
- {"atxmega128a4u", "__AVR_ATxmega128A4U__"},
- {"attiny4", "__AVR_ATtiny4__"},
- {"attiny5", "__AVR_ATtiny5__"},
- {"attiny9", "__AVR_ATtiny9__"},
- {"attiny10", "__AVR_ATtiny10__"},
- {"attiny20", "__AVR_ATtiny20__"},
- {"attiny40", "__AVR_ATtiny40__"},
- {"attiny102", "__AVR_ATtiny102__"},
- {"attiny104", "__AVR_ATtiny104__"},
- {"attiny202", "__AVR_ATtiny202__"},
- {"attiny402", "__AVR_ATtiny402__"},
- {"attiny204", "__AVR_ATtiny204__"},
- {"attiny404", "__AVR_ATtiny404__"},
- {"attiny804", "__AVR_ATtiny804__"},
- {"attiny1604", "__AVR_ATtiny1604__"},
- {"attiny406", "__AVR_ATtiny406__"},
- {"attiny806", "__AVR_ATtiny806__"},
- {"attiny1606", "__AVR_ATtiny1606__"},
- {"attiny807", "__AVR_ATtiny807__"},
- {"attiny1607", "__AVR_ATtiny1607__"},
- {"attiny212", "__AVR_ATtiny212__"},
- {"attiny412", "__AVR_ATtiny412__"},
- {"attiny214", "__AVR_ATtiny214__"},
- {"attiny414", "__AVR_ATtiny414__"},
- {"attiny814", "__AVR_ATtiny814__"},
- {"attiny1614", "__AVR_ATtiny1614__"},
- {"attiny416", "__AVR_ATtiny416__"},
- {"attiny816", "__AVR_ATtiny816__"},
- {"attiny1616", "__AVR_ATtiny1616__"},
- {"attiny3216", "__AVR_ATtiny3216__"},
- {"attiny417", "__AVR_ATtiny417__"},
- {"attiny817", "__AVR_ATtiny817__"},
- {"attiny1617", "__AVR_ATtiny1617__"},
- {"attiny3217", "__AVR_ATtiny3217__"},
+ {"at90s1200", "__AVR_AT90S1200__", 0},
+ {"attiny11", "__AVR_ATtiny11__", 0},
+ {"attiny12", "__AVR_ATtiny12__", 0},
+ {"attiny15", "__AVR_ATtiny15__", 0},
+ {"attiny28", "__AVR_ATtiny28__", 0},
+ {"at90s2313", "__AVR_AT90S2313__", 1},
+ {"at90s2323", "__AVR_AT90S2323__", 1},
+ {"at90s2333", "__AVR_AT90S2333__", 1},
+ {"at90s2343", "__AVR_AT90S2343__", 1},
+ {"attiny22", "__AVR_ATtiny22__", 1},
+ {"attiny26", "__AVR_ATtiny26__", 1},
+ {"at86rf401", "__AVR_AT86RF401__", 1},
+ {"at90s4414", "__AVR_AT90S4414__", 1},
+ {"at90s4433", "__AVR_AT90S4433__", 1},
+ {"at90s4434", "__AVR_AT90S4434__", 1},
+ {"at90s8515", "__AVR_AT90S8515__", 1},
+ {"at90c8534", "__AVR_AT90c8534__", 1},
+ {"at90s8535", "__AVR_AT90S8535__", 1},
+ {"ata5272", "__AVR_ATA5272__", 1},
+ {"attiny13", "__AVR_ATtiny13__", 1},
+ {"attiny13a", "__AVR_ATtiny13A__", 1},
+ {"attiny2313", "__AVR_ATtiny2313__", 1},
+ {"attiny2313a", "__AVR_ATtiny2313A__", 1},
+ {"attiny24", "__AVR_ATtiny24__", 1},
+ {"attiny24a", "__AVR_ATtiny24A__", 1},
+ {"attiny4313", "__AVR_ATtiny4313__", 1},
+ {"attiny44", "__AVR_ATtiny44__", 1},
+ {"attiny44a", "__AVR_ATtiny44A__", 1},
+ {"attiny84", "__AVR_ATtiny84__", 1},
+ {"attiny84a", "__AVR_ATtiny84A__", 1},
+ {"attiny25", "__AVR_ATtiny25__", 1},
+ {"attiny45", "__AVR_ATtiny45__", 1},
+ {"attiny85", "__AVR_ATtiny85__", 1},
+ {"attiny261", "__AVR_ATtiny261__", 1},
+ {"attiny261a", "__AVR_ATtiny261A__", 1},
+ {"attiny441", "__AVR_ATtiny441__", 1},
+ {"attiny461", "__AVR_ATtiny461__", 1},
+ {"attiny461a", "__AVR_ATtiny461A__", 1},
+ {"attiny841", "__AVR_ATtiny841__", 1},
+ {"attiny861", "__AVR_ATtiny861__", 1},
+ {"attiny861a", "__AVR_ATtiny861A__", 1},
+ {"attiny87", "__AVR_ATtiny87__", 1},
+ {"attiny43u", "__AVR_ATtiny43U__", 1},
+ {"attiny48", "__AVR_ATtiny48__", 1},
+ {"attiny88", "__AVR_ATtiny88__", 1},
+ {"attiny828", "__AVR_ATtiny828__", 1},
+ {"at43usb355", "__AVR_AT43USB355__", 1},
+ {"at76c711", "__AVR_AT76C711__", 1},
+ {"atmega103", "__AVR_ATmega103__", 1},
+ {"at43usb320", "__AVR_AT43USB320__", 1},
+ {"attiny167", "__AVR_ATtiny167__", 1},
+ {"at90usb82", "__AVR_AT90USB82__", 1},
+ {"at90usb162", "__AVR_AT90USB162__", 1},
+ {"ata5505", "__AVR_ATA5505__", 1},
+ {"atmega8u2", "__AVR_ATmega8U2__", 1},
+ {"atmega16u2", "__AVR_ATmega16U2__", 1},
+ {"atmega32u2", "__AVR_ATmega32U2__", 1},
+ {"attiny1634", "__AVR_ATtiny1634__", 1},
+ {"atmega8", "__AVR_ATmega8__", 1},
+ {"ata6289", "__AVR_ATA6289__", 1},
+ {"atmega8a", "__AVR_ATmega8A__", 1},
+ {"ata6285", "__AVR_ATA6285__", 1},
+ {"ata6286", "__AVR_ATA6286__", 1},
+ {"atmega48", "__AVR_ATmega48__", 1},
+ {"atmega48a", "__AVR_ATmega48A__", 1},
+ {"atmega48pa", "__AVR_ATmega48PA__", 1},
+ {"atmega48pb", "__AVR_ATmega48PB__", 1},
+ {"atmega48p", "__AVR_ATmega48P__", 1},
+ {"atmega88", "__AVR_ATmega88__", 1},
+ {"atmega88a", "__AVR_ATmega88A__", 1},
+ {"atmega88p", "__AVR_ATmega88P__", 1},
+ {"atmega88pa", "__AVR_ATmega88PA__", 1},
+ {"atmega88pb", "__AVR_ATmega88PB__", 1},
+ {"atmega8515", "__AVR_ATmega8515__", 1},
+ {"atmega8535", "__AVR_ATmega8535__", 1},
+ {"atmega8hva", "__AVR_ATmega8HVA__", 1},
+ {"at90pwm1", "__AVR_AT90PWM1__", 1},
+ {"at90pwm2", "__AVR_AT90PWM2__", 1},
+ {"at90pwm2b", "__AVR_AT90PWM2B__", 1},
+ {"at90pwm3", "__AVR_AT90PWM3__", 1},
+ {"at90pwm3b", "__AVR_AT90PWM3B__", 1},
+ {"at90pwm81", "__AVR_AT90PWM81__", 1},
+ {"ata5790", "__AVR_ATA5790__", 1},
+ {"ata5795", "__AVR_ATA5795__", 1},
+ {"atmega16", "__AVR_ATmega16__", 1},
+ {"atmega16a", "__AVR_ATmega16A__", 1},
+ {"atmega161", "__AVR_ATmega161__", 1},
+ {"atmega162", "__AVR_ATmega162__", 1},
+ {"atmega163", "__AVR_ATmega163__", 1},
+ {"atmega164a", "__AVR_ATmega164A__", 1},
+ {"atmega164p", "__AVR_ATmega164P__", 1},
+ {"atmega164pa", "__AVR_ATmega164PA__", 1},
+ {"atmega165", "__AVR_ATmega165__", 1},
+ {"atmega165a", "__AVR_ATmega165A__", 1},
+ {"atmega165p", "__AVR_ATmega165P__", 1},
+ {"atmega165pa", "__AVR_ATmega165PA__", 1},
+ {"atmega168", "__AVR_ATmega168__", 1},
+ {"atmega168a", "__AVR_ATmega168A__", 1},
+ {"atmega168p", "__AVR_ATmega168P__", 1},
+ {"atmega168pa", "__AVR_ATmega168PA__", 1},
+ {"atmega168pb", "__AVR_ATmega168PB__", 1},
+ {"atmega169", "__AVR_ATmega169__", 1},
+ {"atmega169a", "__AVR_ATmega169A__", 1},
+ {"atmega169p", "__AVR_ATmega169P__", 1},
+ {"atmega169pa", "__AVR_ATmega169PA__", 1},
+ {"atmega32", "__AVR_ATmega32__", 1},
+ {"atmega32a", "__AVR_ATmega32A__", 1},
+ {"atmega323", "__AVR_ATmega323__", 1},
+ {"atmega324a", "__AVR_ATmega324A__", 1},
+ {"atmega324p", "__AVR_ATmega324P__", 1},
+ {"atmega324pa", "__AVR_ATmega324PA__", 1},
+ {"atmega324pb", "__AVR_ATmega324PB__", 1},
+ {"atmega325", "__AVR_ATmega325__", 1},
+ {"atmega325a", "__AVR_ATmega325A__", 1},
+ {"atmega325p", "__AVR_ATmega325P__", 1},
+ {"atmega325pa", "__AVR_ATmega325PA__", 1},
+ {"atmega3250", "__AVR_ATmega3250__", 1},
+ {"atmega3250a", "__AVR_ATmega3250A__", 1},
+ {"atmega3250p", "__AVR_ATmega3250P__", 1},
+ {"atmega3250pa", "__AVR_ATmega3250PA__", 1},
+ {"atmega328", "__AVR_ATmega328__", 1},
+ {"atmega328p", "__AVR_ATmega328P__", 1},
+ {"atmega328pb", "__AVR_ATmega328PB__", 1},
+ {"atmega329", "__AVR_ATmega329__", 1},
+ {"atmega329a", "__AVR_ATmega329A__", 1},
+ {"atmega329p", "__AVR_ATmega329P__", 1},
+ {"atmega329pa", "__AVR_ATmega329PA__", 1},
+ {"atmega3290", "__AVR_ATmega3290__", 1},
+ {"atmega3290a", "__AVR_ATmega3290A__", 1},
+ {"atmega3290p", "__AVR_ATmega3290P__", 1},
+ {"atmega3290pa", "__AVR_ATmega3290PA__", 1},
+ {"atmega406", "__AVR_ATmega406__", 1},
+ {"atmega64", "__AVR_ATmega64__", 1},
+ {"atmega64a", "__AVR_ATmega64A__", 1},
+ {"atmega640", "__AVR_ATmega640__", 1},
+ {"atmega644", "__AVR_ATmega644__", 1},
+ {"atmega644a", "__AVR_ATmega644A__", 1},
+ {"atmega644p", "__AVR_ATmega644P__", 1},
+ {"atmega644pa", "__AVR_ATmega644PA__", 1},
+ {"atmega645", "__AVR_ATmega645__", 1},
+ {"atmega645a", "__AVR_ATmega645A__", 1},
+ {"atmega645p", "__AVR_ATmega645P__", 1},
+ {"atmega649", "__AVR_ATmega649__", 1},
+ {"atmega649a", "__AVR_ATmega649A__", 1},
+ {"atmega649p", "__AVR_ATmega649P__", 1},
+ {"atmega6450", "__AVR_ATmega6450__", 1},
+ {"atmega6450a", "__AVR_ATmega6450A__", 1},
+ {"atmega6450p", "__AVR_ATmega6450P__", 1},
+ {"atmega6490", "__AVR_ATmega6490__", 1},
+ {"atmega6490a", "__AVR_ATmega6490A__", 1},
+ {"atmega6490p", "__AVR_ATmega6490P__", 1},
+ {"atmega64rfr2", "__AVR_ATmega64RFR2__", 1},
+ {"atmega644rfr2", "__AVR_ATmega644RFR2__", 1},
+ {"atmega16hva", "__AVR_ATmega16HVA__", 1},
+ {"atmega16hva2", "__AVR_ATmega16HVA2__", 1},
+ {"atmega16hvb", "__AVR_ATmega16HVB__", 1},
+ {"atmega16hvbrevb", "__AVR_ATmega16HVBREVB__", 1},
+ {"atmega32hvb", "__AVR_ATmega32HVB__", 1},
+ {"atmega32hvbrevb", "__AVR_ATmega32HVBREVB__", 1},
+ {"atmega64hve", "__AVR_ATmega64HVE__", 1},
+ {"at90can32", "__AVR_AT90CAN32__", 1},
+ {"at90can64", "__AVR_AT90CAN64__", 1},
+ {"at90pwm161", "__AVR_AT90PWM161__", 1},
+ {"at90pwm216", "__AVR_AT90PWM216__", 1},
+ {"at90pwm316", "__AVR_AT90PWM316__", 1},
+ {"atmega32c1", "__AVR_ATmega32C1__", 1},
+ {"atmega64c1", "__AVR_ATmega64C1__", 1},
+ {"atmega16m1", "__AVR_ATmega16M1__", 1},
+ {"atmega32m1", "__AVR_ATmega32M1__", 1},
+ {"atmega64m1", "__AVR_ATmega64M1__", 1},
+ {"atmega16u4", "__AVR_ATmega16U4__", 1},
+ {"atmega32u4", "__AVR_ATmega32U4__", 1},
+ {"atmega32u6", "__AVR_ATmega32U6__", 1},
+ {"at90usb646", "__AVR_AT90USB646__", 1},
+ {"at90usb647", "__AVR_AT90USB647__", 1},
+ {"at90scr100", "__AVR_AT90SCR100__", 1},
+ {"at94k", "__AVR_AT94K__", 1},
+ {"m3000", "__AVR_AT000__", 1},
+ {"atmega128", "__AVR_ATmega128__", 2},
+ {"atmega128a", "__AVR_ATmega128A__", 2},
+ {"atmega1280", "__AVR_ATmega1280__", 2},
+ {"atmega1281", "__AVR_ATmega1281__", 2},
+ {"atmega1284", "__AVR_ATmega1284__", 2},
+ {"atmega1284p", "__AVR_ATmega1284P__", 2},
+ {"atmega128rfa1", "__AVR_ATmega128RFA1__", 2},
+ {"atmega128rfr2", "__AVR_ATmega128RFR2__", 2},
+ {"atmega1284rfr2", "__AVR_ATmega1284RFR2__", 2},
+ {"at90can128", "__AVR_AT90CAN128__", 2},
+ {"at90usb1286", "__AVR_AT90USB1286__", 2},
+ {"at90usb1287", "__AVR_AT90USB1287__", 2},
+ {"atmega2560", "__AVR_ATmega2560__", 4},
+ {"atmega2561", "__AVR_ATmega2561__", 4},
+ {"atmega256rfr2", "__AVR_ATmega256RFR2__", 4},
+ {"atmega2564rfr2", "__AVR_ATmega2564RFR2__", 4},
+ {"atxmega16a4", "__AVR_ATxmega16A4__", 1},
+ {"atxmega16a4u", "__AVR_ATxmega16A4U__", 1},
+ {"atxmega16c4", "__AVR_ATxmega16C4__", 1},
+ {"atxmega16d4", "__AVR_ATxmega16D4__", 1},
+ {"atxmega32a4", "__AVR_ATxmega32A4__", 1},
+ {"atxmega32a4u", "__AVR_ATxmega32A4U__", 1},
+ {"atxmega32c4", "__AVR_ATxmega32C4__", 1},
+ {"atxmega32d4", "__AVR_ATxmega32D4__", 1},
+ {"atxmega32e5", "__AVR_ATxmega32E5__", 1},
+ {"atxmega16e5", "__AVR_ATxmega16E5__", 1},
+ {"atxmega8e5", "__AVR_ATxmega8E5__", 1},
+ {"atxmega32x1", "__AVR_ATxmega32X1__", 1},
+ {"atxmega64a3", "__AVR_ATxmega64A3__", 1},
+ {"atxmega64a3u", "__AVR_ATxmega64A3U__", 1},
+ {"atxmega64a4u", "__AVR_ATxmega64A4U__", 1},
+ {"atxmega64b1", "__AVR_ATxmega64B1__", 1},
+ {"atxmega64b3", "__AVR_ATxmega64B3__", 1},
+ {"atxmega64c3", "__AVR_ATxmega64C3__", 1},
+ {"atxmega64d3", "__AVR_ATxmega64D3__", 1},
+ {"atxmega64d4", "__AVR_ATxmega64D4__", 1},
+ {"atxmega64a1", "__AVR_ATxmega64A1__", 1},
+ {"atxmega64a1u", "__AVR_ATxmega64A1U__", 1},
+ {"atxmega128a3", "__AVR_ATxmega128A3__", 2},
+ {"atxmega128a3u", "__AVR_ATxmega128A3U__", 2},
+ {"atxmega128b1", "__AVR_ATxmega128B1__", 2},
+ {"atxmega128b3", "__AVR_ATxmega128B3__", 2},
+ {"atxmega128c3", "__AVR_ATxmega128C3__", 2},
+ {"atxmega128d3", "__AVR_ATxmega128D3__", 2},
+ {"atxmega128d4", "__AVR_ATxmega128D4__", 2},
+ {"atxmega192a3", "__AVR_ATxmega192A3__", 3},
+ {"atxmega192a3u", "__AVR_ATxmega192A3U__", 3},
+ {"atxmega192c3", "__AVR_ATxmega192C3__", 3},
+ {"atxmega192d3", "__AVR_ATxmega192D3__", 3},
+ {"atxmega256a3", "__AVR_ATxmega256A3__", 4},
+ {"atxmega256a3u", "__AVR_ATxmega256A3U__", 4},
+ {"atxmega256a3b", "__AVR_ATxmega256A3B__", 4},
+ {"atxmega256a3bu", "__AVR_ATxmega256A3BU__", 4},
+ {"atxmega256c3", "__AVR_ATxmega256C3__", 4},
+ {"atxmega256d3", "__AVR_ATxmega256D3__", 4},
+ {"atxmega384c3", "__AVR_ATxmega384C3__", 6},
+ {"atxmega384d3", "__AVR_ATxmega384D3__", 6},
+ {"atxmega128a1", "__AVR_ATxmega128A1__", 2},
+ {"atxmega128a1u", "__AVR_ATxmega128A1U__", 2},
+ {"atxmega128a4u", "__AVR_ATxmega128A4U__", 2},
+ {"attiny4", "__AVR_ATtiny4__", 0},
+ {"attiny5", "__AVR_ATtiny5__", 0},
+ {"attiny9", "__AVR_ATtiny9__", 0},
+ {"attiny10", "__AVR_ATtiny10__", 0},
+ {"attiny20", "__AVR_ATtiny20__", 0},
+ {"attiny40", "__AVR_ATtiny40__", 0},
+ {"attiny102", "__AVR_ATtiny102__", 0},
+ {"attiny104", "__AVR_ATtiny104__", 0},
+ {"attiny202", "__AVR_ATtiny202__", 1},
+ {"attiny402", "__AVR_ATtiny402__", 1},
+ {"attiny204", "__AVR_ATtiny204__", 1},
+ {"attiny404", "__AVR_ATtiny404__", 1},
+ {"attiny804", "__AVR_ATtiny804__", 1},
+ {"attiny1604", "__AVR_ATtiny1604__", 1},
+ {"attiny406", "__AVR_ATtiny406__", 1},
+ {"attiny806", "__AVR_ATtiny806__", 1},
+ {"attiny1606", "__AVR_ATtiny1606__", 1},
+ {"attiny807", "__AVR_ATtiny807__", 1},
+ {"attiny1607", "__AVR_ATtiny1607__", 1},
+ {"attiny212", "__AVR_ATtiny212__", 1},
+ {"attiny412", "__AVR_ATtiny412__", 1},
+ {"attiny214", "__AVR_ATtiny214__", 1},
+ {"attiny414", "__AVR_ATtiny414__", 1},
+ {"attiny814", "__AVR_ATtiny814__", 1},
+ {"attiny1614", "__AVR_ATtiny1614__", 1},
+ {"attiny416", "__AVR_ATtiny416__", 1},
+ {"attiny816", "__AVR_ATtiny816__", 1},
+ {"attiny1616", "__AVR_ATtiny1616__", 1},
+ {"attiny3216", "__AVR_ATtiny3216__", 1},
+ {"attiny417", "__AVR_ATtiny417__", 1},
+ {"attiny817", "__AVR_ATtiny817__", 1},
+ {"attiny1617", "__AVR_ATtiny1617__", 1},
+ {"attiny3217", "__AVR_ATtiny3217__", 1},
};
} // namespace targets
@@ -330,13 +331,25 @@ void AVRTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__AVR");
Builder.defineMacro("__AVR__");
Builder.defineMacro("__ELF__");
- Builder.defineMacro("__flash", "__attribute__((address_space(1)))");
if (!this->CPU.empty()) {
auto It = llvm::find_if(
AVRMcus, [&](const MCUInfo &Info) { return Info.Name == this->CPU; });
- if (It != std::end(AVRMcus))
+ if (It != std::end(AVRMcus)) {
Builder.defineMacro(It->DefineName);
+ if (It->NumFlashBanks >= 1)
+ Builder.defineMacro("__flash", "__attribute__((address_space(1)))");
+ if (It->NumFlashBanks >= 2)
+ Builder.defineMacro("__flash1", "__attribute__((address_space(2)))");
+ if (It->NumFlashBanks >= 3)
+ Builder.defineMacro("__flash2", "__attribute__((address_space(3)))");
+ if (It->NumFlashBanks >= 4)
+ Builder.defineMacro("__flash3", "__attribute__((address_space(4)))");
+ if (It->NumFlashBanks >= 5)
+ Builder.defineMacro("__flash4", "__attribute__((address_space(5)))");
+ if (It->NumFlashBanks >= 6)
+ Builder.defineMacro("__flash5", "__attribute__((address_space(6)))");
+ }
}
}
diff --git a/clang/lib/Basic/Targets/AVR.h b/clang/lib/Basic/Targets/AVR.h
index 89a80ca6a39a..a281e2c2cd74 100644
--- a/clang/lib/Basic/Targets/AVR.h
+++ b/clang/lib/Basic/Targets/AVR.h
@@ -55,6 +55,7 @@ public:
Int16Type = SignedInt;
Char32Type = UnsignedLong;
SigAtomicType = SignedChar;
+ ProgramAddrSpace = 1;
resetDataLayout("e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8");
}
diff --git a/clang/lib/Basic/Targets/M68k.cpp b/clang/lib/Basic/Targets/M68k.cpp
index c0cd8fa90ed6..ada5b97ed66d 100644
--- a/clang/lib/Basic/Targets/M68k.cpp
+++ b/clang/lib/Basic/Targets/M68k.cpp
@@ -29,7 +29,7 @@ M68kTargetInfo::M68kTargetInfo(const llvm::Triple &Triple,
const TargetOptions &)
: TargetInfo(Triple) {
- std::string Layout = "";
+ std::string Layout;
// M68k is Big Endian
Layout += "E";
diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp
index 7f7b44b658eb..1eb0317af60b 100644
--- a/clang/lib/Basic/Targets/PPC.cpp
+++ b/clang/lib/Basic/Targets/PPC.cpp
@@ -561,9 +561,9 @@ bool PPCTargetInfo::initFeatureMap(
if (!ppcUserFeaturesCheck(Diags, FeaturesVec))
return false;
- if (!(ArchDefs & ArchDefinePwr9) && (ArchDefs & ArchDefinePpcgr) &&
+ if (!(ArchDefs & ArchDefinePwr7) && (ArchDefs & ArchDefinePpcgr) &&
llvm::is_contained(FeaturesVec, "+float128")) {
- // We have __float128 on PPC but not power 9 and above.
+ // We have __float128 on PPC but not pre-VSX targets.
Diags.Report(diag::err_opt_not_valid_with_opt) << "-mfloat128" << CPU;
return false;
}
@@ -734,23 +734,28 @@ ArrayRef<const char *> PPCTargetInfo::getGCCRegNames() const {
const TargetInfo::GCCRegAlias PPCTargetInfo::GCCRegAliases[] = {
// While some of these aliases do map to different registers
// they still share the same register name.
- {{"0"}, "r0"}, {{"1"}, "r1"}, {{"2"}, "r2"}, {{"3"}, "r3"},
- {{"4"}, "r4"}, {{"5"}, "r5"}, {{"6"}, "r6"}, {{"7"}, "r7"},
- {{"8"}, "r8"}, {{"9"}, "r9"}, {{"10"}, "r10"}, {{"11"}, "r11"},
- {{"12"}, "r12"}, {{"13"}, "r13"}, {{"14"}, "r14"}, {{"15"}, "r15"},
- {{"16"}, "r16"}, {{"17"}, "r17"}, {{"18"}, "r18"}, {{"19"}, "r19"},
- {{"20"}, "r20"}, {{"21"}, "r21"}, {{"22"}, "r22"}, {{"23"}, "r23"},
- {{"24"}, "r24"}, {{"25"}, "r25"}, {{"26"}, "r26"}, {{"27"}, "r27"},
- {{"28"}, "r28"}, {{"29"}, "r29"}, {{"30"}, "r30"}, {{"31"}, "r31"},
- {{"fr0"}, "f0"}, {{"fr1"}, "f1"}, {{"fr2"}, "f2"}, {{"fr3"}, "f3"},
- {{"fr4"}, "f4"}, {{"fr5"}, "f5"}, {{"fr6"}, "f6"}, {{"fr7"}, "f7"},
- {{"fr8"}, "f8"}, {{"fr9"}, "f9"}, {{"fr10"}, "f10"}, {{"fr11"}, "f11"},
- {{"fr12"}, "f12"}, {{"fr13"}, "f13"}, {{"fr14"}, "f14"}, {{"fr15"}, "f15"},
- {{"fr16"}, "f16"}, {{"fr17"}, "f17"}, {{"fr18"}, "f18"}, {{"fr19"}, "f19"},
- {{"fr20"}, "f20"}, {{"fr21"}, "f21"}, {{"fr22"}, "f22"}, {{"fr23"}, "f23"},
- {{"fr24"}, "f24"}, {{"fr25"}, "f25"}, {{"fr26"}, "f26"}, {{"fr27"}, "f27"},
- {{"fr28"}, "f28"}, {{"fr29"}, "f29"}, {{"fr30"}, "f30"}, {{"fr31"}, "f31"},
- {{"cc"}, "cr0"},
+ {{"0"}, "r0"}, {{"1", "sp"}, "r1"}, {{"2"}, "r2"},
+ {{"3"}, "r3"}, {{"4"}, "r4"}, {{"5"}, "r5"},
+ {{"6"}, "r6"}, {{"7"}, "r7"}, {{"8"}, "r8"},
+ {{"9"}, "r9"}, {{"10"}, "r10"}, {{"11"}, "r11"},
+ {{"12"}, "r12"}, {{"13"}, "r13"}, {{"14"}, "r14"},
+ {{"15"}, "r15"}, {{"16"}, "r16"}, {{"17"}, "r17"},
+ {{"18"}, "r18"}, {{"19"}, "r19"}, {{"20"}, "r20"},
+ {{"21"}, "r21"}, {{"22"}, "r22"}, {{"23"}, "r23"},
+ {{"24"}, "r24"}, {{"25"}, "r25"}, {{"26"}, "r26"},
+ {{"27"}, "r27"}, {{"28"}, "r28"}, {{"29"}, "r29"},
+ {{"30"}, "r30"}, {{"31"}, "r31"}, {{"fr0"}, "f0"},
+ {{"fr1"}, "f1"}, {{"fr2"}, "f2"}, {{"fr3"}, "f3"},
+ {{"fr4"}, "f4"}, {{"fr5"}, "f5"}, {{"fr6"}, "f6"},
+ {{"fr7"}, "f7"}, {{"fr8"}, "f8"}, {{"fr9"}, "f9"},
+ {{"fr10"}, "f10"}, {{"fr11"}, "f11"}, {{"fr12"}, "f12"},
+ {{"fr13"}, "f13"}, {{"fr14"}, "f14"}, {{"fr15"}, "f15"},
+ {{"fr16"}, "f16"}, {{"fr17"}, "f17"}, {{"fr18"}, "f18"},
+ {{"fr19"}, "f19"}, {{"fr20"}, "f20"}, {{"fr21"}, "f21"},
+ {{"fr22"}, "f22"}, {{"fr23"}, "f23"}, {{"fr24"}, "f24"},
+ {{"fr25"}, "f25"}, {{"fr26"}, "f26"}, {{"fr27"}, "f27"},
+ {{"fr28"}, "f28"}, {{"fr29"}, "f29"}, {{"fr30"}, "f30"},
+ {{"fr31"}, "f31"}, {{"cc"}, "cr0"},
};
ArrayRef<TargetInfo::GCCRegAlias> PPCTargetInfo::getGCCRegAliases() const {
diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h
index 60701072ac4b..ac52eb219f54 100644
--- a/clang/lib/Basic/Targets/PPC.h
+++ b/clang/lib/Basic/Targets/PPC.h
@@ -414,7 +414,7 @@ public:
LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
IntMaxType = SignedLong;
Int64Type = SignedLong;
- std::string DataLayout = "";
+ std::string DataLayout;
if (Triple.isOSAIX()) {
// TODO: Set appropriate ABI for AIX platform.
diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp
index 770d37a1c1be..0680cad5b07c 100644
--- a/clang/lib/Basic/Targets/RISCV.cpp
+++ b/clang/lib/Basic/Targets/RISCV.cpp
@@ -125,6 +125,9 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32");
StringRef CodeModel = getTargetOpts().CodeModel;
unsigned FLen = ISAInfo->getFLen();
+ unsigned MinVLen = ISAInfo->getMinVLen();
+ unsigned MaxELen = ISAInfo->getMaxELen();
+ unsigned MaxELenFp = ISAInfo->getMaxELenFp();
if (CodeModel == "default")
CodeModel = "small";
@@ -176,10 +179,16 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__riscv_fsqrt");
}
+ if (MinVLen) {
+ Builder.defineMacro("__riscv_v_min_vlen", Twine(MinVLen));
+ Builder.defineMacro("__riscv_v_elen", Twine(MaxELen));
+ Builder.defineMacro("__riscv_v_elen_fp", Twine(MaxELenFp));
+ }
+
if (ISAInfo->hasExtension("c"))
Builder.defineMacro("__riscv_compressed");
- if (ISAInfo->hasExtension("v"))
+ if (ISAInfo->hasExtension("zve32x") || ISAInfo->hasExtension("v"))
Builder.defineMacro("__riscv_vector");
}
@@ -205,10 +214,26 @@ bool RISCVTargetInfo::initFeatureMap(
llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
const std::vector<std::string> &FeaturesVec) const {
- if (getTriple().getArch() == llvm::Triple::riscv64)
+ unsigned XLen = 32;
+
+ if (getTriple().getArch() == llvm::Triple::riscv64) {
Features["64bit"] = true;
+ XLen = 64;
+ }
+
+ auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesVec);
+ if (!ParseResult) {
+ std::string Buffer;
+ llvm::raw_string_ostream OutputErrMsg(Buffer);
+ handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {
+ OutputErrMsg << ErrMsg.getMessage();
+ });
+ Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
+ return false;
+ }
- return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
+ return TargetInfo::initFeatureMap(Features, Diags, CPU,
+ (*ParseResult)->toFeatureVector());
}
/// Return true if has this feature, need to sync with handleTargetFeatures.
diff --git a/clang/lib/Basic/Targets/Sparc.cpp b/clang/lib/Basic/Targets/Sparc.cpp
index 5eeb77406c34..932102434801 100644
--- a/clang/lib/Basic/Targets/Sparc.cpp
+++ b/clang/lib/Basic/Targets/Sparc.cpp
@@ -156,8 +156,6 @@ void SparcV8TargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__sparcv8__");
break;
case CG_V9:
- Builder.defineMacro("__sparcv9");
- Builder.defineMacro("__sparcv9__");
Builder.defineMacro("__sparc_v9__");
break;
}
diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h
index c952b8c9a336..d1b66432e38b 100644
--- a/clang/lib/Basic/Targets/X86.h
+++ b/clang/lib/Basic/Targets/X86.h
@@ -533,11 +533,12 @@ public:
DoubleAlign = LongLongAlign = 64;
bool IsWinCOFF =
getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF();
- resetDataLayout(IsWinCOFF ? "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:"
- "64-i64:64-f80:32-n8:16:32-a:0:32-S32"
- : "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:"
- "64-i64:64-f80:32-n8:16:32-a:0:32-S32",
- IsWinCOFF ? "_" : "");
+ bool IsMSVC = getTriple().isWindowsMSVCEnvironment();
+ std::string Layout = IsWinCOFF ? "e-m:x" : "e-m:e";
+ Layout += "-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-";
+ Layout += IsMSVC ? "f80:128" : "f80:32";
+ Layout += "-n8:16:32-a:0:32-S32";
+ resetDataLayout(Layout, IsWinCOFF ? "_" : "");
}
};
diff --git a/clang/lib/CodeGen/Address.h b/clang/lib/CodeGen/Address.h
index 37c20291c0e8..3ac0f4f0d7e5 100644
--- a/clang/lib/CodeGen/Address.h
+++ b/clang/lib/CodeGen/Address.h
@@ -14,30 +14,77 @@
#ifndef LLVM_CLANG_LIB_CODEGEN_ADDRESS_H
#define LLVM_CLANG_LIB_CODEGEN_ADDRESS_H
-#include "llvm/IR/Constants.h"
#include "clang/AST/CharUnits.h"
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/Support/MathExtras.h"
namespace clang {
namespace CodeGen {
-/// An aligned address.
-class Address {
+// We try to save some space by using 6 bits over two PointerIntPairs to store
+// the alignment. However, some arches don't support 3 bits in a PointerIntPair
+// so we fallback to storing the alignment separately.
+template <typename T, bool = alignof(llvm::Value *) >= 8> class AddressImpl {};
+
+template <typename T> class AddressImpl<T, false> {
llvm::Value *Pointer;
llvm::Type *ElementType;
CharUnits Alignment;
+public:
+ AddressImpl(llvm::Value *Pointer, llvm::Type *ElementType,
+ CharUnits Alignment)
+ : Pointer(Pointer), ElementType(ElementType), Alignment(Alignment) {}
+ llvm::Value *getPointer() const { return Pointer; }
+ llvm::Type *getElementType() const { return ElementType; }
+ CharUnits getAlignment() const { return Alignment; }
+};
+
+template <typename T> class AddressImpl<T, true> {
+ // Int portion stores upper 3 bits of the log of the alignment.
+ llvm::PointerIntPair<llvm::Value *, 3, unsigned> Pointer;
+ // Int portion stores lower 3 bits of the log of the alignment.
+ llvm::PointerIntPair<llvm::Type *, 3, unsigned> ElementType;
+
+public:
+ AddressImpl(llvm::Value *Pointer, llvm::Type *ElementType,
+ CharUnits Alignment)
+ : Pointer(Pointer), ElementType(ElementType) {
+ if (Alignment.isZero())
+ return;
+ // Currently the max supported alignment is much less than 1 << 63 and is
+ // guaranteed to be a power of 2, so we can store the log of the alignment
+ // into 6 bits.
+ assert(Alignment.isPowerOfTwo() && "Alignment cannot be zero");
+ auto AlignLog = llvm::Log2_64(Alignment.getQuantity());
+ assert(AlignLog < (1 << 6) && "cannot fit alignment into 6 bits");
+ this->Pointer.setInt(AlignLog >> 3);
+ this->ElementType.setInt(AlignLog & 7);
+ }
+ llvm::Value *getPointer() const { return Pointer.getPointer(); }
+ llvm::Type *getElementType() const { return ElementType.getPointer(); }
+ CharUnits getAlignment() const {
+ unsigned AlignLog = (Pointer.getInt() << 3) | ElementType.getInt();
+ return CharUnits::fromQuantity(CharUnits::QuantityType(1) << AlignLog);
+ }
+};
+
+/// An aligned address.
+class Address {
+ AddressImpl<void> A;
+
protected:
- Address(std::nullptr_t) : Pointer(nullptr), ElementType(nullptr) {}
+ Address(std::nullptr_t) : A(nullptr, nullptr, CharUnits::Zero()) {}
public:
- Address(llvm::Value *pointer, llvm::Type *elementType, CharUnits alignment)
- : Pointer(pointer), ElementType(elementType), Alignment(alignment) {
- assert(pointer != nullptr && "Pointer cannot be null");
- assert(elementType != nullptr && "Element type cannot be null");
- assert(llvm::cast<llvm::PointerType>(pointer->getType())
- ->isOpaqueOrPointeeTypeMatches(elementType) &&
+ Address(llvm::Value *Pointer, llvm::Type *ElementType, CharUnits Alignment)
+ : A(Pointer, ElementType, Alignment) {
+ assert(Pointer != nullptr && "Pointer cannot be null");
+ assert(ElementType != nullptr && "Element type cannot be null");
+ assert(llvm::cast<llvm::PointerType>(Pointer->getType())
+ ->isOpaqueOrPointeeTypeMatches(ElementType) &&
"Incorrect pointer element type");
- assert(!alignment.isZero() && "Alignment cannot be zero");
}
// Deprecated: Use constructor with explicit element type instead.
@@ -46,11 +93,11 @@ public:
Alignment) {}
static Address invalid() { return Address(nullptr); }
- bool isValid() const { return Pointer != nullptr; }
+ bool isValid() const { return A.getPointer() != nullptr; }
llvm::Value *getPointer() const {
assert(isValid());
- return Pointer;
+ return A.getPointer();
}
/// Return the type of the pointer value.
@@ -61,7 +108,7 @@ public:
/// Return the type of the values stored in this address.
llvm::Type *getElementType() const {
assert(isValid());
- return ElementType;
+ return A.getElementType();
}
/// Return the address space that this address resides in.
@@ -77,19 +124,19 @@ public:
/// Return the alignment of this pointer.
CharUnits getAlignment() const {
assert(isValid());
- return Alignment;
+ return A.getAlignment();
}
/// Return address with different pointer, but same element type and
/// alignment.
Address withPointer(llvm::Value *NewPointer) const {
- return Address(NewPointer, ElementType, Alignment);
+ return Address(NewPointer, getElementType(), getAlignment());
}
/// Return address with different alignment, but same pointer and element
/// type.
Address withAlignment(CharUnits NewAlignment) const {
- return Address(Pointer, ElementType, NewAlignment);
+ return Address(getPointer(), getElementType(), NewAlignment);
}
};
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index bacac0a20d4d..9ae5c870afc8 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -197,8 +197,7 @@ public:
PassManagerBuilderWrapper(const Triple &TargetTriple,
const CodeGenOptions &CGOpts,
const LangOptions &LangOpts)
- : PassManagerBuilder(), TargetTriple(TargetTriple), CGOpts(CGOpts),
- LangOpts(LangOpts) {}
+ : TargetTriple(TargetTriple), CGOpts(CGOpts), LangOpts(LangOpts) {}
const Triple &getTargetTriple() const { return TargetTriple; }
const CodeGenOptions &getCGOpts() const { return CGOpts; }
const LangOptions &getLangOpts() const { return LangOpts; }
@@ -359,7 +358,8 @@ static void addGeneralOptsForMemorySanitizer(const PassManagerBuilder &Builder,
int TrackOrigins = CGOpts.SanitizeMemoryTrackOrigins;
bool Recover = CGOpts.SanitizeRecover.has(SanitizerKind::Memory);
PM.add(createMemorySanitizerLegacyPassPass(
- MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel}));
+ MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel,
+ CGOpts.SanitizeMemoryParamRetval != 0}));
// MemorySanitizer inserts complex instrumentation that mostly follows
// the logic of the original code, but operates on "shadow" values.
@@ -645,6 +645,7 @@ static bool initTargetOptions(DiagnosticsEngine &Diags,
Options.MCOptions.CommandLineArgs = CodeGenOpts.CommandLineArgs;
Options.DebugStrictDwarf = CodeGenOpts.DebugStrictDwarf;
Options.ObjectFilenameForDebug = CodeGenOpts.ObjectFilenameForDebug;
+ Options.Hotpatch = CodeGenOpts.HotPatch;
return true;
}
@@ -1164,11 +1165,11 @@ static void addSanitizers(const Triple &TargetTriple,
int TrackOrigins = CodeGenOpts.SanitizeMemoryTrackOrigins;
bool Recover = CodeGenOpts.SanitizeRecover.has(Mask);
- MPM.addPass(
- ModuleMemorySanitizerPass({TrackOrigins, Recover, CompileKernel}));
+ MemorySanitizerOptions options(TrackOrigins, Recover, CompileKernel,
+ CodeGenOpts.SanitizeMemoryParamRetval);
+ MPM.addPass(ModuleMemorySanitizerPass(options));
FunctionPassManager FPM;
- FPM.addPass(
- MemorySanitizerPass({TrackOrigins, Recover, CompileKernel}));
+ FPM.addPass(MemorySanitizerPass(options));
if (Level != OptimizationLevel::O0) {
// MemorySanitizer inserts complex instrumentation that mostly
// follows the logic of the original code, but operates on
@@ -1491,8 +1492,11 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
}
// Now that we have all of the passes ready, run them.
- PrettyStackTraceString CrashInfo("Optimizer");
- MPM.run(*TheModule, MAM);
+ {
+ PrettyStackTraceString CrashInfo("Optimizer");
+ llvm::TimeTraceScope TimeScope("Optimizer");
+ MPM.run(*TheModule, MAM);
+ }
}
void EmitAssemblyHelper::RunCodegenPipeline(
@@ -1524,8 +1528,11 @@ void EmitAssemblyHelper::RunCodegenPipeline(
return;
}
- PrettyStackTraceString CrashInfo("Code generation");
- CodeGenPasses.run(*TheModule);
+ {
+ PrettyStackTraceString CrashInfo("Code generation");
+ llvm::TimeTraceScope TimeScope("CodeGenPasses");
+ CodeGenPasses.run(*TheModule);
+ }
}
/// A clean version of `EmitAssembly` that uses the new pass manager.
diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp
index e81c5ba5055c..10569ae2c3f9 100644
--- a/clang/lib/CodeGen/CGAtomic.cpp
+++ b/clang/lib/CodeGen/CGAtomic.cpp
@@ -307,7 +307,7 @@ static RValue emitAtomicLibcall(CodeGenFunction &CGF,
const CGFunctionInfo &fnInfo =
CGF.CGM.getTypes().arrangeBuiltinFunctionCall(resultType, args);
llvm::FunctionType *fnTy = CGF.CGM.getTypes().GetFunctionType(fnInfo);
- llvm::AttrBuilder fnAttrB;
+ llvm::AttrBuilder fnAttrB(CGF.getLLVMContext());
fnAttrB.addAttribute(llvm::Attribute::NoUnwind);
fnAttrB.addAttribute(llvm::Attribute::WillReturn);
llvm::AttributeList fnAttrs = llvm::AttributeList::get(
@@ -351,12 +351,12 @@ bool AtomicInfo::requiresMemSetZero(llvm::Type *type) const {
bool AtomicInfo::emitMemSetZeroIfNecessary() const {
assert(LVal.isSimple());
- llvm::Value *addr = LVal.getPointer(CGF);
- if (!requiresMemSetZero(addr->getType()->getPointerElementType()))
+ Address addr = LVal.getAddress(CGF);
+ if (!requiresMemSetZero(addr.getElementType()))
return false;
CGF.Builder.CreateMemSet(
- addr, llvm::ConstantInt::get(CGF.Int8Ty, 0),
+ addr.getPointer(), llvm::ConstantInt::get(CGF.Int8Ty, 0),
CGF.getContext().toCharUnitsFromBits(AtomicSizeInBits).getQuantity(),
LVal.getAlignment().getAsAlign());
return true;
@@ -1522,7 +1522,7 @@ RValue AtomicInfo::ConvertIntToValueOrAtomic(llvm::Value *IntVal,
!AsValue)) {
auto *ValTy = AsValue
? CGF.ConvertTypeForMem(ValueTy)
- : getAtomicAddress().getType()->getPointerElementType();
+ : getAtomicAddress().getElementType();
if (ValTy->isIntegerTy()) {
assert(IntVal->getType() == ValTy && "Different integer types.");
return RValue::get(CGF.EmitFromMemory(IntVal, ValueTy));
diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp
index 7bb6dbb8a8ac..1f1de3df857c 100644
--- a/clang/lib/CodeGen/CGBlocks.cpp
+++ b/clang/lib/CodeGen/CGBlocks.cpp
@@ -33,10 +33,10 @@ using namespace clang;
using namespace CodeGen;
CGBlockInfo::CGBlockInfo(const BlockDecl *block, StringRef name)
- : Name(name), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false),
- HasCXXObject(false), UsesStret(false), HasCapturedVariableLayout(false),
- CapturesNonExternalType(false), LocalAddress(Address::invalid()),
- StructureType(nullptr), Block(block) {
+ : Name(name), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false),
+ NoEscape(false), HasCXXObject(false), UsesStret(false),
+ HasCapturedVariableLayout(false), CapturesNonExternalType(false),
+ LocalAddress(Address::invalid()), StructureType(nullptr), Block(block) {
// Skip asm prefix, if any. 'name' is usually taken directly from
// the mangled name of the enclosing function.
@@ -66,17 +66,6 @@ static llvm::Constant *buildDisposeHelper(CodeGenModule &CGM,
namespace {
-/// Represents a type of copy/destroy operation that should be performed for an
-/// entity that's captured by a block.
-enum class BlockCaptureEntityKind {
- CXXRecord, // Copy or destroy
- ARCWeak,
- ARCStrong,
- NonTrivialCStruct,
- BlockObject, // Assign or release
- None
-};
-
/// Represents a captured entity that requires extra operations in order for
/// this entity to be copied or destroyed correctly.
struct BlockCaptureManagedEntity {
@@ -110,11 +99,7 @@ enum class CaptureStrKind {
} // end anonymous namespace
-static void findBlockCapturedManagedEntities(
- const CGBlockInfo &BlockInfo, const LangOptions &LangOpts,
- SmallVectorImpl<BlockCaptureManagedEntity> &ManagedCaptures);
-
-static std::string getBlockCaptureStr(const BlockCaptureManagedEntity &E,
+static std::string getBlockCaptureStr(const CGBlockInfo::Capture &Cap,
CaptureStrKind StrKind,
CharUnits BlockAlignment,
CodeGenModule &CGM);
@@ -124,34 +109,33 @@ static std::string getBlockDescriptorName(const CGBlockInfo &BlockInfo,
std::string Name = "__block_descriptor_";
Name += llvm::to_string(BlockInfo.BlockSize.getQuantity()) + "_";
- if (BlockInfo.needsCopyDisposeHelpers()) {
+ if (BlockInfo.NeedsCopyDispose) {
if (CGM.getLangOpts().Exceptions)
Name += "e";
if (CGM.getCodeGenOpts().ObjCAutoRefCountExceptions)
Name += "a";
Name += llvm::to_string(BlockInfo.BlockAlign.getQuantity()) + "_";
- SmallVector<BlockCaptureManagedEntity, 4> ManagedCaptures;
- findBlockCapturedManagedEntities(BlockInfo, CGM.getContext().getLangOpts(),
- ManagedCaptures);
+ for (auto &Cap : BlockInfo.SortedCaptures) {
+ if (Cap.isConstantOrTrivial())
+ continue;
- for (const BlockCaptureManagedEntity &E : ManagedCaptures) {
- Name += llvm::to_string(E.Capture->getOffset().getQuantity());
+ Name += llvm::to_string(Cap.getOffset().getQuantity());
- if (E.CopyKind == E.DisposeKind) {
+ if (Cap.CopyKind == Cap.DisposeKind) {
// If CopyKind and DisposeKind are the same, merge the capture
// information.
- assert(E.CopyKind != BlockCaptureEntityKind::None &&
+ assert(Cap.CopyKind != BlockCaptureEntityKind::None &&
"shouldn't see BlockCaptureManagedEntity that is None");
- Name += getBlockCaptureStr(E, CaptureStrKind::Merged,
+ Name += getBlockCaptureStr(Cap, CaptureStrKind::Merged,
BlockInfo.BlockAlign, CGM);
} else {
// If CopyKind and DisposeKind are not the same, which can happen when
// either Kind is None or the captured object is a __strong block,
// concatenate the copy and dispose strings.
- Name += getBlockCaptureStr(E, CaptureStrKind::CopyHelper,
+ Name += getBlockCaptureStr(Cap, CaptureStrKind::CopyHelper,
BlockInfo.BlockAlign, CGM);
- Name += getBlockCaptureStr(E, CaptureStrKind::DisposeHelper,
+ Name += getBlockCaptureStr(Cap, CaptureStrKind::DisposeHelper,
BlockInfo.BlockAlign, CGM);
}
}
@@ -223,7 +207,7 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM,
// Optional copy/dispose helpers.
bool hasInternalHelper = false;
- if (blockInfo.needsCopyDisposeHelpers()) {
+ if (blockInfo.NeedsCopyDispose) {
// copy_func_helper_decl
llvm::Constant *copyHelper = buildCopyHelper(CGM, blockInfo);
elements.add(copyHelper);
@@ -340,17 +324,21 @@ namespace {
struct BlockLayoutChunk {
CharUnits Alignment;
CharUnits Size;
- Qualifiers::ObjCLifetime Lifetime;
const BlockDecl::Capture *Capture; // null for 'this'
llvm::Type *Type;
QualType FieldType;
+ BlockCaptureEntityKind CopyKind, DisposeKind;
+ BlockFieldFlags CopyFlags, DisposeFlags;
BlockLayoutChunk(CharUnits align, CharUnits size,
- Qualifiers::ObjCLifetime lifetime,
- const BlockDecl::Capture *capture,
- llvm::Type *type, QualType fieldType)
- : Alignment(align), Size(size), Lifetime(lifetime),
- Capture(capture), Type(type), FieldType(fieldType) {}
+ const BlockDecl::Capture *capture, llvm::Type *type,
+ QualType fieldType, BlockCaptureEntityKind CopyKind,
+ BlockFieldFlags CopyFlags,
+ BlockCaptureEntityKind DisposeKind,
+ BlockFieldFlags DisposeFlags)
+ : Alignment(align), Size(size), Capture(capture), Type(type),
+ FieldType(fieldType), CopyKind(CopyKind), DisposeKind(DisposeKind),
+ CopyFlags(CopyFlags), DisposeFlags(DisposeFlags) {}
/// Tell the block info that this chunk has the given field index.
void setIndex(CGBlockInfo &info, unsigned index, CharUnits offset) {
@@ -358,32 +346,93 @@ namespace {
info.CXXThisIndex = index;
info.CXXThisOffset = offset;
} else {
- auto C = CGBlockInfo::Capture::makeIndex(index, offset, FieldType);
- info.Captures.insert({Capture->getVariable(), C});
+ info.SortedCaptures.push_back(CGBlockInfo::Capture::makeIndex(
+ index, offset, FieldType, CopyKind, CopyFlags, DisposeKind,
+ DisposeFlags, Capture));
}
}
+
+ bool isTrivial() const {
+ return CopyKind == BlockCaptureEntityKind::None &&
+ DisposeKind == BlockCaptureEntityKind::None;
+ }
};
- /// Order by 1) all __strong together 2) next, all byfref together 3) next,
- /// all __weak together. Preserve descending alignment in all situations.
+ /// Order by 1) all __strong together 2) next, all block together 3) next,
+ /// all byref together 4) next, all __weak together. Preserve descending
+ /// alignment in all situations.
bool operator<(const BlockLayoutChunk &left, const BlockLayoutChunk &right) {
if (left.Alignment != right.Alignment)
return left.Alignment > right.Alignment;
auto getPrefOrder = [](const BlockLayoutChunk &chunk) {
- if (chunk.Capture && chunk.Capture->isByRef())
- return 1;
- if (chunk.Lifetime == Qualifiers::OCL_Strong)
+ switch (chunk.CopyKind) {
+ case BlockCaptureEntityKind::ARCStrong:
return 0;
- if (chunk.Lifetime == Qualifiers::OCL_Weak)
- return 2;
- return 3;
+ case BlockCaptureEntityKind::BlockObject:
+ switch (chunk.CopyFlags.getBitMask()) {
+ case BLOCK_FIELD_IS_OBJECT:
+ return 0;
+ case BLOCK_FIELD_IS_BLOCK:
+ return 1;
+ case BLOCK_FIELD_IS_BYREF:
+ return 2;
+ default:
+ break;
+ }
+ break;
+ case BlockCaptureEntityKind::ARCWeak:
+ return 3;
+ default:
+ break;
+ }
+ return 4;
};
return getPrefOrder(left) < getPrefOrder(right);
}
} // end anonymous namespace
+static std::pair<BlockCaptureEntityKind, BlockFieldFlags>
+computeCopyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T,
+ const LangOptions &LangOpts);
+
+static std::pair<BlockCaptureEntityKind, BlockFieldFlags>
+computeDestroyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T,
+ const LangOptions &LangOpts);
+
+static void addBlockLayout(CharUnits align, CharUnits size,
+ const BlockDecl::Capture *capture, llvm::Type *type,
+ QualType fieldType,
+ SmallVectorImpl<BlockLayoutChunk> &Layout,
+ CGBlockInfo &Info, CodeGenModule &CGM) {
+ if (!capture) {
+ // 'this' capture.
+ Layout.push_back(BlockLayoutChunk(
+ align, size, capture, type, fieldType, BlockCaptureEntityKind::None,
+ BlockFieldFlags(), BlockCaptureEntityKind::None, BlockFieldFlags()));
+ return;
+ }
+
+ const LangOptions &LangOpts = CGM.getLangOpts();
+ BlockCaptureEntityKind CopyKind, DisposeKind;
+ BlockFieldFlags CopyFlags, DisposeFlags;
+
+ std::tie(CopyKind, CopyFlags) =
+ computeCopyInfoForBlockCapture(*capture, fieldType, LangOpts);
+ std::tie(DisposeKind, DisposeFlags) =
+ computeDestroyInfoForBlockCapture(*capture, fieldType, LangOpts);
+ Layout.push_back(BlockLayoutChunk(align, size, capture, type, fieldType,
+ CopyKind, CopyFlags, DisposeKind,
+ DisposeFlags));
+
+ if (Info.NoEscape)
+ return;
+
+ if (!Layout.back().isTrivial())
+ Info.NeedsCopyDispose = true;
+}
+
/// Determines if the given type is safe for constant capture in C++.
static bool isSafeForCXXConstantCapture(QualType type) {
const RecordType *recordType =
@@ -541,6 +590,9 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
CGM.getLangOpts().getGC() == LangOptions::NonGC)
info.HasCapturedVariableLayout = true;
+ if (block->doesNotEscape())
+ info.NoEscape = true;
+
// Collect the layout chunks.
SmallVector<BlockLayoutChunk, 16> layout;
layout.reserve(block->capturesCXXThis() +
@@ -560,9 +612,8 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
auto TInfo = CGM.getContext().getTypeInfoInChars(thisType);
maxFieldAlign = std::max(maxFieldAlign, TInfo.Align);
- layout.push_back(BlockLayoutChunk(TInfo.Align, TInfo.Width,
- Qualifiers::OCL_None,
- nullptr, llvmType, thisType));
+ addBlockLayout(TInfo.Align, TInfo.Width, nullptr, llvmType, thisType,
+ layout, info, CGM);
}
// Next, all the block captures.
@@ -570,9 +621,6 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
const VarDecl *variable = CI.getVariable();
if (CI.isEscapingByref()) {
- // We have to copy/dispose of the __block reference.
- info.NeedsCopyDispose = true;
-
// Just use void* instead of a pointer to the byref type.
CharUnits align = CGM.getPointerAlign();
maxFieldAlign = std::max(maxFieldAlign, align);
@@ -581,72 +629,28 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
// the capture field type should always match.
assert(CGF && getCaptureFieldType(*CGF, CI) == variable->getType() &&
"capture type differs from the variable type");
- layout.push_back(BlockLayoutChunk(align, CGM.getPointerSize(),
- Qualifiers::OCL_None, &CI,
- CGM.VoidPtrTy, variable->getType()));
+ addBlockLayout(align, CGM.getPointerSize(), &CI, CGM.VoidPtrTy,
+ variable->getType(), layout, info, CGM);
continue;
}
// Otherwise, build a layout chunk with the size and alignment of
// the declaration.
if (llvm::Constant *constant = tryCaptureAsConstant(CGM, CGF, variable)) {
- info.Captures[variable] = CGBlockInfo::Capture::makeConstant(constant);
+ info.SortedCaptures.push_back(
+ CGBlockInfo::Capture::makeConstant(constant, &CI));
continue;
}
QualType VT = getCaptureFieldType(*CGF, CI);
- // If we have a lifetime qualifier, honor it for capture purposes.
- // That includes *not* copying it if it's __unsafe_unretained.
- Qualifiers::ObjCLifetime lifetime = VT.getObjCLifetime();
- if (lifetime) {
- switch (lifetime) {
- case Qualifiers::OCL_None: llvm_unreachable("impossible");
- case Qualifiers::OCL_ExplicitNone:
- case Qualifiers::OCL_Autoreleasing:
- break;
-
- case Qualifiers::OCL_Strong:
- case Qualifiers::OCL_Weak:
- info.NeedsCopyDispose = true;
- }
-
- // Block pointers require copy/dispose. So do Objective-C pointers.
- } else if (VT->isObjCRetainableType()) {
- // But honor the inert __unsafe_unretained qualifier, which doesn't
- // actually make it into the type system.
- if (VT->isObjCInertUnsafeUnretainedType()) {
- lifetime = Qualifiers::OCL_ExplicitNone;
- } else {
- info.NeedsCopyDispose = true;
- // used for mrr below.
- lifetime = Qualifiers::OCL_Strong;
- }
-
- // So do types that require non-trivial copy construction.
- } else if (CI.hasCopyExpr()) {
- info.NeedsCopyDispose = true;
- info.HasCXXObject = true;
- if (!VT->getAsCXXRecordDecl()->isExternallyVisible())
- info.CapturesNonExternalType = true;
-
- // So do C structs that require non-trivial copy construction or
- // destruction.
- } else if (VT.isNonTrivialToPrimitiveCopy() == QualType::PCK_Struct ||
- VT.isDestructedType() == QualType::DK_nontrivial_c_struct) {
- info.NeedsCopyDispose = true;
-
- // And so do types with destructors.
- } else if (CGM.getLangOpts().CPlusPlus) {
- if (const CXXRecordDecl *record = VT->getAsCXXRecordDecl()) {
- if (!record->hasTrivialDestructor()) {
+ if (CGM.getLangOpts().CPlusPlus)
+ if (const CXXRecordDecl *record = VT->getAsCXXRecordDecl())
+ if (CI.hasCopyExpr() || !record->hasTrivialDestructor()) {
info.HasCXXObject = true;
- info.NeedsCopyDispose = true;
if (!record->isExternallyVisible())
info.CapturesNonExternalType = true;
}
- }
- }
CharUnits size = C.getTypeSizeInChars(VT);
CharUnits align = C.getDeclAlign(variable);
@@ -656,8 +660,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
llvm::Type *llvmType =
CGM.getTypes().ConvertTypeForMem(VT);
- layout.push_back(
- BlockLayoutChunk(align, size, lifetime, &CI, llvmType, VT));
+ addBlockLayout(align, size, &CI, llvmType, VT, layout, info, CGM);
}
// If that was everything, we're done here.
@@ -665,6 +668,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
info.StructureType =
llvm::StructType::get(CGM.getLLVMContext(), elementTypes, true);
info.CanBeGlobal = true;
+ info.buildCaptureMap();
return;
}
@@ -718,6 +722,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
// ...until we get to the alignment of the maximum field.
if (endAlign >= maxFieldAlign) {
+ ++li;
break;
}
}
@@ -770,6 +775,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
endAlign = getLowBit(blockSize);
}
+ info.buildCaptureMap();
info.StructureType =
llvm::StructType::get(CGM.getLLVMContext(), elementTypes, true);
}
@@ -826,7 +832,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
// If the block is non-escaping, set field 'isa 'to NSConcreteGlobalBlock
// and set the BLOCK_IS_GLOBAL bit of field 'flags'. Copying a non-escaping
// block just returns the original block and releasing it is a no-op.
- llvm::Constant *blockISA = blockInfo.getBlockDecl()->doesNotEscape()
+ llvm::Constant *blockISA = blockInfo.NoEscape
? CGM.getNSConcreteGlobalBlock()
: CGM.getNSConcreteStackBlock();
isa = llvm::ConstantExpr::getBitCast(blockISA, VoidPtrTy);
@@ -838,13 +844,13 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
flags = BLOCK_HAS_SIGNATURE;
if (blockInfo.HasCapturedVariableLayout)
flags |= BLOCK_HAS_EXTENDED_LAYOUT;
- if (blockInfo.needsCopyDisposeHelpers())
+ if (blockInfo.NeedsCopyDispose)
flags |= BLOCK_HAS_COPY_DISPOSE;
if (blockInfo.HasCXXObject)
flags |= BLOCK_HAS_CXX_OBJ;
if (blockInfo.UsesStret)
flags |= BLOCK_USE_STRET;
- if (blockInfo.getBlockDecl()->doesNotEscape())
+ if (blockInfo.NoEscape)
flags |= BLOCK_IS_NOESCAPE | BLOCK_IS_GLOBAL;
}
@@ -1033,7 +1039,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
}
// Push a cleanup for the capture if necessary.
- if (!blockInfo.NeedsCopyDispose)
+ if (!blockInfo.NoEscape && !blockInfo.NeedsCopyDispose)
continue;
// Ignore __block captures; there's nothing special in the on-stack block
@@ -1654,6 +1660,11 @@ computeCopyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T,
// For all other types, the memcpy is fine.
return std::make_pair(BlockCaptureEntityKind::None, BlockFieldFlags());
+ // Honor the inert __unsafe_unretained qualifier, which doesn't actually
+ // make it into the type system.
+ if (T->isObjCInertUnsafeUnretainedType())
+ return std::make_pair(BlockCaptureEntityKind::None, BlockFieldFlags());
+
// Special rules for ARC captures:
Qualifiers QS = T.getQualifiers();
@@ -1669,34 +1680,6 @@ computeCopyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T,
llvm_unreachable("after exhaustive PrimitiveCopyKind switch");
}
-static std::pair<BlockCaptureEntityKind, BlockFieldFlags>
-computeDestroyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T,
- const LangOptions &LangOpts);
-
-/// Find the set of block captures that need to be explicitly copied or destroy.
-static void findBlockCapturedManagedEntities(
- const CGBlockInfo &BlockInfo, const LangOptions &LangOpts,
- SmallVectorImpl<BlockCaptureManagedEntity> &ManagedCaptures) {
- for (const auto &CI : BlockInfo.getBlockDecl()->captures()) {
- const VarDecl *Variable = CI.getVariable();
- const CGBlockInfo::Capture &Capture = BlockInfo.getCapture(Variable);
- if (Capture.isConstant())
- continue;
-
- QualType VT = Capture.fieldType();
- auto CopyInfo = computeCopyInfoForBlockCapture(CI, VT, LangOpts);
- auto DisposeInfo = computeDestroyInfoForBlockCapture(CI, VT, LangOpts);
- if (CopyInfo.first != BlockCaptureEntityKind::None ||
- DisposeInfo.first != BlockCaptureEntityKind::None)
- ManagedCaptures.emplace_back(CopyInfo.first, DisposeInfo.first,
- CopyInfo.second, DisposeInfo.second, CI,
- Capture);
- }
-
- // Sort the captures by offset.
- llvm::sort(ManagedCaptures);
-}
-
namespace {
/// Release a __block variable.
struct CallBlockRelease final : EHScopeStack::Cleanup {
@@ -1732,13 +1715,13 @@ bool CodeGenFunction::cxxDestructorCanThrow(QualType T) {
}
// Return a string that has the information about a capture.
-static std::string getBlockCaptureStr(const BlockCaptureManagedEntity &E,
+static std::string getBlockCaptureStr(const CGBlockInfo::Capture &Cap,
CaptureStrKind StrKind,
CharUnits BlockAlignment,
CodeGenModule &CGM) {
std::string Str;
ASTContext &Ctx = CGM.getContext();
- const BlockDecl::Capture &CI = *E.CI;
+ const BlockDecl::Capture &CI = *Cap.Cap;
QualType CaptureTy = CI.getVariable()->getType();
BlockCaptureEntityKind Kind;
@@ -1747,15 +1730,16 @@ static std::string getBlockCaptureStr(const BlockCaptureManagedEntity &E,
// CaptureStrKind::Merged should be passed only when the operations and the
// flags are the same for copy and dispose.
assert((StrKind != CaptureStrKind::Merged ||
- (E.CopyKind == E.DisposeKind && E.CopyFlags == E.DisposeFlags)) &&
+ (Cap.CopyKind == Cap.DisposeKind &&
+ Cap.CopyFlags == Cap.DisposeFlags)) &&
"different operations and flags");
if (StrKind == CaptureStrKind::DisposeHelper) {
- Kind = E.DisposeKind;
- Flags = E.DisposeFlags;
+ Kind = Cap.DisposeKind;
+ Flags = Cap.DisposeFlags;
} else {
- Kind = E.CopyKind;
- Flags = E.CopyFlags;
+ Kind = Cap.CopyKind;
+ Flags = Cap.CopyFlags;
}
switch (Kind) {
@@ -1803,8 +1787,7 @@ static std::string getBlockCaptureStr(const BlockCaptureManagedEntity &E,
}
case BlockCaptureEntityKind::NonTrivialCStruct: {
bool IsVolatile = CaptureTy.isVolatileQualified();
- CharUnits Alignment =
- BlockAlignment.alignmentAtOffset(E.Capture->getOffset());
+ CharUnits Alignment = BlockAlignment.alignmentAtOffset(Cap.getOffset());
Str += "n";
std::string FuncStr;
@@ -1829,7 +1812,7 @@ static std::string getBlockCaptureStr(const BlockCaptureManagedEntity &E,
}
static std::string getCopyDestroyHelperFuncName(
- const SmallVectorImpl<BlockCaptureManagedEntity> &Captures,
+ const SmallVectorImpl<CGBlockInfo::Capture> &Captures,
CharUnits BlockAlignment, CaptureStrKind StrKind, CodeGenModule &CGM) {
assert((StrKind == CaptureStrKind::CopyHelper ||
StrKind == CaptureStrKind::DisposeHelper) &&
@@ -1843,9 +1826,11 @@ static std::string getCopyDestroyHelperFuncName(
Name += "a";
Name += llvm::to_string(BlockAlignment.getQuantity()) + "_";
- for (const BlockCaptureManagedEntity &E : Captures) {
- Name += llvm::to_string(E.Capture->getOffset().getQuantity());
- Name += getBlockCaptureStr(E, StrKind, BlockAlignment, CGM);
+ for (auto &Cap : Captures) {
+ if (Cap.isConstantOrTrivial())
+ continue;
+ Name += llvm::to_string(Cap.getOffset().getQuantity());
+ Name += getBlockCaptureStr(Cap, StrKind, BlockAlignment, CGM);
}
return Name;
@@ -1916,11 +1901,9 @@ static void setBlockHelperAttributesVisibility(bool CapturesNonExternalType,
/// the contents of an individual __block variable to the heap.
llvm::Constant *
CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
- SmallVector<BlockCaptureManagedEntity, 4> CopiedCaptures;
- findBlockCapturedManagedEntities(blockInfo, getLangOpts(), CopiedCaptures);
- std::string FuncName =
- getCopyDestroyHelperFuncName(CopiedCaptures, blockInfo.BlockAlign,
- CaptureStrKind::CopyHelper, CGM);
+ std::string FuncName = getCopyDestroyHelperFuncName(
+ blockInfo.SortedCaptures, blockInfo.BlockAlign,
+ CaptureStrKind::CopyHelper, CGM);
if (llvm::GlobalValue *Func = CGM.getModule().getNamedValue(FuncName))
return llvm::ConstantExpr::getBitCast(Func, VoidPtrTy);
@@ -1967,17 +1950,19 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
dst = Address(Builder.CreateLoad(dst), blockInfo.BlockAlign);
dst = Builder.CreateBitCast(dst, structPtrTy, "block.dest");
- for (const auto &CopiedCapture : CopiedCaptures) {
- const BlockDecl::Capture &CI = *CopiedCapture.CI;
- const CGBlockInfo::Capture &capture = *CopiedCapture.Capture;
+ for (auto &capture : blockInfo.SortedCaptures) {
+ if (capture.isConstantOrTrivial())
+ continue;
+
+ const BlockDecl::Capture &CI = *capture.Cap;
QualType captureType = CI.getVariable()->getType();
- BlockFieldFlags flags = CopiedCapture.CopyFlags;
+ BlockFieldFlags flags = capture.CopyFlags;
unsigned index = capture.getIndex();
Address srcField = Builder.CreateStructGEP(src, index);
Address dstField = Builder.CreateStructGEP(dst, index);
- switch (CopiedCapture.CopyKind) {
+ switch (capture.CopyKind) {
case BlockCaptureEntityKind::CXXRecord:
// If there's an explicit copy expression, we do that.
assert(CI.getCopyExpr() && "copy expression for variable is missing");
@@ -2040,7 +2025,7 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
// Ensure that we destroy the copied object if an exception is thrown later
// in the helper function.
- pushCaptureCleanup(CopiedCapture.CopyKind, dstField, captureType, flags,
+ pushCaptureCleanup(capture.CopyKind, dstField, captureType, flags,
/*ForCopyHelper*/ true, CI.getVariable(), *this);
}
@@ -2085,8 +2070,10 @@ computeDestroyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T,
BlockFieldFlags());
case QualType::DK_none: {
// Non-ARC captures are strong, and we need to use _Block_object_dispose.
+ // But honor the inert __unsafe_unretained qualifier, which doesn't actually
+ // make it into the type system.
if (T->isObjCRetainableType() && !T.getQualifiers().hasObjCLifetime() &&
- !LangOpts.ObjCAutoRefCount)
+ !LangOpts.ObjCAutoRefCount && !T->isObjCInertUnsafeUnretainedType())
return std::make_pair(BlockCaptureEntityKind::BlockObject,
getBlockFieldFlagsForObjCObjectPointer(CI, T));
// Otherwise, we have nothing to do.
@@ -2105,11 +2092,9 @@ computeDestroyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T,
/// variable.
llvm::Constant *
CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
- SmallVector<BlockCaptureManagedEntity, 4> DestroyedCaptures;
- findBlockCapturedManagedEntities(blockInfo, getLangOpts(), DestroyedCaptures);
- std::string FuncName =
- getCopyDestroyHelperFuncName(DestroyedCaptures, blockInfo.BlockAlign,
- CaptureStrKind::DisposeHelper, CGM);
+ std::string FuncName = getCopyDestroyHelperFuncName(
+ blockInfo.SortedCaptures, blockInfo.BlockAlign,
+ CaptureStrKind::DisposeHelper, CGM);
if (llvm::GlobalValue *Func = CGM.getModule().getNamedValue(FuncName))
return llvm::ConstantExpr::getBitCast(Func, VoidPtrTy);
@@ -2153,14 +2138,16 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
CodeGenFunction::RunCleanupsScope cleanups(*this);
- for (const auto &DestroyedCapture : DestroyedCaptures) {
- const BlockDecl::Capture &CI = *DestroyedCapture.CI;
- const CGBlockInfo::Capture &capture = *DestroyedCapture.Capture;
- BlockFieldFlags flags = DestroyedCapture.DisposeFlags;
+ for (auto &capture : blockInfo.SortedCaptures) {
+ if (capture.isConstantOrTrivial())
+ continue;
+
+ const BlockDecl::Capture &CI = *capture.Cap;
+ BlockFieldFlags flags = capture.DisposeFlags;
Address srcField = Builder.CreateStructGEP(src, capture.getIndex());
- pushCaptureCleanup(DestroyedCapture.DisposeKind, srcField,
+ pushCaptureCleanup(capture.DisposeKind, srcField,
CI.getVariable()->getType(), flags,
/*ForCopyHelper*/ false, CI.getVariable(), *this);
}
diff --git a/clang/lib/CodeGen/CGBlocks.h b/clang/lib/CodeGen/CGBlocks.h
index 698ecd3d926a..e8857d98894f 100644
--- a/clang/lib/CodeGen/CGBlocks.h
+++ b/clang/lib/CodeGen/CGBlocks.h
@@ -26,14 +26,7 @@
#include "clang/Basic/TargetInfo.h"
namespace llvm {
-class Constant;
-class Function;
-class GlobalValue;
-class DataLayout;
-class FunctionType;
-class PointerType;
class Value;
-class LLVMContext;
}
namespace clang {
@@ -148,6 +141,17 @@ public:
CharUnits FieldOffset;
};
+/// Represents a type of copy/destroy operation that should be performed for an
+/// entity that's captured by a block.
+enum class BlockCaptureEntityKind {
+ None,
+ CXXRecord, // Copy or destroy
+ ARCWeak,
+ ARCStrong,
+ NonTrivialCStruct,
+ BlockObject, // Assign or release
+};
+
/// CGBlockInfo - Information to generate a block literal.
class CGBlockInfo {
public:
@@ -197,20 +201,40 @@ public:
return FieldType;
}
- static Capture makeIndex(unsigned index, CharUnits offset,
- QualType FieldType) {
+ static Capture
+ makeIndex(unsigned index, CharUnits offset, QualType FieldType,
+ BlockCaptureEntityKind CopyKind, BlockFieldFlags CopyFlags,
+ BlockCaptureEntityKind DisposeKind, BlockFieldFlags DisposeFlags,
+ const BlockDecl::Capture *Cap) {
Capture v;
v.Data = (index << 1) | 1;
v.Offset = offset.getQuantity();
v.FieldType = FieldType;
+ v.CopyKind = CopyKind;
+ v.CopyFlags = CopyFlags;
+ v.DisposeKind = DisposeKind;
+ v.DisposeFlags = DisposeFlags;
+ v.Cap = Cap;
return v;
}
- static Capture makeConstant(llvm::Value *value) {
+ static Capture makeConstant(llvm::Value *value,
+ const BlockDecl::Capture *Cap) {
Capture v;
v.Data = reinterpret_cast<uintptr_t>(value);
+ v.Cap = Cap;
return v;
}
+
+ bool isConstantOrTrivial() const {
+ return CopyKind == BlockCaptureEntityKind::None &&
+ DisposeKind == BlockCaptureEntityKind::None;
+ }
+
+ BlockCaptureEntityKind CopyKind = BlockCaptureEntityKind::None,
+ DisposeKind = BlockCaptureEntityKind::None;
+ BlockFieldFlags CopyFlags, DisposeFlags;
+ const BlockDecl::Capture *Cap;
};
/// CanBeGlobal - True if the block can be global, i.e. it has
@@ -221,6 +245,9 @@ public:
/// dispose helper functions if the block were escaping.
bool NeedsCopyDispose : 1;
+ /// Indicates whether the block is non-escaping.
+ bool NoEscape : 1;
+
/// HasCXXObject - True if the block's custom copy/dispose functions
/// need to be run even in GC mode.
bool HasCXXObject : 1;
@@ -238,8 +265,11 @@ public:
/// functions.
bool CapturesNonExternalType : 1;
- /// The mapping of allocated indexes within the block.
- llvm::DenseMap<const VarDecl*, Capture> Captures;
+ /// Mapping from variables to pointers to captures in SortedCaptures.
+ llvm::DenseMap<const VarDecl *, Capture *> Captures;
+
+ /// The block's captures. Non-constant captures are sorted by their offsets.
+ llvm::SmallVector<Capture, 4> SortedCaptures;
Address LocalAddress;
llvm::StructType *StructureType;
@@ -263,14 +293,18 @@ public:
/// has been encountered.
CGBlockInfo *NextBlockInfo;
+ void buildCaptureMap() {
+ for (auto &C : SortedCaptures)
+ Captures[C.Cap->getVariable()] = &C;
+ }
+
const Capture &getCapture(const VarDecl *var) const {
return const_cast<CGBlockInfo*>(this)->getCapture(var);
}
Capture &getCapture(const VarDecl *var) {
- llvm::DenseMap<const VarDecl*, Capture>::iterator
- it = Captures.find(var);
+ auto it = Captures.find(var);
assert(it != Captures.end() && "no entry for variable!");
- return it->second;
+ return *it->second;
}
const BlockDecl *getBlockDecl() const { return Block; }
@@ -281,11 +315,6 @@ public:
}
CGBlockInfo(const BlockDecl *blockDecl, StringRef Name);
-
- // Indicates whether the block needs a custom copy or dispose function.
- bool needsCopyDisposeHelpers() const {
- return NeedsCopyDispose && !Block->doesNotEscape();
- }
};
} // end namespace CodeGen
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 1982b40ff667..2b7862e618bd 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -159,6 +159,7 @@ static Value *EmitFromInt(CodeGenFunction &CGF, llvm::Value *V,
static Value *MakeBinaryAtomicValue(
CodeGenFunction &CGF, llvm::AtomicRMWInst::BinOp Kind, const CallExpr *E,
AtomicOrdering Ordering = AtomicOrdering::SequentiallyConsistent) {
+
QualType T = E->getType();
assert(E->getArg(0)->getType()->isPointerType());
assert(CGF.getContext().hasSameUnqualifiedType(T,
@@ -532,13 +533,13 @@ static Value *emitCallMaybeConstrainedFPBuiltin(CodeGenFunction &CGF,
// 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,
- unsigned IntrinsicID) {
+static Value *emitUnaryBuiltin(CodeGenFunction &CGF, const CallExpr *E,
+ unsigned IntrinsicID,
+ llvm::StringRef Name = "") {
llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0));
Function *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType());
- return CGF.Builder.CreateCall(F, Src0);
+ return CGF.Builder.CreateCall(F, Src0, Name);
}
// Emit an intrinsic that has 2 operands of the same type as its result.
@@ -1060,7 +1061,10 @@ static llvm::Value *emitPPCLoadReserveIntrinsic(CodeGenFunction &CGF,
llvm::InlineAsm *IA =
llvm::InlineAsm::get(FTy, Asm, Constraints, /*hasSideEffects=*/true);
- return CGF.Builder.CreateCall(IA, {Addr});
+ llvm::CallInst *CI = CGF.Builder.CreateCall(IA, {Addr});
+ CI->addParamAttr(
+ 0, Attribute::get(CGF.getLLVMContext(), Attribute::ElementType, RetType));
+ return CI;
}
namespace {
@@ -3122,24 +3126,34 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
}
case Builtin::BI__builtin_elementwise_abs: {
- Value *Op0 = EmitScalarExpr(E->getArg(0));
Value *Result;
- if (Op0->getType()->isIntOrIntVectorTy())
+ QualType QT = E->getArg(0)->getType();
+
+ if (auto *VecTy = QT->getAs<VectorType>())
+ QT = VecTy->getElementType();
+ if (QT->isIntegerType())
Result = Builder.CreateBinaryIntrinsic(
- llvm::Intrinsic::abs, Op0, Builder.getFalse(), nullptr, "elt.abs");
+ llvm::Intrinsic::abs, EmitScalarExpr(E->getArg(0)),
+ Builder.getFalse(), nullptr, "elt.abs");
else
- Result = Builder.CreateUnaryIntrinsic(llvm::Intrinsic::fabs, Op0, nullptr,
- "elt.abs");
- return RValue::get(Result);
- }
+ Result = emitUnaryBuiltin(*this, E, llvm::Intrinsic::fabs, "elt.abs");
- case Builtin::BI__builtin_elementwise_ceil: {
- Value *Op0 = EmitScalarExpr(E->getArg(0));
- Value *Result = Builder.CreateUnaryIntrinsic(llvm::Intrinsic::ceil, Op0,
- nullptr, "elt.ceil");
return RValue::get(Result);
}
+ case Builtin::BI__builtin_elementwise_ceil:
+ return RValue::get(
+ emitUnaryBuiltin(*this, E, llvm::Intrinsic::ceil, "elt.ceil"));
+ case Builtin::BI__builtin_elementwise_floor:
+ return RValue::get(
+ emitUnaryBuiltin(*this, E, llvm::Intrinsic::floor, "elt.floor"));
+ case Builtin::BI__builtin_elementwise_roundeven:
+ return RValue::get(emitUnaryBuiltin(*this, E, llvm::Intrinsic::roundeven,
+ "elt.roundeven"));
+ case Builtin::BI__builtin_elementwise_trunc:
+ return RValue::get(
+ emitUnaryBuiltin(*this, E, llvm::Intrinsic::trunc, "elt.trunc"));
+
case Builtin::BI__builtin_elementwise_max: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
Value *Op1 = EmitScalarExpr(E->getArg(1));
@@ -3174,52 +3188,48 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
}
case Builtin::BI__builtin_reduce_max: {
- auto GetIntrinsicID = [](QualType QT, llvm::Type *IrTy) {
- if (IrTy->isIntOrIntVectorTy()) {
- if (auto *VecTy = QT->getAs<VectorType>())
- QT = VecTy->getElementType();
- if (QT->isSignedIntegerType())
- return llvm::Intrinsic::vector_reduce_smax;
- else
- return llvm::Intrinsic::vector_reduce_umax;
- }
+ auto GetIntrinsicID = [](QualType QT) {
+ if (auto *VecTy = QT->getAs<VectorType>())
+ QT = VecTy->getElementType();
+ if (QT->isSignedIntegerType())
+ return llvm::Intrinsic::vector_reduce_smax;
+ if (QT->isUnsignedIntegerType())
+ return llvm::Intrinsic::vector_reduce_umax;
+ assert(QT->isFloatingType() && "must have a float here");
return llvm::Intrinsic::vector_reduce_fmax;
};
- Value *Op0 = EmitScalarExpr(E->getArg(0));
- Value *Result = Builder.CreateUnaryIntrinsic(
- GetIntrinsicID(E->getArg(0)->getType(), Op0->getType()), Op0, nullptr,
- "rdx.min");
- return RValue::get(Result);
+ return RValue::get(emitUnaryBuiltin(
+ *this, E, GetIntrinsicID(E->getArg(0)->getType()), "rdx.min"));
}
case Builtin::BI__builtin_reduce_min: {
- auto GetIntrinsicID = [](QualType QT, llvm::Type *IrTy) {
- if (IrTy->isIntOrIntVectorTy()) {
- if (auto *VecTy = QT->getAs<VectorType>())
- QT = VecTy->getElementType();
- if (QT->isSignedIntegerType())
- return llvm::Intrinsic::vector_reduce_smin;
- else
- return llvm::Intrinsic::vector_reduce_umin;
- }
+ auto GetIntrinsicID = [](QualType QT) {
+ if (auto *VecTy = QT->getAs<VectorType>())
+ QT = VecTy->getElementType();
+ if (QT->isSignedIntegerType())
+ return llvm::Intrinsic::vector_reduce_smin;
+ if (QT->isUnsignedIntegerType())
+ return llvm::Intrinsic::vector_reduce_umin;
+ assert(QT->isFloatingType() && "must have a float here");
return llvm::Intrinsic::vector_reduce_fmin;
};
- Value *Op0 = EmitScalarExpr(E->getArg(0));
- Value *Result = Builder.CreateUnaryIntrinsic(
- GetIntrinsicID(E->getArg(0)->getType(), Op0->getType()), Op0, nullptr,
- "rdx.min");
- return RValue::get(Result);
- }
- case Builtin::BI__builtin_reduce_xor: {
- Value *Op0 = EmitScalarExpr(E->getArg(0));
- Value *Result = Builder.CreateUnaryIntrinsic(
- llvm::Intrinsic::vector_reduce_xor, Op0, nullptr, "rdx.xor");
- return RValue::get(Result);
+ return RValue::get(emitUnaryBuiltin(
+ *this, E, GetIntrinsicID(E->getArg(0)->getType()), "rdx.min"));
}
+ case Builtin::BI__builtin_reduce_xor:
+ return RValue::get(emitUnaryBuiltin(
+ *this, E, llvm::Intrinsic::vector_reduce_xor, "rdx.xor"));
+ case Builtin::BI__builtin_reduce_or:
+ return RValue::get(emitUnaryBuiltin(
+ *this, E, llvm::Intrinsic::vector_reduce_or, "rdx.or"));
+ case Builtin::BI__builtin_reduce_and:
+ return RValue::get(emitUnaryBuiltin(
+ *this, E, llvm::Intrinsic::vector_reduce_and, "rdx.and"));
+
case Builtin::BI__builtin_matrix_transpose: {
- const auto *MatrixTy = E->getArg(0)->getType()->getAs<ConstantMatrixType>();
+ auto *MatrixTy = E->getArg(0)->getType()->castAs<ConstantMatrixType>();
Value *MatValue = EmitScalarExpr(E->getArg(0));
MatrixBuilder<CGBuilderTy> MB(Builder);
Value *Result = MB.CreateMatrixTranspose(MatValue, MatrixTy->getNumRows(),
@@ -3423,6 +3433,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BIalloca:
case Builtin::BI_alloca:
+ case Builtin::BI__builtin_alloca_uninitialized:
case Builtin::BI__builtin_alloca: {
Value *Size = EmitScalarExpr(E->getArg(0));
const TargetInfo &TI = getContext().getTargetInfo();
@@ -3433,10 +3444,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
.getAsAlign();
AllocaInst *AI = Builder.CreateAlloca(Builder.getInt8Ty(), Size);
AI->setAlignment(SuitableAlignmentInBytes);
- initializeAlloca(*this, AI, Size, SuitableAlignmentInBytes);
+ if (BuiltinID != Builtin::BI__builtin_alloca_uninitialized)
+ initializeAlloca(*this, AI, Size, SuitableAlignmentInBytes);
return RValue::get(AI);
}
+ case Builtin::BI__builtin_alloca_with_align_uninitialized:
case Builtin::BI__builtin_alloca_with_align: {
Value *Size = EmitScalarExpr(E->getArg(0));
Value *AlignmentInBitsValue = EmitScalarExpr(E->getArg(1));
@@ -3446,7 +3459,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
CGM.getContext().toCharUnitsFromBits(AlignmentInBits).getAsAlign();
AllocaInst *AI = Builder.CreateAlloca(Builder.getInt8Ty(), Size);
AI->setAlignment(AlignmentInBytes);
- initializeAlloca(*this, AI, Size, AlignmentInBytes);
+ if (BuiltinID != Builtin::BI__builtin_alloca_with_align_uninitialized)
+ initializeAlloca(*this, AI, Size, AlignmentInBytes);
return RValue::get(AI);
}
@@ -4921,7 +4935,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
llvm::Value *Block =
Builder.CreatePointerCast(Info.BlockArg, GenericVoidPtrTy);
- AttrBuilder B;
+ AttrBuilder B(Builder.getContext());
B.addByValAttr(NDRangeL.getAddress(*this).getElementType());
llvm::AttributeList ByValAttrSet =
llvm::AttributeList::get(CGM.getModule().getContext(), 3U, B);
@@ -5860,6 +5874,10 @@ static const ARMVectorIntrinsicInfo ARMSIMDIntrinsicMap [] = {
NEONMAP1(vqmovun_v, arm_neon_vqmovnsu, Add1ArgType),
NEONMAP1(vqneg_v, arm_neon_vqneg, Add1ArgType),
NEONMAP1(vqnegq_v, arm_neon_vqneg, Add1ArgType),
+ NEONMAP1(vqrdmlah_v, arm_neon_vqrdmlah, Add1ArgType),
+ NEONMAP1(vqrdmlahq_v, arm_neon_vqrdmlah, Add1ArgType),
+ NEONMAP1(vqrdmlsh_v, arm_neon_vqrdmlsh, Add1ArgType),
+ NEONMAP1(vqrdmlshq_v, arm_neon_vqrdmlsh, Add1ArgType),
NEONMAP1(vqrdmulh_v, arm_neon_vqrdmulh, Add1ArgType),
NEONMAP1(vqrdmulhq_v, arm_neon_vqrdmulh, Add1ArgType),
NEONMAP2(vqrshl_v, arm_neon_vqrshiftu, arm_neon_vqrshifts, Add1ArgType | UnsignedAlts),
@@ -6085,6 +6103,10 @@ static const ARMVectorIntrinsicInfo AArch64SIMDIntrinsicMap[] = {
NEONMAP1(vqmovun_v, aarch64_neon_sqxtun, Add1ArgType),
NEONMAP1(vqneg_v, aarch64_neon_sqneg, Add1ArgType),
NEONMAP1(vqnegq_v, aarch64_neon_sqneg, Add1ArgType),
+ NEONMAP1(vqrdmlah_v, aarch64_neon_sqrdmlah, Add1ArgType),
+ NEONMAP1(vqrdmlahq_v, aarch64_neon_sqrdmlah, Add1ArgType),
+ NEONMAP1(vqrdmlsh_v, aarch64_neon_sqrdmlsh, Add1ArgType),
+ NEONMAP1(vqrdmlshq_v, aarch64_neon_sqrdmlsh, Add1ArgType),
NEONMAP1(vqrdmulh_lane_v, aarch64_neon_sqrdmulh_lane, 0),
NEONMAP1(vqrdmulh_laneq_v, aarch64_neon_sqrdmulh_laneq, 0),
NEONMAP1(vqrdmulh_v, aarch64_neon_sqrdmulh, Add1ArgType),
@@ -6287,6 +6309,10 @@ static const ARMVectorIntrinsicInfo AArch64SISDIntrinsicMap[] = {
NEONMAP1(vqnegd_s64, aarch64_neon_sqneg, Add1ArgType),
NEONMAP1(vqnegh_s16, aarch64_neon_sqneg, Vectorize1ArgType | Use64BitVectors),
NEONMAP1(vqnegs_s32, aarch64_neon_sqneg, Add1ArgType),
+ NEONMAP1(vqrdmlahh_s16, aarch64_neon_sqrdmlah, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqrdmlahs_s32, aarch64_neon_sqrdmlah, Add1ArgType),
+ NEONMAP1(vqrdmlshh_s16, aarch64_neon_sqrdmlsh, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqrdmlshs_s32, aarch64_neon_sqrdmlsh, Add1ArgType),
NEONMAP1(vqrdmulhh_s16, aarch64_neon_sqrdmulh, Vectorize1ArgType | Use64BitVectors),
NEONMAP1(vqrdmulhs_s32, aarch64_neon_sqrdmulh, Add1ArgType),
NEONMAP1(vqrshlb_s8, aarch64_neon_sqrshl, Vectorize1ArgType | Use64BitVectors),
@@ -14271,73 +14297,6 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
return Builder.CreateCall(F, Ops[0]);
}
}
- case X86::BI__builtin_ia32_pabsb128:
- case X86::BI__builtin_ia32_pabsw128:
- case X86::BI__builtin_ia32_pabsd128:
- case X86::BI__builtin_ia32_pabsb256:
- case X86::BI__builtin_ia32_pabsw256:
- case X86::BI__builtin_ia32_pabsd256:
- case X86::BI__builtin_ia32_pabsq128:
- case X86::BI__builtin_ia32_pabsq256:
- case X86::BI__builtin_ia32_pabsb512:
- case X86::BI__builtin_ia32_pabsw512:
- case X86::BI__builtin_ia32_pabsd512:
- case X86::BI__builtin_ia32_pabsq512: {
- Function *F = CGM.getIntrinsic(Intrinsic::abs, Ops[0]->getType());
- return Builder.CreateCall(F, {Ops[0], Builder.getInt1(false)});
- }
- case X86::BI__builtin_ia32_pmaxsb128:
- case X86::BI__builtin_ia32_pmaxsw128:
- case X86::BI__builtin_ia32_pmaxsd128:
- case X86::BI__builtin_ia32_pmaxsq128:
- case X86::BI__builtin_ia32_pmaxsb256:
- case X86::BI__builtin_ia32_pmaxsw256:
- case X86::BI__builtin_ia32_pmaxsd256:
- case X86::BI__builtin_ia32_pmaxsq256:
- case X86::BI__builtin_ia32_pmaxsb512:
- case X86::BI__builtin_ia32_pmaxsw512:
- case X86::BI__builtin_ia32_pmaxsd512:
- case X86::BI__builtin_ia32_pmaxsq512:
- return EmitX86BinaryIntrinsic(*this, Ops, Intrinsic::smax);
- case X86::BI__builtin_ia32_pmaxub128:
- case X86::BI__builtin_ia32_pmaxuw128:
- case X86::BI__builtin_ia32_pmaxud128:
- case X86::BI__builtin_ia32_pmaxuq128:
- case X86::BI__builtin_ia32_pmaxub256:
- case X86::BI__builtin_ia32_pmaxuw256:
- case X86::BI__builtin_ia32_pmaxud256:
- case X86::BI__builtin_ia32_pmaxuq256:
- case X86::BI__builtin_ia32_pmaxub512:
- case X86::BI__builtin_ia32_pmaxuw512:
- case X86::BI__builtin_ia32_pmaxud512:
- case X86::BI__builtin_ia32_pmaxuq512:
- return EmitX86BinaryIntrinsic(*this, Ops, Intrinsic::umax);
- case X86::BI__builtin_ia32_pminsb128:
- case X86::BI__builtin_ia32_pminsw128:
- case X86::BI__builtin_ia32_pminsd128:
- case X86::BI__builtin_ia32_pminsq128:
- case X86::BI__builtin_ia32_pminsb256:
- case X86::BI__builtin_ia32_pminsw256:
- case X86::BI__builtin_ia32_pminsd256:
- case X86::BI__builtin_ia32_pminsq256:
- case X86::BI__builtin_ia32_pminsb512:
- case X86::BI__builtin_ia32_pminsw512:
- case X86::BI__builtin_ia32_pminsd512:
- case X86::BI__builtin_ia32_pminsq512:
- return EmitX86BinaryIntrinsic(*this, Ops, Intrinsic::smin);
- case X86::BI__builtin_ia32_pminub128:
- case X86::BI__builtin_ia32_pminuw128:
- case X86::BI__builtin_ia32_pminud128:
- case X86::BI__builtin_ia32_pminuq128:
- case X86::BI__builtin_ia32_pminub256:
- case X86::BI__builtin_ia32_pminuw256:
- case X86::BI__builtin_ia32_pminud256:
- case X86::BI__builtin_ia32_pminuq256:
- case X86::BI__builtin_ia32_pminub512:
- case X86::BI__builtin_ia32_pminuw512:
- case X86::BI__builtin_ia32_pminud512:
- case X86::BI__builtin_ia32_pminuq512:
- return EmitX86BinaryIntrinsic(*this, Ops, Intrinsic::umin);
case X86::BI__builtin_ia32_pmuludq128:
case X86::BI__builtin_ia32_pmuludq256:
@@ -14418,12 +14377,6 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
CGM.getIntrinsic(Intrinsic::vector_reduce_add, Ops[0]->getType());
return Builder.CreateCall(F, {Ops[0]});
}
- case X86::BI__builtin_ia32_reduce_and_d512:
- case X86::BI__builtin_ia32_reduce_and_q512: {
- Function *F =
- CGM.getIntrinsic(Intrinsic::vector_reduce_and, Ops[0]->getType());
- return Builder.CreateCall(F, {Ops[0]});
- }
case X86::BI__builtin_ia32_reduce_fadd_pd512:
case X86::BI__builtin_ia32_reduce_fadd_ps512:
case X86::BI__builtin_ia32_reduce_fadd_ph512:
@@ -14470,36 +14423,6 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
CGM.getIntrinsic(Intrinsic::vector_reduce_mul, Ops[0]->getType());
return Builder.CreateCall(F, {Ops[0]});
}
- case X86::BI__builtin_ia32_reduce_or_d512:
- case X86::BI__builtin_ia32_reduce_or_q512: {
- Function *F =
- CGM.getIntrinsic(Intrinsic::vector_reduce_or, Ops[0]->getType());
- return Builder.CreateCall(F, {Ops[0]});
- }
- case X86::BI__builtin_ia32_reduce_smax_d512:
- case X86::BI__builtin_ia32_reduce_smax_q512: {
- Function *F =
- CGM.getIntrinsic(Intrinsic::vector_reduce_smax, Ops[0]->getType());
- return Builder.CreateCall(F, {Ops[0]});
- }
- case X86::BI__builtin_ia32_reduce_smin_d512:
- case X86::BI__builtin_ia32_reduce_smin_q512: {
- Function *F =
- CGM.getIntrinsic(Intrinsic::vector_reduce_smin, Ops[0]->getType());
- return Builder.CreateCall(F, {Ops[0]});
- }
- case X86::BI__builtin_ia32_reduce_umax_d512:
- case X86::BI__builtin_ia32_reduce_umax_q512: {
- Function *F =
- CGM.getIntrinsic(Intrinsic::vector_reduce_umax, Ops[0]->getType());
- return Builder.CreateCall(F, {Ops[0]});
- }
- case X86::BI__builtin_ia32_reduce_umin_d512:
- case X86::BI__builtin_ia32_reduce_umin_q512: {
- Function *F =
- CGM.getIntrinsic(Intrinsic::vector_reduce_umin, Ops[0]->getType());
- return Builder.CreateCall(F, {Ops[0]});
- }
// 3DNow!
case X86::BI__builtin_ia32_pswapdsf:
@@ -17279,7 +17202,7 @@ static NVPTXMmaLdstInfo getNVPTXMmaLdstInfo(unsigned BuiltinID) {
case NVPTX::BI__mma_tf32_m16n16k8_ld_a:
return MMA_LDST(4, m16n16k8_load_a_tf32);
case NVPTX::BI__mma_tf32_m16n16k8_ld_b:
- return MMA_LDST(2, m16n16k8_load_b_tf32);
+ return MMA_LDST(4, m16n16k8_load_b_tf32);
case NVPTX::BI__mma_tf32_m16n16k8_ld_c:
return MMA_LDST(8, m16n16k8_load_c_f32);
@@ -18448,15 +18371,11 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
llvm_unreachable("unexpected builtin ID");
}
llvm::Type *SrcT = Vec->getType();
- llvm::Type *TruncT =
- SrcT->getWithNewType(llvm::IntegerType::get(getLLVMContext(), 32));
+ llvm::Type *TruncT = SrcT->getWithNewType(Builder.getInt32Ty());
Function *Callee = CGM.getIntrinsic(IntNo, {TruncT, SrcT});
Value *Trunc = Builder.CreateCall(Callee, Vec);
- Value *Splat = Builder.CreateVectorSplat(2, Builder.getInt32(0));
- Value *ConcatMask =
- llvm::ConstantVector::get({Builder.getInt32(0), Builder.getInt32(1),
- Builder.getInt32(2), Builder.getInt32(3)});
- return Builder.CreateShuffleVector(Trunc, Splat, ConcatMask);
+ Value *Splat = Constant::getNullValue(TruncT);
+ return Builder.CreateShuffleVector(Trunc, Splat, ArrayRef<int>{0, 1, 2, 3});
}
case WebAssembly::BI__builtin_wasm_shuffle_i8x16: {
Value *Ops[18];
@@ -18822,6 +18741,8 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
case RISCV::BI__builtin_riscv_bcompress_64:
case RISCV::BI__builtin_riscv_bdecompress_32:
case RISCV::BI__builtin_riscv_bdecompress_64:
+ case RISCV::BI__builtin_riscv_bfp_32:
+ case RISCV::BI__builtin_riscv_bfp_64:
case RISCV::BI__builtin_riscv_grev_32:
case RISCV::BI__builtin_riscv_grev_64:
case RISCV::BI__builtin_riscv_gorc_32:
@@ -18841,7 +18762,11 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
case RISCV::BI__builtin_riscv_crc32c_b:
case RISCV::BI__builtin_riscv_crc32c_h:
case RISCV::BI__builtin_riscv_crc32c_w:
- case RISCV::BI__builtin_riscv_crc32c_d: {
+ case RISCV::BI__builtin_riscv_crc32c_d:
+ case RISCV::BI__builtin_riscv_fsl_32:
+ case RISCV::BI__builtin_riscv_fsr_32:
+ case RISCV::BI__builtin_riscv_fsl_64:
+ case RISCV::BI__builtin_riscv_fsr_64: {
switch (BuiltinID) {
default: llvm_unreachable("unexpected builtin ID");
// Zbb
@@ -18871,6 +18796,12 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
ID = Intrinsic::riscv_bdecompress;
break;
+ // Zbf
+ case RISCV::BI__builtin_riscv_bfp_32:
+ case RISCV::BI__builtin_riscv_bfp_64:
+ ID = Intrinsic::riscv_bfp;
+ break;
+
// Zbp
case RISCV::BI__builtin_riscv_grev_32:
case RISCV::BI__builtin_riscv_grev_64:
@@ -18926,6 +18857,16 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
case RISCV::BI__builtin_riscv_crc32c_d:
ID = Intrinsic::riscv_crc32c_d;
break;
+
+ // Zbt
+ case RISCV::BI__builtin_riscv_fsl_32:
+ case RISCV::BI__builtin_riscv_fsl_64:
+ ID = Intrinsic::riscv_fsl;
+ break;
+ case RISCV::BI__builtin_riscv_fsr_32:
+ case RISCV::BI__builtin_riscv_fsr_64:
+ ID = Intrinsic::riscv_fsr;
+ break;
}
IntrinsicTypes = {ResultType};
diff --git a/clang/lib/CodeGen/CGCXXABI.cpp b/clang/lib/CodeGen/CGCXXABI.cpp
index 9714730e3c4b..0b441e382f11 100644
--- a/clang/lib/CodeGen/CGCXXABI.cpp
+++ b/clang/lib/CodeGen/CGCXXABI.cpp
@@ -154,6 +154,51 @@ void CGCXXABI::setCXXABIThisValue(CodeGenFunction &CGF, llvm::Value *ThisPtr) {
CGF.CXXABIThisValue = ThisPtr;
}
+bool CGCXXABI::mayNeedDestruction(const VarDecl *VD) const {
+ if (VD->needsDestruction(getContext()))
+ return true;
+
+ // If the variable has an incomplete class type (or array thereof), it
+ // might need destruction.
+ const Type *T = VD->getType()->getBaseElementTypeUnsafe();
+ if (T->getAs<RecordType>() && T->isIncompleteType())
+ return true;
+
+ return false;
+}
+
+bool CGCXXABI::isEmittedWithConstantInitializer(
+ const VarDecl *VD, bool InspectInitForWeakDef) const {
+ VD = VD->getMostRecentDecl();
+ if (VD->hasAttr<ConstInitAttr>())
+ return true;
+
+ // All later checks examine the initializer specified on the variable. If
+ // the variable is weak, such examination would not be correct.
+ if (!InspectInitForWeakDef && (VD->isWeak() || VD->hasAttr<SelectAnyAttr>()))
+ return false;
+
+ const VarDecl *InitDecl = VD->getInitializingDeclaration();
+ if (!InitDecl)
+ return false;
+
+ // If there's no initializer to run, this is constant initialization.
+ if (!InitDecl->hasInit())
+ return true;
+
+ // If we have the only definition, we don't need a thread wrapper if we
+ // will emit the value as a constant.
+ if (isUniqueGVALinkage(getContext().GetGVALinkageForVariable(VD)))
+ return !mayNeedDestruction(VD) && InitDecl->evaluateValue();
+
+ // Otherwise, we need a thread wrapper unless we know that every
+ // translation unit will emit the value as a constant. We rely on the
+ // variable being constant-initialized in every translation unit if it's
+ // constant-initialized in any translation unit, which isn't actually
+ // guaranteed by the standard but is necessary for sanity.
+ return InitDecl->hasConstantInitialization();
+}
+
void CGCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF,
RValue RV, QualType ResultType) {
assert(!CGF.hasAggregateEvaluationKind(ResultType) &&
diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h
index ea839db7528e..b96222b3ce28 100644
--- a/clang/lib/CodeGen/CGCXXABI.h
+++ b/clang/lib/CodeGen/CGCXXABI.h
@@ -31,7 +31,6 @@ class CXXConstructorDecl;
class CXXDestructorDecl;
class CXXMethodDecl;
class CXXRecordDecl;
-class FieldDecl;
class MangleContext;
namespace CodeGen {
@@ -80,6 +79,18 @@ protected:
ASTContext &getContext() const { return CGM.getContext(); }
+ bool mayNeedDestruction(const VarDecl *VD) const;
+
+ /// Determine whether we will definitely emit this variable with a constant
+ /// initializer, either because the language semantics demand it or because
+ /// we know that the initializer is a constant.
+ // For weak definitions, any initializer available in the current translation
+ // is not necessarily reflective of the initializer used; such initializers
+ // are ignored unless if InspectInitForWeakDef is true.
+ bool
+ isEmittedWithConstantInitializer(const VarDecl *VD,
+ bool InspectInitForWeakDef = false) const;
+
virtual bool requiresArrayCookie(const CXXDeleteExpr *E, QualType eltType);
virtual bool requiresArrayCookie(const CXXNewExpr *E);
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index d70f78fea6b4..a37ff8844e88 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -1892,7 +1892,7 @@ void CodeGenModule::getDefaultFunctionAttributes(StringRef Name,
}
void CodeGenModule::addDefaultFunctionDefinitionAttributes(llvm::Function &F) {
- llvm::AttrBuilder FuncAttrs;
+ llvm::AttrBuilder FuncAttrs(F.getContext());
getDefaultFunctionAttributes(F.getName(), F.hasOptNone(),
/* AttrOnCallSite = */ false, FuncAttrs);
// TODO: call GetCPUAndFeaturesAttributes?
@@ -2014,8 +2014,8 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
llvm::AttributeList &AttrList,
unsigned &CallingConv,
bool AttrOnCallSite, bool IsThunk) {
- llvm::AttrBuilder FuncAttrs;
- llvm::AttrBuilder RetAttrs;
+ llvm::AttrBuilder FuncAttrs(getLLVMContext());
+ llvm::AttrBuilder RetAttrs(getLLVMContext());
// Collect function IR attributes from the CC lowering.
// We'll collect the paramete and result attributes later.
@@ -2243,7 +2243,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
getLangOpts().Sanitize.has(SanitizerKind::Return);
// Determine if the return type could be partially undef
- if (CodeGenOpts.EnableNoundefAttrs && HasStrictReturn) {
+ if (!CodeGenOpts.DisableNoundefAttrs && HasStrictReturn) {
if (!RetTy->isVoidType() && RetAI.getKind() != ABIArgInfo::Indirect &&
DetermineNoUndef(RetTy, getTypes(), DL, RetAI))
RetAttrs.addAttribute(llvm::Attribute::NoUndef);
@@ -2302,7 +2302,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
// Attach attributes to sret.
if (IRFunctionArgs.hasSRetArg()) {
- llvm::AttrBuilder SRETAttrs;
+ llvm::AttrBuilder SRETAttrs(getLLVMContext());
SRETAttrs.addStructRetAttr(getTypes().ConvertTypeForMem(RetTy));
hasUsedSRet = true;
if (RetAI.getInReg())
@@ -2314,7 +2314,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
// Attach attributes to inalloca argument.
if (IRFunctionArgs.hasInallocaArg()) {
- llvm::AttrBuilder Attrs;
+ llvm::AttrBuilder Attrs(getLLVMContext());
Attrs.addInAllocaAttr(FI.getArgStruct());
ArgAttrs[IRFunctionArgs.getInallocaArgNo()] =
llvm::AttributeSet::get(getLLVMContext(), Attrs);
@@ -2329,7 +2329,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
assert(IRArgs.second == 1 && "Expected only a single `this` pointer.");
- llvm::AttrBuilder Attrs;
+ llvm::AttrBuilder Attrs(getLLVMContext());
QualType ThisTy =
FI.arg_begin()->type.castAs<PointerType>()->getPointeeType();
@@ -2364,7 +2364,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
I != E; ++I, ++ArgNo) {
QualType ParamType = I->type;
const ABIArgInfo &AI = I->info;
- llvm::AttrBuilder Attrs;
+ llvm::AttrBuilder Attrs(getLLVMContext());
// Add attribute for padding argument, if necessary.
if (IRFunctionArgs.hasPaddingArg(ArgNo)) {
@@ -2372,14 +2372,15 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
ArgAttrs[IRFunctionArgs.getPaddingArgNo(ArgNo)] =
llvm::AttributeSet::get(
getLLVMContext(),
- llvm::AttrBuilder().addAttribute(llvm::Attribute::InReg));
+ llvm::AttrBuilder(getLLVMContext()).addAttribute(llvm::Attribute::InReg));
}
}
// Decide whether the argument we're handling could be partially undef
- bool ArgNoUndef = DetermineNoUndef(ParamType, getTypes(), DL, AI);
- if (CodeGenOpts.EnableNoundefAttrs && ArgNoUndef)
+ if (!CodeGenOpts.DisableNoundefAttrs &&
+ DetermineNoUndef(ParamType, getTypes(), DL, AI)) {
Attrs.addAttribute(llvm::Attribute::NoUndef);
+ }
// 'restrict' -> 'noalias' is done in EmitFunctionProlog when we
// have the corresponding parameter variable. It doesn't make
@@ -2519,8 +2520,8 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
unsigned FirstIRArg, NumIRArgs;
std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo);
for (unsigned i = 0; i < NumIRArgs; i++)
- ArgAttrs[FirstIRArg + i] =
- llvm::AttributeSet::get(getLLVMContext(), Attrs);
+ ArgAttrs[FirstIRArg + i] = ArgAttrs[FirstIRArg + i].addAttributes(
+ getLLVMContext(), llvm::AttributeSet::get(getLLVMContext(), Attrs));
}
}
assert(ArgNo == FI.arg_size());
@@ -2747,11 +2748,11 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
QualType ETy = ArrTy->getElementType();
llvm::Align Alignment =
CGM.getNaturalTypeAlignment(ETy).getAsAlign();
- AI->addAttrs(llvm::AttrBuilder().addAlignmentAttr(Alignment));
+ AI->addAttrs(llvm::AttrBuilder(getLLVMContext()).addAlignmentAttr(Alignment));
uint64_t ArrSize = ArrTy->getSize().getZExtValue();
if (!ETy->isIncompleteType() && ETy->isConstantSizeType() &&
ArrSize) {
- llvm::AttrBuilder Attrs;
+ llvm::AttrBuilder Attrs(getLLVMContext());
Attrs.addDereferenceableAttr(
getContext().getTypeSizeInChars(ETy).getQuantity() *
ArrSize);
@@ -2771,7 +2772,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
QualType ETy = ArrTy->getElementType();
llvm::Align Alignment =
CGM.getNaturalTypeAlignment(ETy).getAsAlign();
- AI->addAttrs(llvm::AttrBuilder().addAlignmentAttr(Alignment));
+ AI->addAttrs(llvm::AttrBuilder(getLLVMContext()).addAlignmentAttr(Alignment));
if (!getContext().getTargetAddressSpace(ETy) &&
!CGM.getCodeGenOpts().NullPointerIsValid)
AI->addAttr(llvm::Attribute::NonNull);
@@ -2793,7 +2794,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
AlignmentCI->getLimitedValue(llvm::Value::MaximumAlignment);
if (AI->getParamAlign().valueOrOne() < AlignmentInt) {
AI->removeAttr(llvm::Attribute::AttrKind::Alignment);
- AI->addAttrs(llvm::AttrBuilder().addAlignmentAttr(
+ AI->addAttrs(llvm::AttrBuilder(getLLVMContext()).addAlignmentAttr(
llvm::Align(AlignmentInt)));
}
}
@@ -3879,9 +3880,8 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
}
// Create the temporary.
- Address temp = CGF.CreateTempAlloca(destType->getElementType(),
- CGF.getPointerAlign(),
- "icr.temp");
+ Address temp = CGF.CreateTempAlloca(destType->getPointerElementType(),
+ CGF.getPointerAlign(), "icr.temp");
// Loading an l-value can introduce a cleanup if the l-value is __weak,
// and that cleanup will be conditional if we can't prove that the l-value
// isn't null, so we need to register a dominating point so that the cleanups
@@ -3891,9 +3891,8 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
// Zero-initialize it if we're not doing a copy-initialization.
bool shouldCopy = CRE->shouldCopy();
if (!shouldCopy) {
- llvm::Value *null =
- llvm::ConstantPointerNull::get(
- cast<llvm::PointerType>(destType->getElementType()));
+ llvm::Value *null = llvm::ConstantPointerNull::get(
+ cast<llvm::PointerType>(destType->getPointerElementType()));
CGF.Builder.CreateStore(null, temp);
}
@@ -3935,7 +3934,7 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
assert(srcRV.isScalar());
llvm::Value *src = srcRV.getScalarVal();
- src = CGF.Builder.CreateBitCast(src, destType->getElementType(),
+ src = CGF.Builder.CreateBitCast(src, destType->getPointerElementType(),
"icr.cast");
// Use an ordinary store, not a store-to-lvalue.
@@ -5074,8 +5073,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
#ifndef NDEBUG
// Assert that these structs have equivalent element types.
llvm::StructType *FullTy = CallInfo.getArgStruct();
- llvm::StructType *DeclaredTy = cast<llvm::StructType>(
- cast<llvm::PointerType>(LastParamTy)->getElementType());
+ llvm::StructType *DeclaredTy =
+ cast<llvm::StructType>(LastParamTy->getPointerElementType());
assert(DeclaredTy->getNumElements() == FullTy->getNumElements());
for (llvm::StructType::element_iterator DI = DeclaredTy->element_begin(),
DE = DeclaredTy->element_end(),
diff --git a/clang/lib/CodeGen/CGCall.h b/clang/lib/CodeGen/CGCall.h
index c8594068c3fc..af63e1bddd2d 100644
--- a/clang/lib/CodeGen/CGCall.h
+++ b/clang/lib/CodeGen/CGCall.h
@@ -26,17 +26,13 @@
#include "ABIInfo.h"
namespace llvm {
-class AttributeList;
-class Function;
class Type;
class Value;
} // namespace llvm
namespace clang {
-class ASTContext;
class Decl;
class FunctionDecl;
-class ObjCMethodDecl;
class VarDecl;
namespace CodeGen {
@@ -49,11 +45,11 @@ class CGCalleeInfo {
GlobalDecl CalleeDecl;
public:
- explicit CGCalleeInfo() : CalleeProtoTy(nullptr), CalleeDecl() {}
+ explicit CGCalleeInfo() : CalleeProtoTy(nullptr) {}
CGCalleeInfo(const FunctionProtoType *calleeProtoTy, GlobalDecl calleeDecl)
: CalleeProtoTy(calleeProtoTy), CalleeDecl(calleeDecl) {}
CGCalleeInfo(const FunctionProtoType *calleeProtoTy)
- : CalleeProtoTy(calleeProtoTy), CalleeDecl() {}
+ : CalleeProtoTy(calleeProtoTy) {}
CGCalleeInfo(GlobalDecl calleeDecl)
: CalleeProtoTy(nullptr), CalleeDecl(calleeDecl) {}
@@ -116,7 +112,8 @@ public:
assert(functionPtr && "configuring callee without function pointer");
assert(functionPtr->getType()->isPointerTy());
assert(functionPtr->getType()->isOpaquePointerTy() ||
- functionPtr->getType()->getPointerElementType()->isFunctionTy());
+ functionPtr->getType()->getNonOpaquePointerElementType()
+ ->isFunctionTy());
}
static CGCallee forBuiltin(unsigned builtinID,
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index 8f99ff0d50ff..520e119ada26 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -390,7 +390,7 @@ Address CodeGenFunction::GetAddressOfBaseClass(
llvm::PHINode *PHI = Builder.CreatePHI(BasePtrTy, 2, "cast.result");
PHI->addIncoming(Value.getPointer(), notNullBB);
PHI->addIncoming(llvm::Constant::getNullValue(BasePtrTy), origBB);
- Value = Address(PHI, Value.getAlignment());
+ Value = Value.withPointer(PHI);
}
return Value;
@@ -1983,7 +1983,7 @@ void CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor,
CharUnits eltAlignment =
arrayBase.getAlignment()
.alignmentOfArrayElement(getContext().getTypeSizeInChars(type));
- Address curAddr = Address(cur, eltAlignment);
+ Address curAddr = Address(cur, elementType, eltAlignment);
// Zero initialize the storage, if requested.
if (zeroInitialize)
@@ -2852,9 +2852,8 @@ llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad(
SanitizerHandler::CFICheckFail, {}, {});
}
- return Builder.CreateBitCast(
- Builder.CreateExtractValue(CheckedLoad, 0),
- cast<llvm::PointerType>(VTable->getType())->getElementType());
+ return Builder.CreateBitCast(Builder.CreateExtractValue(CheckedLoad, 0),
+ VTable->getType()->getPointerElementType());
}
void CodeGenFunction::EmitForwardingCallToLambda(
diff --git a/clang/lib/CodeGen/CGCleanup.h b/clang/lib/CodeGen/CGCleanup.h
index 76f3a48f32f3..079a3e25d6dc 100644
--- a/clang/lib/CodeGen/CGCleanup.h
+++ b/clang/lib/CodeGen/CGCleanup.h
@@ -23,7 +23,6 @@ namespace llvm {
class BasicBlock;
class Value;
class ConstantInt;
-class AllocaInst;
}
namespace clang {
diff --git a/clang/lib/CodeGen/CGCoroutine.cpp b/clang/lib/CodeGen/CGCoroutine.cpp
index 2041d2a5b4c9..c1763cbbc5a0 100644
--- a/clang/lib/CodeGen/CGCoroutine.cpp
+++ b/clang/lib/CodeGen/CGCoroutine.cpp
@@ -707,6 +707,10 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
if (Stmt *Ret = S.getReturnStmt())
EmitStmt(Ret);
+
+ // LLVM require the frontend to add the function attribute. See
+ // Coroutines.rst.
+ CurFn->addFnAttr("coroutine.presplit", "0");
}
// Emit coroutine intrinsic and patch up arguments of the token type.
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 6e189a61dd20..1a9080604a79 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -354,13 +354,9 @@ CGDebugInfo::computeChecksum(FileID FID, SmallString<32> &Checksum) const {
if (!MemBuffer)
return None;
- llvm::MD5 Hash;
- llvm::MD5::MD5Result Result;
-
- Hash.update(MemBuffer->getBuffer());
- Hash.final(Result);
-
- Hash.stringifyResult(Result, Checksum);
+ llvm::toHex(
+ llvm::MD5::hash(llvm::arrayRefFromStringRef(MemBuffer->getBuffer())),
+ /*LowerCase*/ true, Checksum);
return llvm::DIFile::CSK_MD5;
}
@@ -722,7 +718,7 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) {
auto *LowerBound =
llvm::ConstantAsMetadata::get(llvm::ConstantInt::getSigned(
llvm::Type::getInt64Ty(CGM.getLLVMContext()), 0));
- SmallVector<int64_t, 9> Expr(
+ SmallVector<uint64_t, 9> Expr(
{llvm::dwarf::DW_OP_constu, NumElemsPerVG, llvm::dwarf::DW_OP_bregx,
/* AArch64::VG */ 46, 0, llvm::dwarf::DW_OP_mul,
llvm::dwarf::DW_OP_constu, 1, llvm::dwarf::DW_OP_minus});
@@ -768,7 +764,7 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) {
}
// Element count = (VLENB / SEW) x LMUL
- SmallVector<int64_t, 12> Expr(
+ SmallVector<uint64_t, 12> Expr(
// The DW_OP_bregx operation has two operands: a register which is
// specified by an unsigned LEB128 number, followed by a signed LEB128
// offset.
@@ -3690,7 +3686,7 @@ void CGDebugInfo::CollectContainingType(const CXXRecordDecl *RD,
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) {
// Seek non-virtual primary base root.
- while (1) {
+ while (true) {
const ASTRecordLayout &BRL = CGM.getContext().getASTRecordLayout(PBase);
const CXXRecordDecl *PBT = BRL.getPrimaryBase();
if (PBT && !BRL.isPrimaryBaseVirtual())
@@ -4325,7 +4321,7 @@ void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) {
}
void CGDebugInfo::AppendAddressSpaceXDeref(
- unsigned AddressSpace, SmallVectorImpl<int64_t> &Expr) const {
+ unsigned AddressSpace, SmallVectorImpl<uint64_t> &Expr) const {
Optional<unsigned> DWARFAddressSpace =
CGM.getTarget().getDWARFAddressSpace(AddressSpace);
if (!DWARFAddressSpace)
@@ -4494,7 +4490,7 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD,
Line = getLineNumber(VD->getLocation());
Column = getColumnNumber(VD->getLocation());
}
- SmallVector<int64_t, 13> Expr;
+ SmallVector<uint64_t, 13> Expr;
llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
if (VD->isImplicit())
Flags |= llvm::DINode::FlagArtificial;
@@ -4720,7 +4716,7 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
target.getStructLayout(blockInfo.StructureType)
->getElementOffset(blockInfo.getCapture(VD).getIndex()));
- SmallVector<int64_t, 9> addr;
+ SmallVector<uint64_t, 9> addr;
addr.push_back(llvm::dwarf::DW_OP_deref);
addr.push_back(llvm::dwarf::DW_OP_plus_uconst);
addr.push_back(offset.getQuantity());
@@ -5191,7 +5187,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
} else {
auto Align = getDeclAlignIfRequired(D, CGM.getContext());
- SmallVector<int64_t, 4> Expr;
+ SmallVector<uint64_t, 4> Expr;
unsigned AddressSpace =
CGM.getContext().getTargetAddressSpace(D->getType());
if (CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) {
diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h
index 14ff0eeabd21..a76426e585c8 100644
--- a/clang/lib/CodeGen/CGDebugInfo.h
+++ b/clang/lib/CodeGen/CGDebugInfo.h
@@ -40,7 +40,6 @@ class ClassTemplateSpecializationDecl;
class GlobalDecl;
class ModuleMap;
class ObjCInterfaceDecl;
-class ObjCIvarDecl;
class UsingDecl;
class VarDecl;
enum class DynamicInitKind : unsigned;
@@ -363,7 +362,7 @@ class CGDebugInfo {
/// Extended dereferencing mechanism is has the following format:
/// DW_OP_constu <DWARF Address Space> DW_OP_swap DW_OP_xderef
void AppendAddressSpaceXDeref(unsigned AddressSpace,
- SmallVectorImpl<int64_t> &Expr) const;
+ SmallVectorImpl<uint64_t> &Expr) const;
/// A helper function to collect debug info for the default elements of a
/// block.
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index e09279c1d455..18d658436086 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -1392,9 +1392,11 @@ void CodeGenFunction::EmitAndRegisterVariableArrayDimensions(
else {
// Create an artificial VarDecl to generate debug info for.
IdentifierInfo *NameIdent = VLAExprNames[NameIdx++];
- auto VlaExprTy = VlaSize.NumElts->getType()->getPointerElementType();
+ assert(cast<llvm::PointerType>(VlaSize.NumElts->getType())
+ ->isOpaqueOrPointeeTypeMatches(SizeTy) &&
+ "Number of VLA elements must be SizeTy");
auto QT = getContext().getIntTypeForBitwidth(
- VlaExprTy->getScalarSizeInBits(), false);
+ SizeTy->getScalarSizeInBits(), false);
auto *ArtificialDecl = VarDecl::Create(
getContext(), const_cast<DeclContext *>(D.getDeclContext()),
D.getLocation(), D.getLocation(), NameIdent, QT,
@@ -2250,16 +2252,17 @@ void CodeGenFunction::emitArrayDestroy(llvm::Value *begin,
// Shift the address back by one element.
llvm::Value *negativeOne = llvm::ConstantInt::get(SizeTy, -1, true);
+ llvm::Type *llvmElementType = ConvertTypeForMem(elementType);
llvm::Value *element = Builder.CreateInBoundsGEP(
- elementPast->getType()->getPointerElementType(), elementPast, negativeOne,
- "arraydestroy.element");
+ llvmElementType, elementPast, negativeOne, "arraydestroy.element");
if (useEHCleanup)
pushRegularPartialArrayCleanup(begin, element, elementType, elementAlign,
destroyer);
// Perform the actual destruction there.
- destroyer(*this, Address(element, elementAlign), elementType);
+ destroyer(*this, Address(element, llvmElementType, elementAlign),
+ elementType);
if (useEHCleanup)
PopCleanupBlock();
diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp
index 3579761f1429..7b880c1354e1 100644
--- a/clang/lib/CodeGen/CGDeclCXX.cpp
+++ b/clang/lib/CodeGen/CGDeclCXX.cpp
@@ -136,6 +136,7 @@ static void EmitDeclDestroy(CodeGenFunction &CGF, const VarDecl &D,
}
// Otherwise, the standard logic requires a helper function.
} else {
+ Addr = Addr.getElementBitCast(CGF.ConvertTypeForMem(Type));
Func = CodeGenFunction(CGM)
.generateDestroyHelper(Addr, Type, CGF.getDestroyer(DtorKind),
CGF.needsEHCleanup(DtorKind), &D);
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 34b4951a7f72..0fb7ec26a85e 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1931,7 +1931,7 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) {
if (LV.isMatrixElt()) {
llvm::Value *Idx = LV.getMatrixIdx();
if (CGM.getCodeGenOpts().OptimizationLevel > 0) {
- const auto *const MatTy = LV.getType()->getAs<ConstantMatrixType>();
+ const auto *const MatTy = LV.getType()->castAs<ConstantMatrixType>();
llvm::MatrixBuilder<CGBuilderTy> MB(Builder);
MB.CreateIndexAssumption(Idx, MatTy->getNumElementsFlattened());
}
@@ -2077,7 +2077,7 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
if (Dst.isMatrixElt()) {
llvm::Value *Idx = Dst.getMatrixIdx();
if (CGM.getCodeGenOpts().OptimizationLevel > 0) {
- const auto *const MatTy = Dst.getType()->getAs<ConstantMatrixType>();
+ const auto *const MatTy = Dst.getType()->castAs<ConstantMatrixType>();
llvm::MatrixBuilder<CGBuilderTy> MB(Builder);
MB.CreateIndexAssumption(Idx, MatTy->getNumElementsFlattened());
}
@@ -3178,7 +3178,7 @@ static void emitCheckHandlerCall(CodeGenFunction &CGF,
bool MayReturn =
!IsFatal || RecoverKind == CheckRecoverableKind::AlwaysRecoverable;
- llvm::AttrBuilder B;
+ llvm::AttrBuilder B(CGF.getLLVMContext());
if (!MayReturn) {
B.addAttribute(llvm::Attribute::NoReturn)
.addAttribute(llvm::Attribute::NoUnwind);
@@ -4699,12 +4699,9 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
if (LV.isSimple()) {
Address V = LV.getAddress(*this);
if (V.isValid()) {
- llvm::Type *T =
- ConvertTypeForMem(E->getType())
- ->getPointerTo(
- cast<llvm::PointerType>(V.getType())->getAddressSpace());
- if (V.getType() != T)
- LV.setAddress(Builder.CreateBitCast(V, T));
+ llvm::Type *T = ConvertTypeForMem(E->getType());
+ if (V.getElementType() != T)
+ LV.setAddress(Builder.CreateElementBitCast(V, T));
}
}
return LV;
@@ -4763,8 +4760,9 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
CGM.EmitExplicitCastExprType(CE, this);
LValue LV = EmitLValue(E->getSubExpr());
- Address V = Builder.CreateBitCast(LV.getAddress(*this),
- ConvertType(CE->getTypeAsWritten()));
+ Address V = Builder.CreateElementBitCast(
+ LV.getAddress(*this),
+ ConvertTypeForMem(CE->getTypeAsWritten()->getPointeeType()));
if (SanOpts.has(SanitizerKind::CFIUnrelatedCast))
EmitVTablePtrCheckForCast(E->getType(), V.getPointer(),
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 3b996b89a1d7..0968afd82064 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -614,8 +614,8 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
// every temporary created in a default argument is sequenced before
// the construction of the next array element, if any
CodeGenFunction::RunCleanupsScope CleanupsScope(CGF);
- LValue elementLV =
- CGF.MakeAddrLValue(Address(currentElement, elementAlign), elementType);
+ LValue elementLV = CGF.MakeAddrLValue(
+ Address(currentElement, llvmElementType, elementAlign), elementType);
if (filler)
EmitInitializationToLValue(filler, elementLV);
else
@@ -1801,6 +1801,7 @@ void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E,
CharUnits elementSize = CGF.getContext().getTypeSizeInChars(elementType);
CharUnits elementAlign =
destPtr.getAlignment().alignmentOfArrayElement(elementSize);
+ llvm::Type *llvmElementType = CGF.ConvertTypeForMem(elementType);
llvm::BasicBlock *entryBB = Builder.GetInsertBlock();
llvm::BasicBlock *bodyBB = CGF.createBasicBlock("arrayinit.body");
@@ -1810,8 +1811,8 @@ void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E,
llvm::PHINode *index =
Builder.CreatePHI(zero->getType(), 2, "arrayinit.index");
index->addIncoming(zero, entryBB);
- llvm::Value *element = Builder.CreateInBoundsGEP(
- begin->getType()->getPointerElementType(), begin, index);
+ llvm::Value *element =
+ Builder.CreateInBoundsGEP(llvmElementType, begin, index);
// Prepare for a cleanup.
QualType::DestructionKind dtorKind = elementType.isDestructedType();
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index e32462eb635c..4e8933fffe03 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -1613,8 +1613,9 @@ ScalarExprEmitter::VisitSYCLUniqueStableNameExpr(SYCLUniqueStableNameExpr *E) {
if (GlobalConstStr->getType()->getPointerAddressSpace() == ExprAS)
return GlobalConstStr;
- llvm::Type *EltTy = GlobalConstStr->getType()->getPointerElementType();
- llvm::PointerType *NewPtrTy = llvm::PointerType::get(EltTy, ExprAS);
+ llvm::PointerType *PtrTy = cast<llvm::PointerType>(GlobalConstStr->getType());
+ llvm::PointerType *NewPtrTy =
+ llvm::PointerType::getWithSamePointeeType(PtrTy, ExprAS);
return Builder.CreateAddrSpaceCast(GlobalConstStr, NewPtrTy, "usn_addr_cast");
}
diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp
index b5bcf157036d..8cc609186f9e 100644
--- a/clang/lib/CodeGen/CGObjC.cpp
+++ b/clang/lib/CodeGen/CGObjC.cpp
@@ -847,7 +847,7 @@ static void emitStructGetterCall(CodeGenFunction &CGF, ObjCIvarDecl *ivar,
static bool hasUnalignedAtomics(llvm::Triple::ArchType arch) {
// FIXME: Allow unaligned atomic load/store on x86. (It is not
// currently supported by the backend.)
- return 0;
+ return false;
}
/// Return the maximum size that permits atomic accesses for the given
diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp
index b2bf60d2c0fc..52b449090868 100644
--- a/clang/lib/CodeGen/CGObjCGNU.cpp
+++ b/clang/lib/CodeGen/CGObjCGNU.cpp
@@ -2347,9 +2347,10 @@ llvm::Value *CGObjCGNU::GetTypedSelector(CodeGenFunction &CGF, Selector Sel,
}
}
if (!SelValue) {
- SelValue = llvm::GlobalAlias::create(
- SelectorTy->getElementType(), 0, llvm::GlobalValue::PrivateLinkage,
- ".objc_selector_" + Sel.getAsString(), &TheModule);
+ SelValue = llvm::GlobalAlias::create(SelectorTy->getPointerElementType(), 0,
+ llvm::GlobalValue::PrivateLinkage,
+ ".objc_selector_" + Sel.getAsString(),
+ &TheModule);
Types.emplace_back(TypeEncoding, SelValue);
}
@@ -2576,14 +2577,16 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
if (IsClassMessage) {
if (!MetaClassPtrAlias) {
MetaClassPtrAlias = llvm::GlobalAlias::create(
- IdTy->getElementType(), 0, llvm::GlobalValue::InternalLinkage,
+ IdTy->getPointerElementType(), 0,
+ llvm::GlobalValue::InternalLinkage,
".objc_metaclass_ref" + Class->getNameAsString(), &TheModule);
}
ReceiverClass = MetaClassPtrAlias;
} else {
if (!ClassPtrAlias) {
ClassPtrAlias = llvm::GlobalAlias::create(
- IdTy->getElementType(), 0, llvm::GlobalValue::InternalLinkage,
+ IdTy->getPointerElementType(), 0,
+ llvm::GlobalValue::InternalLinkage,
".objc_class_ref" + Class->getNameAsString(), &TheModule);
}
ReceiverClass = ClassPtrAlias;
@@ -3706,7 +3709,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
GenerateProtocolHolderCategory();
llvm::StructType *selStructTy =
- dyn_cast<llvm::StructType>(SelectorTy->getElementType());
+ dyn_cast<llvm::StructType>(SelectorTy->getPointerElementType());
llvm::Type *selStructPtrTy = SelectorTy;
if (!selStructTy) {
selStructTy = llvm::StructType::get(CGM.getLLVMContext(),
diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp
index 425d1a793439..e7dba4c8feab 100644
--- a/clang/lib/CodeGen/CGObjCMac.cpp
+++ b/clang/lib/CodeGen/CGObjCMac.cpp
@@ -2138,16 +2138,7 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
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);
- }
+ llvm::Value *SelValue = llvm::UndefValue::get(Types.ConvertType(selTy));
CallArgList ActualArgs;
if (!IsSuper)
@@ -2168,10 +2159,15 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
canMessageReceiverBeNull(CGF, Method, IsSuper, ClassReceiver, Arg0);
bool RequiresNullCheck = false;
+ bool RequiresSelValue = true;
llvm::FunctionCallee Fn = nullptr;
if (Method && Method->isDirectMethod()) {
+ assert(!IsSuper);
Fn = GenerateDirectMethod(Method, Method->getClassInterface());
+ // Direct methods will synthesize the proper `_cmd` internally,
+ // so just don't bother with setting the `_cmd` argument.
+ RequiresSelValue = false;
} else if (CGM.ReturnSlotInterferesWithArgs(MSI.CallInfo)) {
if (ReceiverCanBeNull) RequiresNullCheck = true;
Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper)
@@ -2209,6 +2205,12 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
nullReturn.init(CGF, Arg0);
}
+ // If a selector value needs to be passed, emit the load before the call.
+ if (RequiresSelValue) {
+ SelValue = GetSelector(CGF, Sel);
+ ActualArgs[1] = CallArg(RValue::get(SelValue), selTy);
+ }
+
llvm::CallBase *CallSite;
CGCallee Callee = CGCallee::forDirect(BitcastFn);
RValue rvalue = CGF.EmitCall(MSI.CallInfo, Callee, Return, ActualArgs,
@@ -2487,7 +2489,7 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
if (FQT->isUnionType())
HasUnion = true;
- BuildRCBlockVarRecordLayout(FQT->getAs<RecordType>(),
+ BuildRCBlockVarRecordLayout(FQT->castAs<RecordType>(),
BytePos + FieldOffset, HasUnion);
continue;
}
@@ -2935,8 +2937,7 @@ CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
std::string CGObjCCommonMac::getRCBlockLayoutStr(CodeGenModule &CGM,
const CGBlockInfo &blockInfo) {
fillRunSkipBlockVars(CGM, blockInfo);
- return getBlockLayoutInfoString(RunSkipBlockVars,
- blockInfo.needsCopyDisposeHelpers());
+ return getBlockLayoutInfoString(RunSkipBlockVars, blockInfo.NeedsCopyDispose);
}
llvm::Constant *CGObjCCommonMac::BuildByrefLayout(CodeGen::CodeGenModule &CGM,
@@ -4370,7 +4371,11 @@ FragileHazards::FragileHazards(CodeGenFunction &CGF) : CGF(CGF) {
void FragileHazards::emitWriteHazard() {
if (Locals.empty()) return;
- CGF.EmitNounwindRuntimeCall(WriteHazard, Locals);
+ llvm::CallInst *Call = CGF.EmitNounwindRuntimeCall(WriteHazard, Locals);
+ for (auto Pair : llvm::enumerate(Locals))
+ Call->addParamAttr(Pair.index(), llvm::Attribute::get(
+ CGF.getLLVMContext(), llvm::Attribute::ElementType,
+ cast<llvm::AllocaInst>(Pair.value())->getAllocatedType()));
}
void FragileHazards::emitReadHazard(CGBuilderTy &Builder) {
@@ -4378,6 +4383,10 @@ void FragileHazards::emitReadHazard(CGBuilderTy &Builder) {
llvm::CallInst *call = Builder.CreateCall(ReadHazard, Locals);
call->setDoesNotThrow();
call->setCallingConv(CGF.getRuntimeCC());
+ for (auto Pair : llvm::enumerate(Locals))
+ call->addParamAttr(Pair.index(), llvm::Attribute::get(
+ Builder.getContext(), llvm::Attribute::ElementType,
+ cast<llvm::AllocaInst>(Pair.value())->getAllocatedType()));
}
/// Emit read hazards in all the protected blocks, i.e. all the blocks
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
index e35c15421520..db1c3ca191ca 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -837,12 +837,11 @@ void ReductionCodeGen::emitAggregateType(CodeGenFunction &CGF, unsigned N) {
}
llvm::Value *Size;
llvm::Value *SizeInChars;
- auto *ElemType =
- cast<llvm::PointerType>(OrigAddresses[N].first.getPointer(CGF)->getType())
- ->getElementType();
+ auto *ElemType = OrigAddresses[N].first.getAddress(CGF).getElementType();
auto *ElemSizeOf = llvm::ConstantExpr::getSizeOf(ElemType);
if (AsArraySection) {
- Size = CGF.Builder.CreatePtrDiff(OrigAddresses[N].second.getPointer(CGF),
+ Size = CGF.Builder.CreatePtrDiff(ElemType,
+ OrigAddresses[N].second.getPointer(CGF),
OrigAddresses[N].first.getPointer(CGF));
Size = CGF.Builder.CreateNUWAdd(
Size, llvm::ConstantInt::get(Size->getType(), /*V=*/1));
@@ -1008,7 +1007,8 @@ Address ReductionCodeGen::adjustPrivateAddress(CodeGenFunction &CGF, unsigned N,
OriginalBaseLValue);
Address SharedAddr = SharedAddresses[N].first.getAddress(CGF);
llvm::Value *Adjustment = CGF.Builder.CreatePtrDiff(
- BaseLValue.getPointer(CGF), SharedAddr.getPointer());
+ SharedAddr.getElementType(), BaseLValue.getPointer(CGF),
+ SharedAddr.getPointer());
llvm::Value *PrivatePointer =
CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
PrivateAddr.getPointer(), SharedAddr.getType());
@@ -1429,24 +1429,25 @@ static StringRef getIdentStringFromSourceLocation(CodeGenFunction &CGF,
llvm::Value *CGOpenMPRuntime::emitUpdateLocation(CodeGenFunction &CGF,
SourceLocation Loc,
unsigned Flags) {
+ uint32_t SrcLocStrSize;
llvm::Constant *SrcLocStr;
if (CGM.getCodeGenOpts().getDebugInfo() == codegenoptions::NoDebugInfo ||
Loc.isInvalid()) {
- SrcLocStr = OMPBuilder.getOrCreateDefaultSrcLocStr();
+ SrcLocStr = OMPBuilder.getOrCreateDefaultSrcLocStr(SrcLocStrSize);
} else {
- std::string FunctionName = "";
+ std::string FunctionName;
if (const auto *FD = dyn_cast_or_null<FunctionDecl>(CGF.CurFuncDecl))
FunctionName = FD->getQualifiedNameAsString();
PresumedLoc PLoc = CGF.getContext().getSourceManager().getPresumedLoc(Loc);
const char *FileName = PLoc.getFilename();
unsigned Line = PLoc.getLine();
unsigned Column = PLoc.getColumn();
- SrcLocStr =
- OMPBuilder.getOrCreateSrcLocStr(FunctionName, FileName, Line, Column);
+ SrcLocStr = OMPBuilder.getOrCreateSrcLocStr(FunctionName, FileName, Line,
+ Column, SrcLocStrSize);
}
unsigned Reserved2Flags = getDefaultLocationReserved2Flags();
- return OMPBuilder.getOrCreateIdent(SrcLocStr, llvm::omp::IdentFlag(Flags),
- Reserved2Flags);
+ return OMPBuilder.getOrCreateIdent(
+ SrcLocStr, SrcLocStrSize, llvm::omp::IdentFlag(Flags), Reserved2Flags);
}
llvm::Value *CGOpenMPRuntime::getThreadID(CodeGenFunction &CGF,
@@ -1457,10 +1458,11 @@ llvm::Value *CGOpenMPRuntime::getThreadID(CodeGenFunction &CGF,
if (CGM.getLangOpts().OpenMPIRBuilder) {
SmallString<128> Buffer;
OMPBuilder.updateToLocation(CGF.Builder.saveIP());
+ uint32_t SrcLocStrSize;
auto *SrcLocStr = OMPBuilder.getOrCreateSrcLocStr(
- getIdentStringFromSourceLocation(CGF, Loc, Buffer));
+ getIdentStringFromSourceLocation(CGF, Loc, Buffer), SrcLocStrSize);
return OMPBuilder.getOrCreateThreadID(
- OMPBuilder.getOrCreateIdent(SrcLocStr));
+ OMPBuilder.getOrCreateIdent(SrcLocStr, SrcLocStrSize));
}
llvm::Value *ThreadID = nullptr;
@@ -3464,8 +3466,7 @@ static bool isAllocatableDecl(const VarDecl *VD) {
return false;
const auto *AA = CVD->getAttr<OMPAllocateDeclAttr>();
// Use the default allocation.
- return !((AA->getAllocatorType() == OMPAllocateDeclAttr::OMPDefaultMemAlloc ||
- AA->getAllocatorType() == OMPAllocateDeclAttr::OMPNullMemAlloc) &&
+ return !(AA->getAllocatorType() == OMPAllocateDeclAttr::OMPDefaultMemAlloc &&
!AA->getAllocator());
}
@@ -8120,7 +8121,7 @@ private:
.getAddress(CGF);
}
Size = CGF.Builder.CreatePtrDiff(
- CGF.EmitCastToVoidPtr(ComponentLB.getPointer()),
+ CGF.Int8Ty, CGF.EmitCastToVoidPtr(ComponentLB.getPointer()),
CGF.EmitCastToVoidPtr(LB.getPointer()));
break;
}
@@ -8141,7 +8142,7 @@ private:
CombinedInfo.BasePointers.push_back(BP.getPointer());
CombinedInfo.Pointers.push_back(LB.getPointer());
Size = CGF.Builder.CreatePtrDiff(
- CGF.Builder.CreateConstGEP(HB, 1).getPointer(),
+ CGF.Int8Ty, CGF.Builder.CreateConstGEP(HB, 1).getPointer(),
CGF.EmitCastToVoidPtr(LB.getPointer()));
CombinedInfo.Sizes.push_back(
CGF.Builder.CreateIntCast(Size, CGF.Int64Ty, /*isSigned=*/true));
@@ -8967,7 +8968,7 @@ public:
CGF.Builder.CreateConstGEP1_32(HBAddr.getElementType(), HB, /*Idx0=*/1);
llvm::Value *CLAddr = CGF.Builder.CreatePointerCast(LB, CGF.VoidPtrTy);
llvm::Value *CHAddr = CGF.Builder.CreatePointerCast(HAddr, CGF.VoidPtrTy);
- llvm::Value *Diff = CGF.Builder.CreatePtrDiff(CHAddr, CLAddr);
+ llvm::Value *Diff = CGF.Builder.CreatePtrDiff(CGF.Int8Ty, CHAddr, CLAddr);
llvm::Value *Size = CGF.Builder.CreateIntCast(Diff, CGF.Int64Ty,
/*isSigned=*/false);
CombinedInfo.Sizes.push_back(Size);
@@ -9527,8 +9528,9 @@ llvm::Constant *
emitMappingInformation(CodeGenFunction &CGF, llvm::OpenMPIRBuilder &OMPBuilder,
MappableExprsHandler::MappingExprInfo &MapExprs) {
+ uint32_t SrcLocStrSize;
if (!MapExprs.getMapDecl() && !MapExprs.getMapExpr())
- return OMPBuilder.getOrCreateDefaultSrcLocStr();
+ return OMPBuilder.getOrCreateDefaultSrcLocStr(SrcLocStrSize);
SourceLocation Loc;
if (!MapExprs.getMapDecl() && MapExprs.getMapExpr()) {
@@ -9540,7 +9542,7 @@ emitMappingInformation(CodeGenFunction &CGF, llvm::OpenMPIRBuilder &OMPBuilder,
Loc = MapExprs.getMapDecl()->getLocation();
}
- std::string ExprName = "";
+ std::string ExprName;
if (MapExprs.getMapExpr()) {
PrintingPolicy P(CGF.getContext().getLangOpts());
llvm::raw_string_ostream OS(ExprName);
@@ -9551,8 +9553,9 @@ emitMappingInformation(CodeGenFunction &CGF, llvm::OpenMPIRBuilder &OMPBuilder,
}
PresumedLoc PLoc = CGF.getContext().getSourceManager().getPresumedLoc(Loc);
- return OMPBuilder.getOrCreateSrcLocStr(PLoc.getFilename(), ExprName.c_str(),
- PLoc.getLine(), PLoc.getColumn());
+ return OMPBuilder.getOrCreateSrcLocStr(PLoc.getFilename(), ExprName,
+ PLoc.getLine(), PLoc.getColumn(),
+ SrcLocStrSize);
}
/// Emit the arrays used to pass the captures and map information to the
@@ -10216,8 +10219,7 @@ void CGOpenMPRuntime::emitUDMapperArrayInitOrDel(
llvm::Value *Cond;
if (IsInit) {
// base != begin?
- llvm::Value *BaseIsBegin = MapperCGF.Builder.CreateIsNotNull(
- MapperCGF.Builder.CreatePtrDiff(Base, Begin));
+ llvm::Value *BaseIsBegin = MapperCGF.Builder.CreateICmpNE(Base, Begin);
// IsPtrAndObj?
llvm::Value *PtrAndObjBit = MapperCGF.Builder.CreateAnd(
MapType,
@@ -10581,7 +10583,7 @@ void CGOpenMPRuntime::emitTargetCall(
emitOffloadingArraysArgument(
CGF, Info.BasePointersArray, Info.PointersArray, Info.SizesArray,
Info.MapTypesArray, Info.MapNamesArray, Info.MappersArray, Info,
- {/*ForEndTask=*/false});
+ {/*ForEndCall=*/false});
InputInfo.NumberOfTargetItems = Info.NumberOfPtrs;
InputInfo.BasePointersArray =
@@ -11463,7 +11465,7 @@ void CGOpenMPRuntime::emitTargetDataStandAloneCall(
emitOffloadingArraysArgument(
CGF, Info.BasePointersArray, Info.PointersArray, Info.SizesArray,
Info.MapTypesArray, Info.MapNamesArray, Info.MappersArray, Info,
- {/*ForEndTask=*/false});
+ {/*ForEndCall=*/false});
InputInfo.NumberOfTargetItems = Info.NumberOfPtrs;
InputInfo.BasePointersArray =
Address(Info.BasePointersArray, CGM.getPointerAlign());
@@ -12213,6 +12215,26 @@ Address CGOpenMPRuntime::getParameterAddress(CodeGenFunction &CGF,
return CGF.GetAddrOfLocalVar(NativeParam);
}
+/// Return allocator value from expression, or return a null allocator (default
+/// when no allocator specified).
+static llvm::Value *getAllocatorVal(CodeGenFunction &CGF,
+ const Expr *Allocator) {
+ llvm::Value *AllocVal;
+ if (Allocator) {
+ AllocVal = CGF.EmitScalarExpr(Allocator);
+ // According to the standard, the original allocator type is a enum
+ // (integer). Convert to pointer type, if required.
+ AllocVal = CGF.EmitScalarConversion(AllocVal, Allocator->getType(),
+ CGF.getContext().VoidPtrTy,
+ Allocator->getExprLoc());
+ } else {
+ // If no allocator specified, it defaults to the null allocator.
+ AllocVal = llvm::Constant::getNullValue(
+ CGF.CGM.getTypes().ConvertType(CGF.getContext().VoidPtrTy));
+ }
+ return AllocVal;
+}
+
Address CGOpenMPRuntime::getAddressOfLocalVariable(CodeGenFunction &CGF,
const VarDecl *VD) {
if (!VD)
@@ -12249,20 +12271,24 @@ Address CGOpenMPRuntime::getAddressOfLocalVariable(CodeGenFunction &CGF,
}
llvm::Value *ThreadID = getThreadID(CGF, CVD->getBeginLoc());
const auto *AA = CVD->getAttr<OMPAllocateDeclAttr>();
- assert(AA->getAllocator() &&
- "Expected allocator expression for non-default allocator.");
- llvm::Value *Allocator = CGF.EmitScalarExpr(AA->getAllocator());
- // According to the standard, the original allocator type is a enum
- // (integer). Convert to pointer type, if required.
- Allocator = CGF.EmitScalarConversion(
- Allocator, AA->getAllocator()->getType(), CGF.getContext().VoidPtrTy,
- AA->getAllocator()->getExprLoc());
- llvm::Value *Args[] = {ThreadID, Size, Allocator};
-
- llvm::Value *Addr =
- CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
- CGM.getModule(), OMPRTL___kmpc_alloc),
- Args, getName({CVD->getName(), ".void.addr"}));
+ const Expr *Allocator = AA->getAllocator();
+ llvm::Value *AllocVal = getAllocatorVal(CGF, Allocator);
+ llvm::Value *Alignment =
+ AA->getAlignment()
+ ? CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(AA->getAlignment()),
+ CGM.SizeTy, /*isSigned=*/false)
+ : nullptr;
+ SmallVector<llvm::Value *, 4> Args;
+ Args.push_back(ThreadID);
+ if (Alignment)
+ Args.push_back(Alignment);
+ Args.push_back(Size);
+ Args.push_back(AllocVal);
+ llvm::omp::RuntimeFunction FnID =
+ Alignment ? OMPRTL___kmpc_aligned_alloc : OMPRTL___kmpc_alloc;
+ llvm::Value *Addr = CGF.EmitRuntimeCall(
+ OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(), FnID), Args,
+ getName({CVD->getName(), ".void.addr"}));
llvm::FunctionCallee FiniRTLFn = OMPBuilder.getOrCreateRuntimeFunction(
CGM.getModule(), OMPRTL___kmpc_free);
QualType Ty = CGM.getContext().getPointerType(CVD->getType());
@@ -12276,14 +12302,14 @@ Address CGOpenMPRuntime::getAddressOfLocalVariable(CodeGenFunction &CGF,
llvm::FunctionCallee RTLFn;
SourceLocation::UIntTy LocEncoding;
Address Addr;
- const Expr *Allocator;
+ const Expr *AllocExpr;
public:
OMPAllocateCleanupTy(llvm::FunctionCallee RTLFn,
SourceLocation::UIntTy LocEncoding, Address Addr,
- const Expr *Allocator)
+ const Expr *AllocExpr)
: RTLFn(RTLFn), LocEncoding(LocEncoding), Addr(Addr),
- Allocator(Allocator) {}
+ AllocExpr(AllocExpr) {}
void Emit(CodeGenFunction &CGF, Flags /*flags*/) override {
if (!CGF.HaveInsertPoint())
return;
@@ -12292,14 +12318,8 @@ Address CGOpenMPRuntime::getAddressOfLocalVariable(CodeGenFunction &CGF,
CGF, SourceLocation::getFromRawEncoding(LocEncoding));
Args[1] = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
Addr.getPointer(), CGF.VoidPtrTy);
- llvm::Value *AllocVal = CGF.EmitScalarExpr(Allocator);
- // According to the standard, the original allocator type is a enum
- // (integer). Convert to pointer type, if required.
- AllocVal = CGF.EmitScalarConversion(AllocVal, Allocator->getType(),
- CGF.getContext().VoidPtrTy,
- Allocator->getExprLoc());
+ llvm::Value *AllocVal = getAllocatorVal(CGF, AllocExpr);
Args[2] = AllocVal;
-
CGF.EmitRuntimeCall(RTLFn, Args);
}
};
@@ -12307,7 +12327,7 @@ Address CGOpenMPRuntime::getAddressOfLocalVariable(CodeGenFunction &CGF,
UntiedRealAddr.isValid() ? UntiedRealAddr : Address(Addr, Align);
CGF.EHStack.pushCleanup<OMPAllocateCleanupTy>(
NormalAndEHCleanup, FiniRTLFn, CVD->getLocation().getRawEncoding(),
- VDAddr, AA->getAllocator());
+ VDAddr, Allocator);
if (UntiedRealAddr.isValid())
if (auto *Region =
dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo))
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.h b/clang/lib/CodeGen/CGOpenMPRuntime.h
index b83ec78696d1..19754b0cfacc 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.h
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.h
@@ -35,7 +35,6 @@ class ArrayType;
class Constant;
class FunctionType;
class GlobalVariable;
-class StructType;
class Type;
class Value;
class OpenMPIRBuilder;
@@ -48,7 +47,6 @@ class OMPExecutableDirective;
class OMPLoopDirective;
class VarDecl;
class OMPDeclareReductionDecl;
-class IdentifierInfo;
namespace CodeGen {
class Address;
diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
index 866454ddeaed..e09ea5e01b1a 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
@@ -1402,10 +1402,14 @@ void CGOpenMPRuntimeGPU::emitGenericVarsProlog(CodeGenFunction &CGF,
// Allocate space for the variable to be globalized
llvm::Value *AllocArgs[] = {CGF.getTypeSize(VD->getType())};
- llvm::Instruction *VoidPtr =
+ llvm::CallBase *VoidPtr =
CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
CGM.getModule(), OMPRTL___kmpc_alloc_shared),
AllocArgs, VD->getName());
+ // FIXME: We should use the variables actual alignment as an argument.
+ VoidPtr->addRetAttr(llvm::Attribute::get(
+ CGM.getLLVMContext(), llvm::Attribute::Alignment,
+ CGM.getContext().getTargetInfo().getNewAlign() / 8));
// Cast the void pointer and get the address of the globalized variable.
llvm::PointerType *VarPtrTy = CGF.ConvertTypeForMem(VarTy)->getPointerTo();
@@ -1438,10 +1442,13 @@ void CGOpenMPRuntimeGPU::emitGenericVarsProlog(CodeGenFunction &CGF,
// Allocate space for this VLA object to be globalized.
llvm::Value *AllocArgs[] = {CGF.getTypeSize(VD->getType())};
- llvm::Instruction *VoidPtr =
+ llvm::CallBase *VoidPtr =
CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
CGM.getModule(), OMPRTL___kmpc_alloc_shared),
AllocArgs, VD->getName());
+ VoidPtr->addRetAttr(
+ llvm::Attribute::get(CGM.getLLVMContext(), llvm::Attribute::Alignment,
+ CGM.getContext().getTargetInfo().getNewAlign()));
I->getSecond().EscapedVariableLengthDeclsAddrs.emplace_back(
std::pair<llvm::Value *, llvm::Value *>(
@@ -1791,8 +1798,9 @@ static void shuffleAndStore(CodeGenFunction &CGF, Address SrcAddr,
Ptr = Address(PhiSrc, Ptr.getAlignment());
ElemPtr = Address(PhiDest, ElemPtr.getAlignment());
llvm::Value *PtrDiff = Bld.CreatePtrDiff(
- PtrEnd.getPointer(), Bld.CreatePointerBitCastOrAddrSpaceCast(
- Ptr.getPointer(), CGF.VoidPtrTy));
+ CGF.Int8Ty, PtrEnd.getPointer(),
+ Bld.CreatePointerBitCastOrAddrSpaceCast(Ptr.getPointer(),
+ CGF.VoidPtrTy));
Bld.CreateCondBr(Bld.CreateICmpSGT(PtrDiff, Bld.getInt64(IntSize - 1)),
ThenBB, ExitBB);
CGF.EmitBlock(ThenBB);
@@ -3394,12 +3402,13 @@ CGOpenMPRuntimeGPU::getParameterAddress(CodeGenFunction &CGF,
LocalAddr, /*Volatile=*/false, TargetTy, SourceLocation());
// First cast to generic.
TargetAddr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- TargetAddr, TargetAddr->getType()->getPointerElementType()->getPointerTo(
- /*AddrSpace=*/0));
+ TargetAddr, llvm::PointerType::getWithSamePointeeType(
+ cast<llvm::PointerType>(TargetAddr->getType()), /*AddrSpace=*/0));
// Cast from generic to native address space.
TargetAddr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- TargetAddr, TargetAddr->getType()->getPointerElementType()->getPointerTo(
- NativePointeeAddrSpace));
+ TargetAddr, llvm::PointerType::getWithSamePointeeType(
+ cast<llvm::PointerType>(TargetAddr->getType()),
+ NativePointeeAddrSpace));
Address NativeParamAddr = CGF.CreateMemTemp(NativeParamType);
CGF.EmitStoreOfScalar(TargetAddr, NativeParamAddr, /*Volatile=*/false,
NativeParamType);
@@ -3424,8 +3433,8 @@ void CGOpenMPRuntimeGPU::emitOutlinedFunctionCall(
continue;
}
llvm::Value *TargetArg = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- NativeArg,
- NativeArg->getType()->getPointerElementType()->getPointerTo());
+ NativeArg, llvm::PointerType::getWithSamePointeeType(
+ cast<llvm::PointerType>(NativeArg->getType()), /*AddrSpace*/ 0));
TargetArgs.emplace_back(
CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(TargetArg, TargetType));
}
diff --git a/clang/lib/CodeGen/CGRecordLayout.h b/clang/lib/CodeGen/CGRecordLayout.h
index e6665b72bcba..5a3bcdf72f7b 100644
--- a/clang/lib/CodeGen/CGRecordLayout.h
+++ b/clang/lib/CodeGen/CGRecordLayout.h
@@ -93,8 +93,8 @@ struct CGBitFieldInfo {
CharUnits VolatileStorageOffset;
CGBitFieldInfo()
- : Offset(), Size(), IsSigned(), StorageSize(), StorageOffset(),
- VolatileOffset(), VolatileStorageSize(), VolatileStorageOffset() {}
+ : Offset(), Size(), IsSigned(), StorageSize(), VolatileOffset(),
+ VolatileStorageSize() {}
CGBitFieldInfo(unsigned Offset, unsigned Size, bool IsSigned,
unsigned StorageSize, CharUnits StorageOffset)
diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
index cf8313f92587..6f85bca8a201 100644
--- a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -411,7 +411,7 @@ CGRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field,
continue;
}
llvm::Type *Type =
- Types.ConvertTypeForMem(Field->getType(), /*ForBitFields=*/true);
+ Types.ConvertTypeForMem(Field->getType(), /*ForBitField=*/true);
// If we don't have a run yet, or don't live within the previous run's
// allocated storage then we allocate some storage and start a new run.
if (Run == FieldEnd || BitOffset >= Tail) {
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index ef0068cd3b0c..520483bc08b6 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -2109,42 +2109,35 @@ AddVariableConstraints(const std::string &Constraint, const Expr &AsmExpr,
return (EarlyClobber ? "&{" : "{") + Register.str() + "}";
}
-llvm::Value*
-CodeGenFunction::EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info,
- LValue InputValue, QualType InputType,
- std::string &ConstraintStr,
- SourceLocation Loc) {
- llvm::Value *Arg;
+std::pair<llvm::Value*, llvm::Type *> CodeGenFunction::EmitAsmInputLValue(
+ const TargetInfo::ConstraintInfo &Info, LValue InputValue,
+ QualType InputType, std::string &ConstraintStr, SourceLocation Loc) {
if (Info.allowsRegister() || !Info.allowsMemory()) {
- if (CodeGenFunction::hasScalarEvaluationKind(InputType)) {
- Arg = EmitLoadOfLValue(InputValue, Loc).getScalarVal();
- } else {
- llvm::Type *Ty = ConvertType(InputType);
- uint64_t Size = CGM.getDataLayout().getTypeSizeInBits(Ty);
- if ((Size <= 64 && llvm::isPowerOf2_64(Size)) ||
- getTargetHooks().isScalarizableAsmOperand(*this, Ty)) {
- Ty = llvm::IntegerType::get(getLLVMContext(), Size);
- Ty = llvm::PointerType::getUnqual(Ty);
+ if (CodeGenFunction::hasScalarEvaluationKind(InputType))
+ return {EmitLoadOfLValue(InputValue, Loc).getScalarVal(), nullptr};
- Arg = Builder.CreateLoad(
- Builder.CreateBitCast(InputValue.getAddress(*this), Ty));
- } else {
- Arg = InputValue.getPointer(*this);
- ConstraintStr += '*';
- }
+ llvm::Type *Ty = ConvertType(InputType);
+ uint64_t Size = CGM.getDataLayout().getTypeSizeInBits(Ty);
+ if ((Size <= 64 && llvm::isPowerOf2_64(Size)) ||
+ getTargetHooks().isScalarizableAsmOperand(*this, Ty)) {
+ Ty = llvm::IntegerType::get(getLLVMContext(), Size);
+ Ty = llvm::PointerType::getUnqual(Ty);
+
+ return {Builder.CreateLoad(
+ Builder.CreateBitCast(InputValue.getAddress(*this), Ty)),
+ nullptr};
}
- } else {
- Arg = InputValue.getPointer(*this);
- ConstraintStr += '*';
}
- return Arg;
+ Address Addr = InputValue.getAddress(*this);
+ ConstraintStr += '*';
+ return {Addr.getPointer(), Addr.getElementType()};
}
-llvm::Value* CodeGenFunction::EmitAsmInput(
- const TargetInfo::ConstraintInfo &Info,
- const Expr *InputExpr,
- std::string &ConstraintStr) {
+std::pair<llvm::Value *, llvm::Type *>
+CodeGenFunction::EmitAsmInput(const TargetInfo::ConstraintInfo &Info,
+ const Expr *InputExpr,
+ std::string &ConstraintStr) {
// If this can't be a register or memory, i.e., has to be a constant
// (immediate or symbolic), try to emit it as such.
if (!Info.allowsRegister() && !Info.allowsMemory()) {
@@ -2155,19 +2148,20 @@ llvm::Value* CodeGenFunction::EmitAsmInput(
llvm::APSInt IntResult;
if (EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(),
getContext()))
- return llvm::ConstantInt::get(getLLVMContext(), IntResult);
+ return {llvm::ConstantInt::get(getLLVMContext(), IntResult), nullptr};
}
Expr::EvalResult Result;
if (InputExpr->EvaluateAsInt(Result, getContext()))
- return llvm::ConstantInt::get(getLLVMContext(), Result.Val.getInt());
+ return {llvm::ConstantInt::get(getLLVMContext(), Result.Val.getInt()),
+ nullptr};
}
if (Info.allowsRegister() || !Info.allowsMemory())
if (CodeGenFunction::hasScalarEvaluationKind(InputExpr->getType()))
- return EmitScalarExpr(InputExpr);
+ return {EmitScalarExpr(InputExpr), nullptr};
if (InputExpr->getStmtClass() == Expr::CXXThisExprClass)
- return EmitScalarExpr(InputExpr);
+ return {EmitScalarExpr(InputExpr), nullptr};
InputExpr = InputExpr->IgnoreParenNoopCasts(getContext());
LValue Dest = EmitLValue(InputExpr);
return EmitAsmInputLValue(Info, Dest, InputExpr->getType(), ConstraintStr,
@@ -2209,6 +2203,7 @@ static void UpdateAsmCallInst(llvm::CallBase &Result, bool HasSideEffect,
bool HasUnwindClobber, bool ReadOnly,
bool ReadNone, bool NoMerge, const AsmStmt &S,
const std::vector<llvm::Type *> &ResultRegTypes,
+ const std::vector<llvm::Type *> &ArgElemTypes,
CodeGenFunction &CGF,
std::vector<llvm::Value *> &RegResults) {
if (!HasUnwindClobber)
@@ -2224,6 +2219,15 @@ static void UpdateAsmCallInst(llvm::CallBase &Result, bool HasSideEffect,
Result.addFnAttr(llvm::Attribute::ReadOnly);
}
+ // Add elementtype attribute for indirect constraints.
+ for (auto Pair : llvm::enumerate(ArgElemTypes)) {
+ if (Pair.value()) {
+ auto Attr = llvm::Attribute::get(
+ CGF.getLLVMContext(), llvm::Attribute::ElementType, Pair.value());
+ Result.addParamAttr(Pair.index(), Attr);
+ }
+ }
+
// Slap the source location of the inline asm into a !srcloc metadata on the
// call.
if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(&S))
@@ -2291,6 +2295,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
std::vector<llvm::Type *> ResultRegTypes;
std::vector<llvm::Type *> ResultTruncRegTypes;
std::vector<llvm::Type *> ArgTypes;
+ std::vector<llvm::Type *> ArgElemTypes;
std::vector<llvm::Value*> Args;
llvm::BitVector ResultTypeRequiresCast;
@@ -2298,6 +2303,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
std::string InOutConstraints;
std::vector<llvm::Value*> InOutArgs;
std::vector<llvm::Type*> InOutArgTypes;
+ std::vector<llvm::Type*> InOutArgElemTypes;
// Keep track of out constraints for tied input operand.
std::vector<std::string> OutputConstraints;
@@ -2399,21 +2405,19 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
std::max((uint64_t)LargestVectorWidth,
VT->getPrimitiveSizeInBits().getKnownMinSize());
} else {
- llvm::Type *DestAddrTy = Dest.getAddress(*this).getType();
- llvm::Value *DestPtr = Dest.getPointer(*this);
+ Address DestAddr = Dest.getAddress(*this);
// Matrix types in memory are represented by arrays, but accessed through
// vector pointers, with the alignment specified on the access operation.
// For inline assembly, update pointer arguments to use vector pointers.
// Otherwise there will be a mis-match if the matrix is also an
// input-argument which is represented as vector.
- if (isa<MatrixType>(OutExpr->getType().getCanonicalType())) {
- DestAddrTy = llvm::PointerType::get(
- ConvertType(OutExpr->getType()),
- cast<llvm::PointerType>(DestAddrTy)->getAddressSpace());
- DestPtr = Builder.CreateBitCast(DestPtr, DestAddrTy);
- }
- ArgTypes.push_back(DestAddrTy);
- Args.push_back(DestPtr);
+ if (isa<MatrixType>(OutExpr->getType().getCanonicalType()))
+ DestAddr = Builder.CreateElementBitCast(
+ DestAddr, ConvertType(OutExpr->getType()));
+
+ ArgTypes.push_back(DestAddr.getType());
+ ArgElemTypes.push_back(DestAddr.getElementType());
+ Args.push_back(DestAddr.getPointer());
Constraints += "=*";
Constraints += OutputConstraint;
ReadOnly = ReadNone = false;
@@ -2423,9 +2427,11 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
InOutConstraints += ',';
const Expr *InputExpr = S.getOutputExpr(i);
- llvm::Value *Arg = EmitAsmInputLValue(Info, Dest, InputExpr->getType(),
- InOutConstraints,
- InputExpr->getExprLoc());
+ llvm::Value *Arg;
+ llvm::Type *ArgElemType;
+ std::tie(Arg, ArgElemType) = EmitAsmInputLValue(
+ Info, Dest, InputExpr->getType(), InOutConstraints,
+ InputExpr->getExprLoc());
if (llvm::Type* AdjTy =
getTargetHooks().adjustInlineAsmType(*this, OutputConstraint,
@@ -2444,6 +2450,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
InOutConstraints += OutputConstraint;
InOutArgTypes.push_back(Arg->getType());
+ InOutArgElemTypes.push_back(ArgElemType);
InOutArgs.push_back(Arg);
}
}
@@ -2483,7 +2490,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
getTarget(), CGM, S, false /* No EarlyClobber */);
std::string ReplaceConstraint (InputConstraint);
- llvm::Value *Arg = EmitAsmInput(Info, InputExpr, Constraints);
+ llvm::Value *Arg;
+ llvm::Type *ArgElemType;
+ std::tie(Arg, ArgElemType) = EmitAsmInput(Info, InputExpr, Constraints);
// If this input argument is tied to a larger output result, extend the
// input to be the same size as the output. The LLVM backend wants to see
@@ -2528,10 +2537,19 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
VT->getPrimitiveSizeInBits().getKnownMinSize());
ArgTypes.push_back(Arg->getType());
+ ArgElemTypes.push_back(ArgElemType);
Args.push_back(Arg);
Constraints += InputConstraint;
}
+ // Append the "input" part of inout constraints.
+ for (unsigned i = 0, e = InOutArgs.size(); i != e; i++) {
+ ArgTypes.push_back(InOutArgTypes[i]);
+ ArgElemTypes.push_back(InOutArgElemTypes[i]);
+ Args.push_back(InOutArgs[i]);
+ }
+ Constraints += InOutConstraints;
+
// Labels
SmallVector<llvm::BasicBlock *, 16> Transfer;
llvm::BasicBlock *Fallthrough = nullptr;
@@ -2546,21 +2564,15 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
llvm::BlockAddress::get(CurFn, Dest.getBlock());
Args.push_back(BA);
ArgTypes.push_back(BA->getType());
+ ArgElemTypes.push_back(nullptr);
if (!Constraints.empty())
Constraints += ',';
- Constraints += 'X';
+ Constraints += 'i';
}
Fallthrough = createBasicBlock("asm.fallthrough");
}
}
- // Append the "input" part of inout constraints last.
- for (unsigned i = 0, e = InOutArgs.size(); i != e; i++) {
- ArgTypes.push_back(InOutArgTypes[i]);
- Args.push_back(InOutArgs[i]);
- }
- Constraints += InOutConstraints;
-
bool HasUnwindClobber = false;
// Clobbers
@@ -2647,18 +2659,18 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
EmitBlock(Fallthrough);
UpdateAsmCallInst(cast<llvm::CallBase>(*Result), HasSideEffect, false,
ReadOnly, ReadNone, InNoMergeAttributedStmt, S,
- ResultRegTypes, *this, RegResults);
+ ResultRegTypes, ArgElemTypes, *this, RegResults);
} else if (HasUnwindClobber) {
llvm::CallBase *Result = EmitCallOrInvoke(IA, Args, "");
UpdateAsmCallInst(*Result, HasSideEffect, true, ReadOnly, ReadNone,
- InNoMergeAttributedStmt, S, ResultRegTypes, *this,
- RegResults);
+ InNoMergeAttributedStmt, S, ResultRegTypes, ArgElemTypes,
+ *this, RegResults);
} else {
llvm::CallInst *Result =
Builder.CreateCall(IA, Args, getBundlesForFunclet(IA));
UpdateAsmCallInst(cast<llvm::CallBase>(*Result), HasSideEffect, false,
ReadOnly, ReadNone, InNoMergeAttributedStmt, S,
- ResultRegTypes, *this, RegResults);
+ ResultRegTypes, ArgElemTypes, *this, RegResults);
}
assert(RegResults.size() == ResultRegTypes.size());
diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index 4c11f7d67534..0db59dd2624c 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -2584,7 +2584,67 @@ static void emitOMPSimdRegion(CodeGenFunction &CGF, const OMPLoopDirective &S,
}
}
+static bool isSupportedByOpenMPIRBuilder(const OMPExecutableDirective &S) {
+ // Check for unsupported clauses
+ if (!S.clauses().empty()) {
+ // Currently no clause is supported
+ return false;
+ }
+
+ // Check if we have a statement with the ordered directive.
+ // Visit the statement hierarchy to find a compound statement
+ // with a ordered directive in it.
+ if (const auto *CanonLoop = dyn_cast<OMPCanonicalLoop>(S.getRawStmt())) {
+ if (const Stmt *SyntacticalLoop = CanonLoop->getLoopStmt()) {
+ for (const Stmt *SubStmt : SyntacticalLoop->children()) {
+ if (!SubStmt)
+ continue;
+ if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(SubStmt)) {
+ for (const Stmt *CSSubStmt : CS->children()) {
+ if (!CSSubStmt)
+ continue;
+ if (isa<OMPOrderedDirective>(CSSubStmt)) {
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
+ bool UseOMPIRBuilder =
+ CGM.getLangOpts().OpenMPIRBuilder && isSupportedByOpenMPIRBuilder(S);
+ if (UseOMPIRBuilder) {
+ auto &&CodeGenIRBuilder = [this, &S, UseOMPIRBuilder](CodeGenFunction &CGF,
+ PrePostActionTy &) {
+ // Use the OpenMPIRBuilder if enabled.
+ if (UseOMPIRBuilder) {
+ // Emit the associated statement and get its loop representation.
+ llvm::DebugLoc DL = SourceLocToDebugLoc(S.getBeginLoc());
+ const Stmt *Inner = S.getRawStmt();
+ llvm::CanonicalLoopInfo *CLI =
+ EmitOMPCollapsedCanonicalLoopNest(Inner, 1);
+
+ llvm::OpenMPIRBuilder &OMPBuilder =
+ CGM.getOpenMPRuntime().getOMPBuilder();
+ // Add SIMD specific metadata
+ OMPBuilder.applySimd(DL, CLI);
+ return;
+ }
+ };
+ {
+ auto LPCRegion =
+ CGOpenMPRuntime::LastprivateConditionalRAII::disable(*this, S);
+ OMPLexicalScope Scope(*this, S, OMPD_unknown);
+ CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_simd,
+ CodeGenIRBuilder);
+ }
+ return;
+ }
+
ParentLoopDirectiveForScanRegion ScanRegion(*this, S);
OMPFirstScanLoop = true;
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
@@ -4460,8 +4520,9 @@ void CodeGenFunction::EmitOMPTaskBasedDirective(
CGF.getContext().getASTRecordLayout(CaptureRecord);
unsigned Offset =
Layout.getFieldOffset(It->second->getFieldIndex()) / CharWidth;
- (void)DI->EmitDeclareOfAutoVariable(SharedVar, ContextValue,
- CGF.Builder, false);
+ if (CGF.CGM.getCodeGenOpts().hasReducedDebugInfo())
+ (void)DI->EmitDeclareOfAutoVariable(SharedVar, ContextValue,
+ CGF.Builder, false);
llvm::Instruction &Last = CGF.Builder.GetInsertBlock()->back();
// Get the call dbg.declare instruction we just created and update
// its DIExpression to add offset to base address.
@@ -4560,8 +4621,10 @@ void CodeGenFunction::EmitOMPTaskBasedDirective(
CGF.getContext().getDeclAlign(Pair.first));
Scope.addPrivate(Pair.first, [Replacement]() { return Replacement; });
if (auto *DI = CGF.getDebugInfo())
- DI->EmitDeclareOfAutoVariable(Pair.first, Pair.second.getPointer(),
- CGF.Builder, /*UsePointerValue*/ true);
+ if (CGF.CGM.getCodeGenOpts().hasReducedDebugInfo())
+ (void)DI->EmitDeclareOfAutoVariable(
+ Pair.first, Pair.second.getPointer(), CGF.Builder,
+ /*UsePointerValue*/ true);
}
// Adjust mapping for internal locals by mapping actual memory instead of
// a pointer to this memory.
@@ -6046,6 +6109,7 @@ static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
case OMPC_inbranch:
case OMPC_notinbranch:
case OMPC_link:
+ case OMPC_indirect:
case OMPC_use:
case OMPC_novariants:
case OMPC_nocontext:
@@ -6789,7 +6853,7 @@ void CodeGenFunction::EmitOMPTargetDataDirective(
public:
explicit DevicePointerPrivActionTy(bool &PrivatizeDevicePointers)
- : PrePostActionTy(), PrivatizeDevicePointers(PrivatizeDevicePointers) {}
+ : PrivatizeDevicePointers(PrivatizeDevicePointers) {}
void Enter(CodeGenFunction &CGF) override {
PrivatizeDevicePointers = true;
}
diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp
index 482499da1b0f..c839376880c4 100644
--- a/clang/lib/CodeGen/CGVTables.cpp
+++ b/clang/lib/CodeGen/CGVTables.cpp
@@ -1178,7 +1178,7 @@ bool CodeGenModule::HasLTOVisibilityPublicStd(const CXXRecordDecl *RD) {
return false;
const DeclContext *DC = RD;
- while (1) {
+ while (true) {
auto *D = cast<Decl>(DC);
DC = DC->getParent();
if (isa<TranslationUnitDecl>(DC->getRedeclContext())) {
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index e6adec6948af..50e1638924d1 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -740,7 +740,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
#include "clang/Basic/Sanitizers.def"
#undef SANITIZER
- } while (0);
+ } while (false);
if (D) {
bool NoSanitizeCoverage = false;
@@ -882,6 +882,13 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
if (Offset)
Fn->addFnAttr("patchable-function-prefix", std::to_string(Offset));
}
+ // Instruct that functions for COFF/CodeView targets should start with a
+ // patchable instruction, but only on x86/x64. Don't forward this to ARM/ARM64
+ // backends as they don't need it -- instructions on these architectures are
+ // always atomically patchable at runtime.
+ if (CGM.getCodeGenOpts().HotPatch &&
+ getContext().getTargetInfo().getTriple().isX86())
+ Fn->addFnAttr("patchable-function", "prologue-short-redirect");
// Add no-jump-tables value.
if (CGM.getCodeGenOpts().NoUseJumpTables)
@@ -1595,9 +1602,9 @@ void CodeGenFunction::EmitBranchToCounterBlock(
if (!InstrumentRegions || !isInstrumentedCondition(Cond))
return EmitBranchOnBoolExpr(Cond, TrueBlock, FalseBlock, TrueCount, LH);
- llvm::BasicBlock *ThenBlock = NULL;
- llvm::BasicBlock *ElseBlock = NULL;
- llvm::BasicBlock *NextBlock = NULL;
+ llvm::BasicBlock *ThenBlock = nullptr;
+ llvm::BasicBlock *ElseBlock = nullptr;
+ llvm::BasicBlock *NextBlock = nullptr;
// Create the block we'll use to increment the appropriate counter.
llvm::BasicBlock *CounterIncrBlock = createBasicBlock("lop.rhscnt");
@@ -2109,6 +2116,7 @@ llvm::Value *CodeGenFunction::emitArrayLength(const ArrayType *origArrayType,
// Create the actual GEP.
addr = Address(Builder.CreateInBoundsGEP(
addr.getElementType(), addr.getPointer(), gepIndices, "array.begin"),
+ ConvertTypeForMem(eltType),
addr.getAlignment());
}
@@ -2246,32 +2254,36 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
// Unknown size indication requires no size computation.
// Otherwise, evaluate and record it.
- if (const Expr *size = vat->getSizeExpr()) {
+ if (const Expr *sizeExpr = vat->getSizeExpr()) {
// It's possible that we might have emitted this already,
// e.g. with a typedef and a pointer to it.
- llvm::Value *&entry = VLASizeMap[size];
+ llvm::Value *&entry = VLASizeMap[sizeExpr];
if (!entry) {
- llvm::Value *Size = EmitScalarExpr(size);
+ llvm::Value *size = EmitScalarExpr(sizeExpr);
// C11 6.7.6.2p5:
// If the size is an expression that is not an integer constant
// expression [...] each time it is evaluated it shall have a value
// greater than zero.
- if (SanOpts.has(SanitizerKind::VLABound) &&
- size->getType()->isSignedIntegerType()) {
+ if (SanOpts.has(SanitizerKind::VLABound)) {
SanitizerScope SanScope(this);
- llvm::Value *Zero = llvm::Constant::getNullValue(Size->getType());
+ llvm::Value *Zero = llvm::Constant::getNullValue(size->getType());
+ clang::QualType SEType = sizeExpr->getType();
+ llvm::Value *CheckCondition =
+ SEType->isSignedIntegerType()
+ ? Builder.CreateICmpSGT(size, Zero)
+ : Builder.CreateICmpUGT(size, Zero);
llvm::Constant *StaticArgs[] = {
- EmitCheckSourceLocation(size->getBeginLoc()),
- EmitCheckTypeDescriptor(size->getType())};
- EmitCheck(std::make_pair(Builder.CreateICmpSGT(Size, Zero),
- SanitizerKind::VLABound),
- SanitizerHandler::VLABoundNotPositive, StaticArgs, Size);
+ EmitCheckSourceLocation(sizeExpr->getBeginLoc()),
+ EmitCheckTypeDescriptor(SEType)};
+ EmitCheck(std::make_pair(CheckCondition, SanitizerKind::VLABound),
+ SanitizerHandler::VLABoundNotPositive, StaticArgs, size);
}
// Always zexting here would be wrong if it weren't
// undefined behavior to have a negative bound.
- entry = Builder.CreateIntCast(Size, SizeTy, /*signed*/ false);
+ // FIXME: What about when size's type is larger than size_t?
+ entry = Builder.CreateIntCast(size, SizeTy, /*signed*/ false);
}
}
type = vat->getElementType();
@@ -2694,7 +2706,7 @@ void CodeGenFunction::emitAlignmentAssumptionCheck(
SanitizerScope SanScope(this);
if (!OffsetValue)
- OffsetValue = Builder.getInt1(0); // no offset.
+ OffsetValue = Builder.getInt1(false); // no offset.
llvm::Constant *StaticData[] = {EmitCheckSourceLocation(Loc),
EmitCheckSourceLocation(SecondaryLoc),
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index f76ce8a6400d..6db888dcec08 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -46,7 +46,6 @@ namespace llvm {
class BasicBlock;
class LLVMContext;
class MDNode;
-class Module;
class SwitchInst;
class Twine;
class Value;
@@ -55,13 +54,11 @@ class CanonicalLoopInfo;
namespace clang {
class ASTContext;
-class BlockDecl;
class CXXDestructorDecl;
class CXXForRangeStmt;
class CXXTryStmt;
class Decl;
class LabelDecl;
-class EnumConstantDecl;
class FunctionDecl;
class FunctionProtoType;
class LabelStmt;
@@ -80,7 +77,6 @@ class ObjCAtSynchronizedStmt;
class ObjCAutoreleasePoolStmt;
class OMPUseDevicePtrClause;
class OMPUseDeviceAddrClause;
-class ReturnsNonNullAttr;
class SVETypeFlags;
class OMPExecutableDirective;
@@ -92,12 +88,10 @@ namespace CodeGen {
class CodeGenTypes;
class CGCallee;
class CGFunctionInfo;
-class CGRecordLayout;
class CGBlockInfo;
class CGCXXABI;
class BlockByrefHelpers;
class BlockByrefInfo;
-class BlockFlags;
class BlockFieldFlags;
class RegionCodeGenTy;
class TargetCodeGenInfo;
@@ -182,6 +176,7 @@ template <> struct DominatingValue<Address> {
struct saved_type {
DominatingLLVMValue::saved_type SavedValue;
+ llvm::Type *ElementType;
CharUnits Alignment;
};
@@ -190,11 +185,11 @@ template <> struct DominatingValue<Address> {
}
static saved_type save(CodeGenFunction &CGF, type value) {
return { DominatingLLVMValue::save(CGF, value.getPointer()),
- value.getAlignment() };
+ value.getElementType(), value.getAlignment() };
}
static type restore(CodeGenFunction &CGF, saved_type value) {
return Address(DominatingLLVMValue::restore(CGF, value.SavedValue),
- value.Alignment);
+ value.ElementType, value.Alignment);
}
};
@@ -241,11 +236,10 @@ public:
/// A jump destination is an abstract label, branching to which may
/// require a jump out through normal cleanups.
struct JumpDest {
- JumpDest() : Block(nullptr), ScopeDepth(), Index(0) {}
- JumpDest(llvm::BasicBlock *Block,
- EHScopeStack::stable_iterator Depth,
+ JumpDest() : Block(nullptr), Index(0) {}
+ JumpDest(llvm::BasicBlock *Block, EHScopeStack::stable_iterator Depth,
unsigned Index)
- : Block(Block), ScopeDepth(Depth), Index(Index) {}
+ : Block(Block), ScopeDepth(Depth), Index(Index) {}
bool isValid() const { return Block != nullptr; }
llvm::BasicBlock *getBlock() const { return Block; }
@@ -4677,13 +4671,14 @@ private:
SmallVectorImpl<llvm::Value *> &IRCallArgs,
unsigned &IRCallArgPos);
- llvm::Value* EmitAsmInput(const TargetInfo::ConstraintInfo &Info,
- const Expr *InputExpr, std::string &ConstraintStr);
+ std::pair<llvm::Value *, llvm::Type *>
+ EmitAsmInput(const TargetInfo::ConstraintInfo &Info, const Expr *InputExpr,
+ std::string &ConstraintStr);
- llvm::Value* EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info,
- LValue InputValue, QualType InputType,
- std::string &ConstraintStr,
- SourceLocation Loc);
+ std::pair<llvm::Value *, llvm::Type *>
+ EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info, LValue InputValue,
+ QualType InputType, std::string &ConstraintStr,
+ SourceLocation Loc);
/// Attempts to statically evaluate the object size of E. If that
/// fails, emits code to figure the size of E out for us. This is
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 36b7ce87336c..d534cf182f5a 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -565,7 +565,9 @@ void CodeGenModule::Release() {
"__amdgpu_device_library_preserve_asan_functions_ptr", nullptr,
llvm::GlobalVariable::NotThreadLocal);
addCompilerUsedGlobal(Var);
- getModule().addModuleFlag(llvm::Module::Override, "amdgpu_hostcall", 1);
+ if (!getModule().getModuleFlag("amdgpu_hostcall")) {
+ getModule().addModuleFlag(llvm::Module::Override, "amdgpu_hostcall", 1);
+ }
}
emitLLVMUsed();
@@ -610,7 +612,7 @@ void CodeGenModule::Release() {
if (Context.getLangOpts().SemanticInterposition)
// Require various optimization to respect semantic interposition.
- getModule().setSemanticInterposition(1);
+ getModule().setSemanticInterposition(true);
if (CodeGenOpts.EmitCodeView) {
// Indicate that we want CodeView in the metadata.
@@ -710,6 +712,9 @@ void CodeGenModule::Release() {
1);
}
+ if (CodeGenOpts.IBTSeal)
+ getModule().addModuleFlag(llvm::Module::Override, "ibt-seal", 1);
+
// Add module metadata for return address signing (ignoring
// non-leaf/all) and stack tagging. These are actually turned on by function
// attributes, but we use module metadata to emit build attributes. This is
@@ -1368,7 +1373,8 @@ static std::string getMangledNameImpl(CodeGenModule &CGM, GlobalDecl GD,
}
void CodeGenModule::UpdateMultiVersionNames(GlobalDecl GD,
- const FunctionDecl *FD) {
+ const FunctionDecl *FD,
+ StringRef &CurName) {
if (!FD->isMultiVersion())
return;
@@ -1400,7 +1406,11 @@ void CodeGenModule::UpdateMultiVersionNames(GlobalDecl GD,
if (ExistingRecord != std::end(Manglings))
Manglings.remove(&(*ExistingRecord));
auto Result = Manglings.insert(std::make_pair(OtherName, OtherGD));
- MangledDeclNames[OtherGD.getCanonicalDecl()] = Result.first->first();
+ StringRef OtherNameRef = MangledDeclNames[OtherGD.getCanonicalDecl()] =
+ Result.first->first();
+ // If this is the current decl is being created, make sure we update the name.
+ if (GD.getCanonicalDecl() == OtherGD.getCanonicalDecl())
+ CurName = OtherNameRef;
if (llvm::GlobalValue *Entry = GetGlobalValue(NonTargetName))
Entry->setName(OtherName);
}
@@ -1819,7 +1829,7 @@ CodeGenModule::getMostBaseClasses(const CXXRecordDecl *RD) {
void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
llvm::Function *F) {
- llvm::AttrBuilder B;
+ llvm::AttrBuilder B(F->getContext());
if (CodeGenOpts.UnwindTables)
B.addAttribute(llvm::Attribute::UWTable);
@@ -1982,7 +1992,7 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
void CodeGenModule::setLLVMFunctionFEnvAttributes(const FunctionDecl *D,
llvm::Function *F) {
if (D->hasAttr<StrictFPAttr>()) {
- llvm::AttrBuilder FuncAttrs;
+ llvm::AttrBuilder FuncAttrs(F->getContext());
FuncAttrs.addAttribute("strictfp");
F->addFnAttrs(FuncAttrs);
}
@@ -2092,12 +2102,12 @@ void CodeGenModule::setNonAliasAttributes(GlobalDecl GD,
if (!D->getAttr<SectionAttr>())
F->addFnAttr("implicit-section-name", SA->getName());
- llvm::AttrBuilder Attrs;
+ llvm::AttrBuilder Attrs(F->getContext());
if (GetCPUAndFeaturesAttributes(GD, Attrs)) {
// We know that GetCPUAndFeaturesAttributes will always have the
// newest set, since it has the newest possible FunctionDecl, so the
// new ones should replace the old.
- llvm::AttrBuilder RemoveAttrs;
+ llvm::AttributeMask RemoveAttrs;
RemoveAttrs.addAttribute("target-cpu");
RemoveAttrs.addAttribute("target-features");
RemoveAttrs.addAttribute("tune-cpu");
@@ -3479,6 +3489,7 @@ void CodeGenModule::emitMultiVersionFunctions() {
void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
const auto *FD = cast<FunctionDecl>(GD.getDecl());
assert(FD && "Not a FunctionDecl?");
+ assert(FD->isCPUDispatchMultiVersion() && "Not a multiversion function?");
const auto *DD = FD->getAttr<CPUDispatchAttr>();
assert(DD && "Not a cpu_dispatch Function?");
llvm::Type *DeclTy = getTypes().ConvertType(FD->getType());
@@ -3489,14 +3500,16 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
}
StringRef ResolverName = getMangledName(GD);
+ UpdateMultiVersionNames(GD, FD, ResolverName);
llvm::Type *ResolverType;
GlobalDecl ResolverGD;
- if (getTarget().supportsIFunc())
+ if (getTarget().supportsIFunc()) {
ResolverType = llvm::FunctionType::get(
llvm::PointerType::get(DeclTy,
Context.getTargetAddressSpace(FD->getType())),
false);
+ }
else {
ResolverType = DeclTy;
ResolverGD = GD;
@@ -3688,8 +3701,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
}
if (FD->isMultiVersion()) {
- if (FD->hasAttr<TargetAttr>())
- UpdateMultiVersionNames(GD, FD);
+ UpdateMultiVersionNames(GD, FD, MangledName);
if (!IsForDefinition)
return GetOrCreateMultiVersionResolver(GD, Ty, FD);
}
@@ -3785,7 +3797,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
if (D)
SetFunctionAttributes(GD, F, IsIncompleteFunction, IsThunk);
if (ExtraAttrs.hasFnAttrs()) {
- llvm::AttrBuilder B(ExtraAttrs, llvm::AttributeList::FunctionIndex);
+ llvm::AttrBuilder B(F->getContext(), ExtraAttrs.getFnAttrs());
F->addFnAttrs(B);
}
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index f1565511f98a..e803022508a4 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -46,7 +46,6 @@ class GlobalValue;
class DataLayout;
class FunctionType;
class LLVMContext;
-class OpenMPIRBuilder;
class IndexedInstrProfReader;
}
@@ -55,17 +54,13 @@ class ASTContext;
class AtomicType;
class FunctionDecl;
class IdentifierInfo;
-class ObjCMethodDecl;
class ObjCImplementationDecl;
-class ObjCCategoryImplDecl;
-class ObjCProtocolDecl;
class ObjCEncodeExpr;
class BlockExpr;
class CharUnits;
class Decl;
class Expr;
class Stmt;
-class InitListExpr;
class StringLiteral;
class NamedDecl;
class ValueDecl;
@@ -78,13 +73,10 @@ class AnnotateAttr;
class CXXDestructorDecl;
class Module;
class CoverageSourceInfo;
-class TargetAttr;
class InitSegAttr;
-struct ParsedTargetAttr;
namespace CodeGen {
-class CallArgList;
class CodeGenFunction;
class CodeGenTBAA;
class CGCXXABI;
@@ -93,8 +85,6 @@ class CGObjCRuntime;
class CGOpenCLRuntime;
class CGOpenMPRuntime;
class CGCUDARuntime;
-class BlockFieldFlags;
-class FunctionArgList;
class CoverageMappingModuleGen;
class TargetCodeGenInfo;
@@ -311,7 +301,7 @@ private:
const TargetInfo &Target;
std::unique_ptr<CGCXXABI> ABI;
llvm::LLVMContext &VMContext;
- std::string ModuleNameHash = "";
+ std::string ModuleNameHash;
std::unique_ptr<CodeGenTBAA> TBAA;
@@ -345,7 +335,7 @@ private:
/// for emission and therefore should only be output if they are actually
/// used. If a decl is in this, then it is known to have not been referenced
/// yet.
- std::map<StringRef, GlobalDecl> DeferredDecls;
+ llvm::DenseMap<StringRef, GlobalDecl> DeferredDecls;
/// This is a list of deferred decls which we have seen that *are* actually
/// referenced. These get code generated when the module is done.
@@ -1478,7 +1468,8 @@ private:
llvm::Constant *GetOrCreateMultiVersionResolver(GlobalDecl GD,
llvm::Type *DeclTy,
const FunctionDecl *FD);
- void UpdateMultiVersionNames(GlobalDecl GD, const FunctionDecl *FD);
+ void UpdateMultiVersionNames(GlobalDecl GD, const FunctionDecl *FD,
+ StringRef &CurName);
llvm::Constant *
GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty, LangAS AddrSpace,
diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp
index ab953c2c7d52..6657f2a91e3d 100644
--- a/clang/lib/CodeGen/CodeGenPGO.cpp
+++ b/clang/lib/CodeGen/CodeGenPGO.cpp
@@ -131,7 +131,7 @@ public:
static_assert(LastHashType <= TooBig, "Too many types in HashType");
PGOHash(PGOHashVersion HashVersion)
- : Working(0), Count(0), HashVersion(HashVersion), MD5() {}
+ : Working(0), Count(0), HashVersion(HashVersion) {}
void combine(HashType Type);
uint64_t finalize();
PGOHashVersion getHashVersion() const { return HashVersion; }
diff --git a/clang/lib/CodeGen/CodeGenTBAA.h b/clang/lib/CodeGen/CodeGenTBAA.h
index e8e006f41616..a65963596fe9 100644
--- a/clang/lib/CodeGen/CodeGenTBAA.h
+++ b/clang/lib/CodeGen/CodeGenTBAA.h
@@ -29,7 +29,6 @@ namespace clang {
class Type;
namespace CodeGen {
-class CGRecordLayout;
// TBAAAccessKind - A kind of TBAA memory access descriptor.
enum class TBAAAccessKind : unsigned {
diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp
index 77721510dfd0..4839e22c4b14 100644
--- a/clang/lib/CodeGen/CodeGenTypes.cpp
+++ b/clang/lib/CodeGen/CodeGenTypes.cpp
@@ -643,11 +643,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
llvm::Type *PointeeType = ConvertTypeForMem(ETy);
if (PointeeType->isVoidTy())
PointeeType = llvm::Type::getInt8Ty(getLLVMContext());
-
- unsigned AS = PointeeType->isFunctionTy()
- ? getDataLayout().getProgramAddressSpace()
- : Context.getTargetAddressSpace(ETy);
-
+ unsigned AS = Context.getTargetAddressSpace(ETy);
ResultType = llvm::PointerType::get(PointeeType, AS);
break;
}
@@ -748,7 +744,13 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
llvm::Type *PointeeType = CGM.getLangOpts().OpenCL
? CGM.getGenericBlockLiteralType()
: ConvertTypeForMem(FTy);
- unsigned AS = Context.getTargetAddressSpace(FTy);
+ // Block pointers lower to function type. For function type,
+ // getTargetAddressSpace() returns default address space for
+ // function pointer i.e. program address space. Therefore, for block
+ // pointers, it is important to pass qualifiers when calling
+ // getTargetAddressSpace(), to ensure that we get the address space
+ // for data pointers and not function pointers.
+ unsigned AS = Context.getTargetAddressSpace(FTy.getQualifiers());
ResultType = llvm::PointerType::get(PointeeType, AS);
break;
}
diff --git a/clang/lib/CodeGen/CodeGenTypes.h b/clang/lib/CodeGen/CodeGenTypes.h
index f8f7542e4c83..28b831222943 100644
--- a/clang/lib/CodeGen/CodeGenTypes.h
+++ b/clang/lib/CodeGen/CodeGenTypes.h
@@ -31,14 +31,9 @@ namespace clang {
class ASTContext;
template <typename> class CanQual;
class CXXConstructorDecl;
-class CXXDestructorDecl;
class CXXMethodDecl;
class CodeGenOptions;
-class FieldDecl;
class FunctionProtoType;
-class ObjCInterfaceDecl;
-class ObjCIvarDecl;
-class PointerType;
class QualType;
class RecordDecl;
class TagDecl;
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 1a15b09c7b2b..2979d92c8417 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -334,59 +334,6 @@ public:
ArrayRef<llvm::Function *> CXXThreadLocalInits,
ArrayRef<const VarDecl *> CXXThreadLocalInitVars) override;
- bool mayNeedDestruction(const VarDecl *VD) const {
- if (VD->needsDestruction(getContext()))
- return true;
-
- // If the variable has an incomplete class type (or array thereof), it
- // might need destruction.
- const Type *T = VD->getType()->getBaseElementTypeUnsafe();
- if (T->getAs<RecordType>() && T->isIncompleteType())
- return true;
-
- return false;
- }
-
- /// Determine whether we will definitely emit this variable with a constant
- /// initializer, either because the language semantics demand it or because
- /// we know that the initializer is a constant.
- // For weak definitions, any initializer available in the current translation
- // is not necessarily reflective of the initializer used; such initializers
- // are ignored unless if InspectInitForWeakDef is true.
- bool
- isEmittedWithConstantInitializer(const VarDecl *VD,
- bool InspectInitForWeakDef = false) const {
- VD = VD->getMostRecentDecl();
- if (VD->hasAttr<ConstInitAttr>())
- return true;
-
- // All later checks examine the initializer specified on the variable. If
- // the variable is weak, such examination would not be correct.
- if (!InspectInitForWeakDef &&
- (VD->isWeak() || VD->hasAttr<SelectAnyAttr>()))
- return false;
-
- const VarDecl *InitDecl = VD->getInitializingDeclaration();
- if (!InitDecl)
- return false;
-
- // If there's no initializer to run, this is constant initialization.
- if (!InitDecl->hasInit())
- return true;
-
- // If we have the only definition, we don't need a thread wrapper if we
- // will emit the value as a constant.
- if (isUniqueGVALinkage(getContext().GetGVALinkageForVariable(VD)))
- return !mayNeedDestruction(VD) && InitDecl->evaluateValue();
-
- // Otherwise, we need a thread wrapper unless we know that every
- // translation unit will emit the value as a constant. We rely on the
- // variable being constant-initialized in every translation unit if it's
- // constant-initialized in any translation unit, which isn't actually
- // guaranteed by the standard but is necessary for sanity.
- return InitDecl->hasConstantInitialization();
- }
-
bool usesThreadWrapperFunction(const VarDecl *VD) const override {
return !isEmittedWithConstantInitializer(VD) ||
mayNeedDestruction(VD);
@@ -697,8 +644,8 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
CharUnits VTablePtrAlign =
CGF.CGM.getDynamicOffsetAlignment(ThisAddr.getAlignment(), RD,
CGF.getPointerAlign());
- llvm::Value *VTable =
- CGF.GetVTablePtr(Address(This, VTablePtrAlign), VTableTy, RD);
+ llvm::Value *VTable = CGF.GetVTablePtr(
+ Address(This, ThisAddr.getElementType(), VTablePtrAlign), VTableTy, RD);
// Apply the offset.
// On ARM64, to reserve extra space in virtual member function pointers,
@@ -4525,8 +4472,7 @@ static void InitCatchParam(CodeGenFunction &CGF,
// pad. The best solution is to fix the personality function.
} else {
// Pull the pointer for the reference type off.
- llvm::Type *PtrTy =
- cast<llvm::PointerType>(LLVMCatchTy)->getElementType();
+ llvm::Type *PtrTy = LLVMCatchTy->getPointerElementType();
// Create the temporary and write the adjusted pointer into it.
Address ExnPtrTmp =
diff --git a/clang/lib/CodeGen/MacroPPCallbacks.h b/clang/lib/CodeGen/MacroPPCallbacks.h
index 32906a000269..d249b5b0eb88 100644
--- a/clang/lib/CodeGen/MacroPPCallbacks.h
+++ b/clang/lib/CodeGen/MacroPPCallbacks.h
@@ -17,7 +17,6 @@
namespace llvm {
class DIMacroFile;
-class DIMacroNode;
}
namespace clang {
class Preprocessor;
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index 5971a7709304..e00ff2b68719 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -401,7 +401,9 @@ public:
ArrayRef<const VarDecl *> CXXThreadLocalInitVars) override;
bool usesThreadWrapperFunction(const VarDecl *VD) const override {
- return false;
+ return getContext().getLangOpts().isCompatibleWithMSVC(
+ LangOptions::MSVC2019_5) &&
+ (!isEmittedWithConstantInitializer(VD) || mayNeedDestruction(VD));
}
LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD,
QualType LValType) override;
@@ -2397,11 +2399,97 @@ void MicrosoftCXXABI::EmitThreadLocalInitFuncs(
}
}
+static llvm::GlobalValue *getTlsGuardVar(CodeGenModule &CGM) {
+ // __tls_guard comes from the MSVC runtime and reflects
+ // whether TLS has been initialized for a particular thread.
+ // It is set from within __dyn_tls_init by the runtime.
+ // Every library and executable has its own variable.
+ llvm::Type *VTy = llvm::Type::getInt8Ty(CGM.getLLVMContext());
+ llvm::Constant *TlsGuardConstant =
+ CGM.CreateRuntimeVariable(VTy, "__tls_guard");
+ llvm::GlobalValue *TlsGuard = cast<llvm::GlobalValue>(TlsGuardConstant);
+
+ TlsGuard->setThreadLocal(true);
+
+ return TlsGuard;
+}
+
+static llvm::FunctionCallee getDynTlsOnDemandInitFn(CodeGenModule &CGM) {
+ // __dyn_tls_on_demand_init comes from the MSVC runtime and triggers
+ // dynamic TLS initialization by calling __dyn_tls_init internally.
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()), {},
+ /*isVarArg=*/false);
+ return CGM.CreateRuntimeFunction(
+ FTy, "__dyn_tls_on_demand_init",
+ llvm::AttributeList::get(CGM.getLLVMContext(),
+ llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::NoUnwind),
+ /*Local=*/true);
+}
+
+static void emitTlsGuardCheck(CodeGenFunction &CGF, llvm::GlobalValue *TlsGuard,
+ llvm::BasicBlock *DynInitBB,
+ llvm::BasicBlock *ContinueBB) {
+ llvm::LoadInst *TlsGuardValue =
+ CGF.Builder.CreateLoad(Address(TlsGuard, CharUnits::One()));
+ llvm::Value *CmpResult =
+ CGF.Builder.CreateICmpEQ(TlsGuardValue, CGF.Builder.getInt8(0));
+ CGF.Builder.CreateCondBr(CmpResult, DynInitBB, ContinueBB);
+}
+
+static void emitDynamicTlsInitializationCall(CodeGenFunction &CGF,
+ llvm::GlobalValue *TlsGuard,
+ llvm::BasicBlock *ContinueBB) {
+ llvm::FunctionCallee Initializer = getDynTlsOnDemandInitFn(CGF.CGM);
+ llvm::Function *InitializerFunction =
+ cast<llvm::Function>(Initializer.getCallee());
+ llvm::CallInst *CallVal = CGF.Builder.CreateCall(InitializerFunction);
+ CallVal->setCallingConv(InitializerFunction->getCallingConv());
+
+ CGF.Builder.CreateBr(ContinueBB);
+}
+
+static void emitDynamicTlsInitialization(CodeGenFunction &CGF) {
+ llvm::BasicBlock *DynInitBB =
+ CGF.createBasicBlock("dyntls.dyn_init", CGF.CurFn);
+ llvm::BasicBlock *ContinueBB =
+ CGF.createBasicBlock("dyntls.continue", CGF.CurFn);
+
+ llvm::GlobalValue *TlsGuard = getTlsGuardVar(CGF.CGM);
+
+ emitTlsGuardCheck(CGF, TlsGuard, DynInitBB, ContinueBB);
+ CGF.Builder.SetInsertPoint(DynInitBB);
+ emitDynamicTlsInitializationCall(CGF, TlsGuard, ContinueBB);
+ CGF.Builder.SetInsertPoint(ContinueBB);
+}
+
LValue MicrosoftCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF,
const VarDecl *VD,
QualType LValType) {
- CGF.CGM.ErrorUnsupported(VD, "thread wrappers");
- return LValue();
+ // Dynamic TLS initialization works by checking the state of a
+ // guard variable (__tls_guard) to see whether TLS initialization
+ // for a thread has happend yet.
+ // If not, the initialization is triggered on-demand
+ // by calling __dyn_tls_on_demand_init.
+ emitDynamicTlsInitialization(CGF);
+
+ // Emit the variable just like any regular global variable.
+
+ llvm::Value *V = CGF.CGM.GetAddrOfGlobalVar(VD);
+ llvm::Type *RealVarTy = CGF.getTypes().ConvertTypeForMem(VD->getType());
+
+ unsigned AS = cast<llvm::PointerType>(V->getType())->getAddressSpace();
+ V = CGF.Builder.CreateBitCast(V, RealVarTy->getPointerTo(AS));
+
+ CharUnits Alignment = CGF.getContext().getDeclAlign(VD);
+ Address Addr(V, Alignment);
+
+ LValue LV = VD->getType()->isReferenceType()
+ ? CGF.EmitLoadOfReferenceLValue(Addr, VD->getType(),
+ AlignmentSource::Decl)
+ : CGF.MakeAddrLValue(Addr, LValType, AlignmentSource::Decl);
+ return LV;
}
static ConstantAddress getInitThreadEpochPtr(CodeGenModule &CGM) {
diff --git a/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp b/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
index f7b83c45022d..9fe7e5d1f5c3 100644
--- a/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
+++ b/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
@@ -156,6 +156,7 @@ public:
CodeGenOpts.setDebuggerTuning(CI.getCodeGenOpts().getDebuggerTuning());
CodeGenOpts.DebugPrefixMap =
CI.getInvocation().getCodeGenOpts().DebugPrefixMap;
+ CodeGenOpts.DebugStrictDwarf = CI.getCodeGenOpts().DebugStrictDwarf;
}
~PCHContainerGenerator() override = default;
diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp
index 85089cdb2200..fb81169003fc 100644
--- a/clang/lib/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CodeGen/TargetInfo.cpp
@@ -855,19 +855,19 @@ public:
if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D)) {
if (const auto *Attr = FD->getAttr<WebAssemblyImportModuleAttr>()) {
llvm::Function *Fn = cast<llvm::Function>(GV);
- llvm::AttrBuilder B;
+ llvm::AttrBuilder B(GV->getContext());
B.addAttribute("wasm-import-module", Attr->getImportModule());
Fn->addFnAttrs(B);
}
if (const auto *Attr = FD->getAttr<WebAssemblyImportNameAttr>()) {
llvm::Function *Fn = cast<llvm::Function>(GV);
- llvm::AttrBuilder B;
+ llvm::AttrBuilder B(GV->getContext());
B.addAttribute("wasm-import-name", Attr->getImportName());
Fn->addFnAttrs(B);
}
if (const auto *Attr = FD->getAttr<WebAssemblyExportNameAttr>()) {
llvm::Function *Fn = cast<llvm::Function>(GV);
- llvm::AttrBuilder B;
+ llvm::AttrBuilder B(GV->getContext());
B.addAttribute("wasm-export-name", Attr->getExportName());
Fn->addFnAttrs(B);
}
@@ -1606,7 +1606,7 @@ static bool isSIMDVectorType(ASTContext &Context, QualType Ty) {
static bool isRecordWithSIMDVectorType(ASTContext &Context, QualType Ty) {
const RecordType *RT = Ty->getAs<RecordType>();
if (!RT)
- return 0;
+ return false;
const RecordDecl *RD = RT->getDecl();
// If this is a C++ record, check the bases first.
@@ -6414,7 +6414,7 @@ public:
// AAPCS guarantees that sp will be 8-byte aligned on any public interface,
// however this is not necessarily true on taking any interrupt. Instruct
// the backend to perform a realignment as part of the function prologue.
- llvm::AttrBuilder B;
+ llvm::AttrBuilder B(Fn->getContext());
B.addStackAlignmentAttr(8);
Fn->addFnAttrs(B);
}
@@ -8282,14 +8282,15 @@ public:
LangAS getGlobalVarAddressSpace(CodeGenModule &CGM,
const VarDecl *D) const override {
- // Check if a global/static variable is defined within address space 1
+ // Check if global/static variable is defined in address space
+ // 1~6 (__flash, __flash1, __flash2, __flash3, __flash4, __flash5)
// but not constant.
LangAS AS = D->getType().getAddressSpace();
- if (isTargetAddressSpace(AS) && toTargetAddressSpace(AS) == 1 &&
- !D->getType().isConstQualified())
+ if (isTargetAddressSpace(AS) && 1 <= toTargetAddressSpace(AS) &&
+ toTargetAddressSpace(AS) <= 6 && !D->getType().isConstQualified())
CGM.getDiags().Report(D->getLocation(),
diag::err_verify_nonconst_addrspace)
- << "__flash";
+ << "__flash*";
return TargetCodeGenInfo::getGlobalVarAddressSpace(CGM, D);
}
@@ -8693,7 +8694,7 @@ Address HexagonABIInfo::EmitVAArgForHexagonLinux(CodeGenFunction &CGF,
llvm::ConstantInt::get(CGF.Int32Ty, ArgSize),
"__new_saved_reg_area_pointer");
- llvm::Value *UsingStack = 0;
+ llvm::Value *UsingStack = nullptr;
UsingStack = CGF.Builder.CreateICmpSGT(__new_saved_reg_area_pointer,
__saved_reg_area_end_pointer);
@@ -8935,9 +8936,9 @@ private:
llvm::Type *coerceKernelArgumentType(llvm::Type *Ty, unsigned FromAS,
unsigned ToAS) const {
// Single value types.
- if (Ty->isPointerTy() && Ty->getPointerAddressSpace() == FromAS)
- return llvm::PointerType::get(
- cast<llvm::PointerType>(Ty)->getElementType(), ToAS);
+ auto *PtrTy = llvm::dyn_cast<llvm::PointerType>(Ty);
+ if (PtrTy && PtrTy->getAddressSpace() == FromAS)
+ return llvm::PointerType::getWithSamePointeeType(PtrTy, ToAS);
return Ty;
}
@@ -9304,16 +9305,9 @@ void AMDGPUTargetCodeGenInfo::setTargetAttributes(
if (FD)
setFunctionDeclAttributes(FD, F, M);
- const bool IsOpenCLKernel =
- M.getLangOpts().OpenCL && FD && FD->hasAttr<OpenCLKernelAttr>();
const bool IsHIPKernel =
M.getLangOpts().HIP && FD && FD->hasAttr<CUDAGlobalAttr>();
- const bool IsOpenMP = M.getLangOpts().OpenMP && !FD;
- if ((IsOpenCLKernel || IsHIPKernel || IsOpenMP) &&
- (M.getTriple().getOS() == llvm::Triple::AMDHSA))
- F->addFnAttr("amdgpu-implicitarg-num-bytes", "56");
-
if (IsHIPKernel)
F->addFnAttr("uniform-work-group-size", "true");
@@ -9340,8 +9334,8 @@ llvm::Constant *AMDGPUTargetCodeGenInfo::getNullPointer(
return llvm::ConstantPointerNull::get(PT);
auto &Ctx = CGM.getContext();
- auto NPT = llvm::PointerType::get(PT->getElementType(),
- Ctx.getTargetAddressSpace(LangAS::opencl_generic));
+ auto NPT = llvm::PointerType::getWithSamePointeeType(
+ PT, Ctx.getTargetAddressSpace(LangAS::opencl_generic));
return llvm::ConstantExpr::getAddrSpaceCast(
llvm::ConstantPointerNull::get(NPT), PT);
}
@@ -10276,9 +10270,9 @@ ABIArgInfo SPIRVABIInfo::classifyKernelArgumentType(QualType Ty) const {
llvm::Type *LTy = CGT.ConvertType(Ty);
auto DefaultAS = getContext().getTargetAddressSpace(LangAS::Default);
auto GlobalAS = getContext().getTargetAddressSpace(LangAS::cuda_device);
- if (LTy->isPointerTy() && LTy->getPointerAddressSpace() == DefaultAS) {
- LTy = llvm::PointerType::get(
- cast<llvm::PointerType>(LTy)->getElementType(), GlobalAS);
+ auto *PtrTy = llvm::dyn_cast<llvm::PointerType>(LTy);
+ if (PtrTy && PtrTy->getAddressSpace() == DefaultAS) {
+ LTy = llvm::PointerType::getWithSamePointeeType(PtrTy, GlobalAS);
return ABIArgInfo::getDirect(LTy, 0, nullptr, false);
}
}
@@ -11417,7 +11411,7 @@ TargetCodeGenInfo::createEnqueuedBlockKernel(CodeGenFunction &CGF,
auto &C = CGF.getLLVMContext();
std::string Name = Invoke->getName().str() + "_kernel";
auto *FT = llvm::FunctionType::get(llvm::Type::getVoidTy(C), ArgTys, false);
- auto *F = llvm::Function::Create(FT, llvm::GlobalValue::InternalLinkage, Name,
+ auto *F = llvm::Function::Create(FT, llvm::GlobalValue::ExternalLinkage, Name,
&CGF.CGM.getModule());
auto IP = CGF.Builder.saveIP();
auto *BB = llvm::BasicBlock::Create(C, "entry", F);
diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h
index aa8bbb60a75f..dfdb2f5f55bb 100644
--- a/clang/lib/CodeGen/TargetInfo.h
+++ b/clang/lib/CodeGen/TargetInfo.h
@@ -38,7 +38,6 @@ class ABIInfo;
class CallArgList;
class CodeGenFunction;
class CGBlockInfo;
-class CGFunctionInfo;
/// TargetCodeGenInfo - This class organizes various target-specific
/// codegeneration issues, like target-specific attributes, builtins and so
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 3b551ea94cc2..2e4ebc10e9ba 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -62,6 +62,7 @@
#include "clang/Driver/SanitizerArgs.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
+#include "clang/Driver/Types.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallSet.h"
@@ -170,13 +171,11 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple,
: Diags(Diags), VFS(std::move(VFS)), Mode(GCCMode),
SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone), LTOMode(LTOK_None),
ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT),
- DriverTitle(Title), CCPrintStatReportFilename(), CCPrintOptionsFilename(),
- CCPrintHeadersFilename(), CCLogDiagnosticsFilename(),
- CCCPrintBindings(false), CCPrintOptions(false), CCPrintHeaders(false),
- CCLogDiagnostics(false), CCGenDiagnostics(false),
- CCPrintProcessStats(false), TargetTriple(TargetTriple),
- CCCGenericGCCName(""), Saver(Alloc), CheckInputsExist(true),
- GenReproducer(false), SuppressMissingInputWarning(false) {
+ DriverTitle(Title), CCCPrintBindings(false), CCPrintOptions(false),
+ CCPrintHeaders(false), CCLogDiagnostics(false), CCGenDiagnostics(false),
+ CCPrintProcessStats(false), TargetTriple(TargetTriple), Saver(Alloc),
+ CheckInputsExist(true), GenReproducer(false),
+ SuppressMissingInputWarning(false) {
// Provide a sane fallback if no VFS is specified.
if (!this->VFS)
this->VFS = llvm::vfs::getRealFileSystem();
@@ -328,7 +327,8 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL,
(PhaseArg = DAL.getLastArg(options::OPT_rewrite_legacy_objc)) ||
(PhaseArg = DAL.getLastArg(options::OPT__migrate)) ||
(PhaseArg = DAL.getLastArg(options::OPT__analyze)) ||
- (PhaseArg = DAL.getLastArg(options::OPT_emit_ast))) {
+ (PhaseArg = DAL.getLastArg(options::OPT_emit_ast)) ||
+ (PhaseArg = DAL.getLastArg(options::OPT_extract_api))) {
FinalPhase = phases::Compile;
// -S only runs up to the backend.
@@ -369,7 +369,20 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
bool HasNostdlib = Args.hasArg(options::OPT_nostdlib);
bool HasNostdlibxx = Args.hasArg(options::OPT_nostdlibxx);
bool HasNodefaultlib = Args.hasArg(options::OPT_nodefaultlibs);
+ bool IgnoreUnused = false;
for (Arg *A : Args) {
+ if (IgnoreUnused)
+ A->claim();
+
+ if (A->getOption().matches(options::OPT_start_no_unused_arguments)) {
+ IgnoreUnused = true;
+ continue;
+ }
+ if (A->getOption().matches(options::OPT_end_no_unused_arguments)) {
+ IgnoreUnused = false;
+ continue;
+ }
+
// Unfortunately, we have to parse some forwarding options (-Xassembler,
// -Xlinker, -Xpreprocessor) because we either integrate their functionality
// (assembler and preprocessor), or bypass a previous driver ('collect2').
@@ -437,7 +450,7 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
// Enforce -static if -miamcu is present.
if (Args.hasFlag(options::OPT_miamcu, options::OPT_mno_iamcu, false))
- DAL->AddFlagArg(0, Opts.getOption(options::OPT_static));
+ DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_static));
// Add a default value of -mlinker-version=, if one was given and the user
// didn't specify one.
@@ -763,6 +776,18 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
llvm::Triple TT(Val);
std::string NormalizedName = TT.normalize();
+ // We want to expand the shortened versions of the triples passed in to
+ // the values used for the bitcode libraries for convenience.
+ if (TT.getVendor() == llvm::Triple::UnknownVendor ||
+ TT.getOS() == llvm::Triple::UnknownOS) {
+ if (TT.getArch() == llvm::Triple::nvptx)
+ TT = llvm::Triple("nvptx-nvidia-cuda");
+ else if (TT.getArch() == llvm::Triple::nvptx64)
+ TT = llvm::Triple("nvptx64-nvidia-cuda");
+ else if (TT.getArch() == llvm::Triple::amdgcn)
+ TT = llvm::Triple("amdgcn-amd-amdhsa");
+ }
+
// Make sure we don't have a duplicate triple.
auto Duplicate = FoundNormalizedTriples.find(NormalizedName);
if (Duplicate != FoundNormalizedTriples.end()) {
@@ -1871,9 +1896,16 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
}
if (C.getArgs().hasArg(options::OPT_print_runtime_dir)) {
- std::string CandidateRuntimePath = TC.getRuntimePath();
- if (getVFS().exists(CandidateRuntimePath))
- llvm::outs() << CandidateRuntimePath << '\n';
+ std::string RuntimePath;
+ // Get the first existing path, if any.
+ for (auto Path : TC.getRuntimePaths()) {
+ if (getVFS().exists(Path)) {
+ RuntimePath = Path;
+ break;
+ }
+ }
+ if (!RuntimePath.empty())
+ llvm::outs() << RuntimePath << '\n';
else
llvm::outs() << TC.getCompilerRTPath() << '\n';
return false;
@@ -3105,7 +3137,7 @@ class OffloadingActionBuilder final {
// We will pass the device action as a host dependence, so we don't
// need to do anything else with them.
CudaDeviceActions.clear();
- return ABRT_Success;
+ return CompileDeviceOnly ? ABRT_Ignore_Host : ABRT_Success;
}
// By default, we produce an action for each device arch.
@@ -3138,6 +3170,7 @@ class OffloadingActionBuilder final {
assert(DeviceLinkerInputs.size() == GpuArchList.size() &&
"Linker inputs and GPU arch list sizes do not match.");
+ ActionList Actions;
// Append a new link action for each device.
unsigned I = 0;
for (auto &LI : DeviceLinkerInputs) {
@@ -3149,22 +3182,29 @@ class OffloadingActionBuilder final {
OffloadAction::DeviceDependences DeviceLinkDeps;
DeviceLinkDeps.add(*DeviceLinkAction, *ToolChains[0],
GpuArchList[I], AssociatedOffloadKind);
- AL.push_back(C.MakeAction<OffloadAction>(DeviceLinkDeps,
- DeviceLinkAction->getType()));
+ Actions.push_back(C.MakeAction<OffloadAction>(
+ DeviceLinkDeps, DeviceLinkAction->getType()));
++I;
}
DeviceLinkerInputs.clear();
// Create a host object from all the device images by embedding them
- // in a fat binary.
+ // in a fat binary for mixed host-device compilation. For device-only
+ // compilation, creates a fat binary.
OffloadAction::DeviceDependences DDeps;
- auto *TopDeviceLinkAction =
- C.MakeAction<LinkJobAction>(AL, types::TY_Object);
- DDeps.add(*TopDeviceLinkAction, *ToolChains[0],
- nullptr, AssociatedOffloadKind);
-
- // Offload the host object to the host linker.
- AL.push_back(C.MakeAction<OffloadAction>(DDeps, TopDeviceLinkAction->getType()));
+ if (!CompileDeviceOnly || !BundleOutput.hasValue() ||
+ BundleOutput.getValue()) {
+ auto *TopDeviceLinkAction = C.MakeAction<LinkJobAction>(
+ Actions,
+ CompileDeviceOnly ? types::TY_HIP_FATBIN : types::TY_Object);
+ DDeps.add(*TopDeviceLinkAction, *ToolChains[0], nullptr,
+ AssociatedOffloadKind);
+ // Offload the host object to the host linker.
+ AL.push_back(
+ C.MakeAction<OffloadAction>(DDeps, TopDeviceLinkAction->getType()));
+ } else {
+ AL.append(Actions);
+ }
}
Action* appendLinkHostActions(ActionList &AL) override { return AL.back(); }
@@ -3551,15 +3591,18 @@ public:
return false;
}
- Action* makeHostLinkAction() {
- // Build a list of device linking actions.
- ActionList DeviceAL;
+ void appendDeviceLinkActions(ActionList &AL) {
for (DeviceActionBuilder *SB : SpecializedBuilders) {
if (!SB->isValid())
continue;
- SB->appendLinkDeviceActions(DeviceAL);
+ SB->appendLinkDeviceActions(AL);
}
+ }
+ Action *makeHostLinkAction() {
+ // Build a list of device linking actions.
+ ActionList DeviceAL;
+ appendDeviceLinkActions(DeviceAL);
if (DeviceAL.empty())
return nullptr;
@@ -3775,14 +3818,6 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
}
}
- // FIXME: Linking separate translation units for SPIR-V is not supported yet.
- // It can be done either by LLVM IR linking before conversion of the final
- // linked module to SPIR-V or external SPIR-V linkers can be used e.g.
- // spirv-link.
- if (C.getDefaultToolChain().getTriple().isSPIRV() && Inputs.size() > 1) {
- Diag(clang::diag::warn_drv_spirv_linking_multiple_inputs_unsupported);
- }
-
handleArguments(C, Args, Inputs, Actions);
// Builder to be used to build offloading actions.
@@ -3822,15 +3857,8 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
// Queue linker inputs.
if (Phase == phases::Link) {
assert(Phase == PL.back() && "linking must be final compilation step.");
- // Compilation phases are setup per language, however for SPIR-V the
- // final linking phase is meaningless since the compilation phase
- // produces the final binary.
- // FIXME: OpenCL - we could strip linking phase out from OpenCL
- // compilation phases if we could verify it is not needed by any target.
- if (!C.getDefaultToolChain().getTriple().isSPIRV()) {
- LinkerInputs.push_back(Current);
- Current = nullptr;
- }
+ LinkerInputs.push_back(Current);
+ Current = nullptr;
break;
}
@@ -3888,6 +3916,13 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
}
// Add a link action if necessary.
+
+ if (LinkerInputs.empty()) {
+ Arg *FinalPhaseArg;
+ if (getFinalPhase(Args, &FinalPhaseArg) == phases::Link)
+ OffloadBuilder.appendDeviceLinkActions(Actions);
+ }
+
if (!LinkerInputs.empty()) {
if (Action *Wrapper = OffloadBuilder.makeHostLinkAction())
LinkerInputs.push_back(Wrapper);
@@ -4036,7 +4071,8 @@ Action *Driver::ConstructPhaseAction(
OutputTy = types::TY_ModuleFile;
}
- if (Args.hasArg(options::OPT_fsyntax_only)) {
+ if (Args.hasArg(options::OPT_fsyntax_only) ||
+ Args.hasArg(options::OPT_extract_api)) {
// Syntax checks should not emit a PCH file
OutputTy = types::TY_Nothing;
}
@@ -4064,6 +4100,8 @@ Action *Driver::ConstructPhaseAction(
return C.MakeAction<CompileJobAction>(Input, types::TY_ModuleFile);
if (Args.hasArg(options::OPT_verify_pch))
return C.MakeAction<VerifyPCHJobAction>(Input, types::TY_Nothing);
+ if (Args.hasArg(options::OPT_extract_api))
+ return C.MakeAction<CompileJobAction>(Input, types::TY_API_INFO);
return C.MakeAction<CompileJobAction>(Input, types::TY_LLVM_BC);
}
case phases::Backend: {
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index d31529748b62..403fac76f060 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -16,6 +16,7 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SpecialCaseList.h"
+#include "llvm/Support/AArch64TargetParser.h"
#include "llvm/Support/TargetParser.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Transforms/Instrumentation/AddressSanitizerOptions.h"
@@ -641,10 +642,14 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
Args.hasFlag(options::OPT_fsanitize_memory_use_after_dtor,
options::OPT_fno_sanitize_memory_use_after_dtor,
MsanUseAfterDtor);
+ MsanParamRetval = Args.hasFlag(
+ options::OPT_fsanitize_memory_param_retval,
+ options::OPT_fno_sanitize_memory_param_retval, MsanParamRetval);
NeedPIE |= !(TC.getTriple().isOSLinux() &&
TC.getTriple().getArch() == llvm::Triple::x86_64);
} else {
MsanUseAfterDtor = false;
+ MsanParamRetval = false;
}
if (AllAddedKinds & SanitizerKind::Thread) {
@@ -1096,6 +1101,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
if (MsanUseAfterDtor)
CmdArgs.push_back("-fsanitize-memory-use-after-dtor");
+ if (MsanParamRetval)
+ CmdArgs.push_back("-fsanitize-memory-param-retval");
+
// FIXME: Pass these parameters as function attributes, not as -llvm flags.
if (!TsanMemoryAccess) {
CmdArgs.push_back("-mllvm");
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 50c89aaadc18..5fef1fb2ee5a 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -75,17 +75,16 @@ ToolChain::ToolChain(const Driver &D, const llvm::Triple &T,
const ArgList &Args)
: D(D), Triple(T), Args(Args), CachedRTTIArg(GetRTTIArgument(Args)),
CachedRTTIMode(CalculateRTTIMode(Args, Triple, CachedRTTIArg)) {
- std::string RuntimePath = getRuntimePath();
- if (getVFS().exists(RuntimePath))
- getLibraryPaths().push_back(RuntimePath);
-
- std::string StdlibPath = getStdlibPath();
- if (getVFS().exists(StdlibPath))
- getFilePaths().push_back(StdlibPath);
+ auto addIfExists = [this](path_list &List, const std::string &Path) {
+ if (getVFS().exists(Path))
+ List.push_back(Path);
+ };
- std::string CandidateLibPath = getArchSpecificLibPath();
- if (getVFS().exists(CandidateLibPath))
- getFilePaths().push_back(CandidateLibPath);
+ for (const auto &Path : getRuntimePaths())
+ addIfExists(getLibraryPaths(), Path);
+ for (const auto &Path : getStdlibPaths())
+ addIfExists(getFilePaths(), Path);
+ addIfExists(getFilePaths(), getArchSpecificLibPath());
}
void ToolChain::setTripleEnvironment(llvm::Triple::EnvironmentType Env) {
@@ -110,6 +109,10 @@ bool ToolChain::useRelaxRelocations() const {
return ENABLE_X86_RELAX_RELOCATIONS;
}
+bool ToolChain::defaultToIEEELongDouble() const {
+ return PPC_LINUX_DEFAULT_IEEELONGDOUBLE && getTriple().isOSLinux();
+}
+
SanitizerArgs
ToolChain::getSanitizerArgs(const llvm::opt::ArgList &JobArgs) const {
SanitizerArgs SanArgs(*this, JobArgs, !SanitizerArgsChecked);
@@ -485,16 +488,35 @@ const char *ToolChain::getCompilerRTArgString(const llvm::opt::ArgList &Args,
return Args.MakeArgString(getCompilerRT(Args, Component, Type));
}
-std::string ToolChain::getRuntimePath() const {
- SmallString<128> P(D.ResourceDir);
- llvm::sys::path::append(P, "lib", getTripleString());
- return std::string(P.str());
+ToolChain::path_list ToolChain::getRuntimePaths() const {
+ path_list Paths;
+ auto addPathForTriple = [this, &Paths](const llvm::Triple &Triple) {
+ SmallString<128> P(D.ResourceDir);
+ llvm::sys::path::append(P, "lib", Triple.str());
+ Paths.push_back(std::string(P.str()));
+ };
+
+ addPathForTriple(getTriple());
+
+ // Android targets may include an API level at the end. We still want to fall
+ // back on a path without the API level.
+ if (getTriple().isAndroid() &&
+ getTriple().getEnvironmentName() != "android") {
+ llvm::Triple TripleWithoutLevel = getTriple();
+ TripleWithoutLevel.setEnvironmentName("android");
+ addPathForTriple(TripleWithoutLevel);
+ }
+
+ return Paths;
}
-std::string ToolChain::getStdlibPath() const {
+ToolChain::path_list ToolChain::getStdlibPaths() const {
+ path_list Paths;
SmallString<128> P(D.Dir);
llvm::sys::path::append(P, "..", "lib", getTripleString());
- return std::string(P.str());
+ Paths.push_back(std::string(P.str()));
+
+ return Paths;
}
std::string ToolChain::getArchSpecificLibPath() const {
diff --git a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp
index f282f04b7931..6899f9360da5 100644
--- a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp
+++ b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp
@@ -16,6 +16,7 @@
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/InputInfo.h"
#include "clang/Driver/Options.h"
+#include "clang/Driver/Tool.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormatAdapters.h"
@@ -95,9 +96,9 @@ const char *AMDGCN::OpenMPLinker::constructLLVMLinkCommand(
if (II.isFilename())
CmdArgs.push_back(II.getFilename());
+ bool HasLibm = false;
if (Args.hasArg(options::OPT_l)) {
auto Lm = Args.getAllArgValues(options::OPT_l);
- bool HasLibm = false;
for (auto &Lib : Lm) {
if (Lib == "m") {
HasLibm = true;
@@ -131,9 +132,8 @@ const char *AMDGCN::OpenMPLinker::constructLLVMLinkCommand(
}
AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, CmdArgs, "amdgcn",
- SubArchName,
- /* bitcode SDL?*/ true,
- /* PostClang Link? */ false);
+ SubArchName, /*isBitCodeSDL=*/true,
+ /*postClangLink=*/false);
// Add an intermediate output file.
CmdArgs.push_back("-o");
const char *OutputFileName =
@@ -144,6 +144,26 @@ const char *AMDGCN::OpenMPLinker::constructLLVMLinkCommand(
C.addCommand(std::make_unique<Command>(
JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs,
InputInfo(&JA, Args.MakeArgString(OutputFileName))));
+
+ // If we linked in libm definitions late we run another round of optimizations
+ // to inline the definitions and fold what is foldable.
+ if (HasLibm) {
+ ArgStringList OptCmdArgs;
+ const char *OptOutputFileName =
+ getOutputFileName(C, OutputFilePrefix, "-linked-opt", "bc");
+ addLLCOptArg(Args, OptCmdArgs);
+ OptCmdArgs.push_back(OutputFileName);
+ OptCmdArgs.push_back("-o");
+ OptCmdArgs.push_back(OptOutputFileName);
+ const char *OptExec =
+ Args.MakeArgString(getToolChain().GetProgramPath("opt"));
+ C.addCommand(std::make_unique<Command>(
+ JA, *this, ResponseFileSupport::AtFileCurCP(), OptExec, OptCmdArgs,
+ InputInfo(&JA, Args.MakeArgString(OutputFileName)),
+ InputInfo(&JA, Args.MakeArgString(OptOutputFileName))));
+ OutputFileName = OptOutputFileName;
+ }
+
return OutputFileName;
}
@@ -286,10 +306,22 @@ llvm::opt::DerivedArgList *AMDGPUOpenMPToolChain::TranslateArgs(
const OptTable &Opts = getDriver().getOpts();
- if (DeviceOffloadKind != Action::OFK_OpenMP) {
- for (Arg *A : Args) {
- DAL->append(A);
+ if (DeviceOffloadKind == Action::OFK_OpenMP) {
+ for (Arg *A : Args)
+ if (!llvm::is_contained(*DAL, A))
+ DAL->append(A);
+
+ std::string Arch = DAL->getLastArgValue(options::OPT_march_EQ).str();
+ if (Arch.empty()) {
+ checkSystemForAMDGPU(Args, *this, Arch);
+ DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), Arch);
}
+
+ return DAL;
+ }
+
+ for (Arg *A : Args) {
+ DAL->append(A);
}
if (!BoundArch.empty()) {
diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
index be13d6d583ce..ca0ca4bf4eea 100644
--- a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
@@ -11,6 +11,7 @@
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "llvm/Option/ArgList.h"
+#include "llvm/Support/AArch64TargetParser.h"
#include "llvm/Support/TargetParser.h"
#include "llvm/Support/Host.h"
@@ -98,12 +99,14 @@ static bool DecodeAArch64Features(const Driver &D, StringRef text,
Features.push_back("-sve2-sm4");
}
- // +sve implies +f32mm if the base architecture is v8.6A, v8.7A, v9.1A or
- // v9.2A. It isn't the case in general that sve implies both f64mm and f32mm
+ // +sve implies +f32mm if the base architecture is >= v8.6A (except v9A)
+ // It isn't the case in general that sve implies both f64mm and f32mm
if ((ArchKind == llvm::AArch64::ArchKind::ARMV8_6A ||
ArchKind == llvm::AArch64::ArchKind::ARMV8_7A ||
+ ArchKind == llvm::AArch64::ArchKind::ARMV8_8A ||
ArchKind == llvm::AArch64::ArchKind::ARMV9_1A ||
- ArchKind == llvm::AArch64::ArchKind::ARMV9_2A) &&
+ ArchKind == llvm::AArch64::ArchKind::ARMV9_2A ||
+ ArchKind == llvm::AArch64::ArchKind::ARMV9_3A) &&
Feature == "sve")
Features.push_back("+f32mm");
}
@@ -219,6 +222,7 @@ getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu,
void aarch64::getAArch64TargetFeatures(const Driver &D,
const llvm::Triple &Triple,
const ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs,
std::vector<StringRef> &Features,
bool ForAS) {
Arg *A;
@@ -390,9 +394,11 @@ fp16_fml_fallthrough:
}
if (std::find(ItBegin, ItEnd, "+v8.4a") != ItEnd ||
+ std::find(ItBegin, ItEnd, "+v8.8a") != ItEnd ||
std::find(ItBegin, ItEnd, "+v9a") != ItEnd ||
std::find(ItBegin, ItEnd, "+v9.1a") != ItEnd ||
- std::find(ItBegin, ItEnd, "+v9.2a") != ItEnd) {
+ std::find(ItBegin, ItEnd, "+v9.2a") != ItEnd ||
+ std::find(ItBegin, ItEnd, "+v9.3a") != ItEnd) {
if (HasCrypto && !NoCrypto) {
// Check if we have NOT disabled an algorithm with something like:
// +crypto, -algorithm
@@ -451,7 +457,8 @@ fp16_fml_fallthrough:
}
}
- const char *Archs[] = {"+v8.6a", "+v8.7a", "+v9.1a", "+v9.2a"};
+ const char *Archs[] = {"+v8.6a", "+v8.7a", "+v8.8a",
+ "+v9.1a", "+v9.2a", "+v9.3a"};
auto Pos = std::find_first_of(Features.begin(), Features.end(),
std::begin(Archs), std::end(Archs));
if (Pos != std::end(Features))
@@ -459,10 +466,16 @@ fp16_fml_fallthrough:
if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
options::OPT_munaligned_access)) {
- if (A->getOption().matches(options::OPT_mno_unaligned_access))
+ if (A->getOption().matches(options::OPT_mno_unaligned_access)) {
Features.push_back("+strict-align");
- } else if (Triple.isOSOpenBSD())
+ if (!ForAS)
+ CmdArgs.push_back("-Wunaligned-access");
+ }
+ } else if (Triple.isOSOpenBSD()) {
Features.push_back("+strict-align");
+ if (!ForAS)
+ CmdArgs.push_back("-Wunaligned-access");
+ }
if (Args.hasArg(options::OPT_ffixed_x1))
Features.push_back("+reserve-x1");
diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.h b/clang/lib/Driver/ToolChains/Arch/AArch64.h
index d47c402d4a42..0cdc2ec725e0 100644
--- a/clang/lib/Driver/ToolChains/Arch/AArch64.h
+++ b/clang/lib/Driver/ToolChains/Arch/AArch64.h
@@ -22,6 +22,7 @@ namespace aarch64 {
void getAArch64TargetFeatures(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs,
std::vector<llvm::StringRef> &Features,
bool ForAS);
diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/clang/lib/Driver/ToolChains/Arch/ARM.cpp
index 4013cf230026..16af9f6d7129 100644
--- a/clang/lib/Driver/ToolChains/Arch/ARM.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/ARM.cpp
@@ -12,6 +12,7 @@
#include "clang/Driver/Options.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/ArgList.h"
+#include "llvm/Support/ARMTargetParser.h"
#include "llvm/Support/TargetParser.h"
#include "llvm/Support/Host.h"
@@ -769,10 +770,12 @@ fp16_fml_fallthrough:
}
// Kernel code has more strict alignment requirements.
- if (KernelOrKext)
+ if (KernelOrKext) {
Features.push_back("+strict-align");
- else if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
- options::OPT_munaligned_access)) {
+ if (!ForAS)
+ CmdArgs.push_back("-Wunaligned-access");
+ } else if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
+ options::OPT_munaligned_access)) {
if (A->getOption().matches(options::OPT_munaligned_access)) {
// No v6M core supports unaligned memory access (v6M ARM ARM A3.2).
if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m)
@@ -781,8 +784,11 @@ fp16_fml_fallthrough:
// access either.
else if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v8m_baseline)
D.Diag(diag::err_target_unsupported_unaligned) << "v8m.base";
- } else
+ } else {
Features.push_back("+strict-align");
+ if (!ForAS)
+ CmdArgs.push_back("-Wunaligned-access");
+ }
} else {
// Assume pre-ARMv6 doesn't support unaligned accesses.
//
@@ -801,14 +807,23 @@ fp16_fml_fallthrough:
int VersionNum = getARMSubArchVersionNumber(Triple);
if (Triple.isOSDarwin() || Triple.isOSNetBSD()) {
if (VersionNum < 6 ||
- Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m)
+ Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m) {
Features.push_back("+strict-align");
+ if (!ForAS)
+ CmdArgs.push_back("-Wunaligned-access");
+ }
} else if (Triple.isOSLinux() || Triple.isOSNaCl() ||
Triple.isOSWindows()) {
- if (VersionNum < 7)
+ if (VersionNum < 7) {
Features.push_back("+strict-align");
- } else
+ if (!ForAS)
+ CmdArgs.push_back("-Wunaligned-access");
+ }
+ } else {
Features.push_back("+strict-align");
+ if (!ForAS)
+ CmdArgs.push_back("-Wunaligned-access");
+ }
}
// llvm does not support reserving registers in general. There is support
diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.h b/clang/lib/Driver/ToolChains/Arch/ARM.h
index 881b63bd36b9..862a2f2796be 100644
--- a/clang/lib/Driver/ToolChains/Arch/ARM.h
+++ b/clang/lib/Driver/ToolChains/Arch/ARM.h
@@ -13,6 +13,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Option/Option.h"
+#include "llvm/Support/ARMTargetParser.h"
#include "llvm/Support/TargetParser.h"
#include <string>
#include <vector>
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 65347a38490e..4386e395bc6c 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -33,6 +33,7 @@
#include "clang/Driver/InputInfo.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/SanitizerArgs.h"
+#include "clang/Driver/Types.h"
#include "clang/Driver/XRayArgs.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Config/llvm-config.h"
@@ -346,7 +347,8 @@ static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple,
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_32:
case llvm::Triple::aarch64_be:
- aarch64::getAArch64TargetFeatures(D, Triple, Args, Features, ForAS);
+ aarch64::getAArch64TargetFeatures(D, Triple, Args, CmdArgs, Features,
+ ForAS);
break;
case llvm::Triple::x86:
case llvm::Triple::x86_64:
@@ -1115,7 +1117,7 @@ static void RenderDebugInfoCompressionArgs(const ArgList &Args,
StringRef Value = A->getValue();
if (Value == "none") {
CmdArgs.push_back("--compress-debug-sections=none");
- } else if (Value == "zlib" || Value == "zlib-gnu") {
+ } else if (Value == "zlib") {
if (llvm::zlib::isAvailable()) {
CmdArgs.push_back(
Args.MakeArgString("--compress-debug-sections=" + Twine(Value)));
@@ -1929,6 +1931,11 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
}
}
+ if (Args.getLastArg(options::OPT_mfix4300)) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-mfix4300");
+ }
+
if (Arg *A = Args.getLastArg(options::OPT_G)) {
StringRef v = A->getValue();
CmdArgs.push_back("-mllvm");
@@ -2055,7 +2062,7 @@ void Clang::AddPPCTargetArgs(const ArgList &Args,
}
}
- bool IEEELongDouble = false;
+ bool IEEELongDouble = getToolChain().defaultToIEEELongDouble();
for (const Arg *A : Args.filtered(options::OPT_mabi_EQ)) {
StringRef V = A->getValue();
if (V == "ieeelongdouble")
@@ -2897,6 +2904,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
AssociativeMath = true;
ReciprocalMath = true;
SignedZeros = false;
+ ApproxFunc = true;
TrappingMath = false;
FPExceptionBehavior = "";
break;
@@ -2904,6 +2912,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
AssociativeMath = false;
ReciprocalMath = false;
SignedZeros = true;
+ ApproxFunc = false;
TrappingMath = true;
FPExceptionBehavior = "strict";
@@ -2923,6 +2932,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
MathErrno = false;
AssociativeMath = true;
ReciprocalMath = true;
+ ApproxFunc = true;
SignedZeros = false;
TrappingMath = false;
RoundingFPMath = false;
@@ -2938,6 +2948,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
MathErrno = TC.IsMathErrnoDefault();
AssociativeMath = false;
ReciprocalMath = false;
+ ApproxFunc = false;
SignedZeros = true;
// -fno_fast_math restores default denormal and fpcontract handling
DenormalFPMath = DefaultDenormalFPMath;
@@ -2956,7 +2967,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
// 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 &&
+ SignedZeros && TrappingMath && RoundingFPMath && !ApproxFunc &&
DenormalFPMath == llvm::DenormalMode::getIEEE() &&
DenormalFP32Math == llvm::DenormalMode::getIEEE() &&
FPContract.equals("off"))
@@ -2989,7 +3000,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
CmdArgs.push_back("-fmath-errno");
if (!MathErrno && AssociativeMath && ReciprocalMath && !SignedZeros &&
- !TrappingMath)
+ ApproxFunc && !TrappingMath)
CmdArgs.push_back("-menable-unsafe-fp-math");
if (!SignedZeros)
@@ -3040,7 +3051,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
// -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 &&
+ if (!HonorINFs && !HonorNaNs && !MathErrno && AssociativeMath && ApproxFunc &&
ReciprocalMath && !SignedZeros && !TrappingMath && !RoundingFPMath) {
CmdArgs.push_back("-ffast-math");
if (FPModel.equals("fast")) {
@@ -3217,9 +3228,7 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
return;
}
// Check whether the target subarch supports the hardware TLS register
- if (arm::getARMSubArchVersionNumber(EffectiveTriple) < 7 &&
- llvm::ARM::parseArch(EffectiveTriple.getArchName()) !=
- llvm::ARM::ArchKind::ARMV6T2) {
+ if (!arm::isHardTPSupported(EffectiveTriple)) {
D.Diag(diag::err_target_unsupported_tp_hard)
<< EffectiveTriple.getArchName();
return;
@@ -4589,6 +4598,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
} else if (JA.getType() == types::TY_RewrittenLegacyObjC) {
CmdArgs.push_back("-rewrite-objc");
rewriteKind = RK_Fragile;
+ } else if (JA.getType() == types::TY_API_INFO) {
+ CmdArgs.push_back("-extract-api");
} else {
assert(JA.getType() == types::TY_PP_Asm && "Unexpected output type!");
}
@@ -5310,7 +5321,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// as errors, but until then, we can live with a warning being emitted by the
// compiler. This way, Clang can be used to compile code with scalable vectors
// and identify possible issues.
- if (isa<BackendJobAction>(JA)) {
+ if (isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA) ||
+ isa<BackendJobAction>(JA)) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-treat-scalable-fixed-error-as-warning");
}
@@ -5813,6 +5825,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-ftype-visibility");
CmdArgs.push_back("default");
}
+ } else if (IsOpenMPDevice) {
+ // When compiling for the OpenMP device we want protected visibility by
+ // default. This prevents the device from accidenally preempting code on the
+ // host, makes the system more robust, and improves performance.
+ CmdArgs.push_back("-fvisibility");
+ CmdArgs.push_back("protected");
}
if (!RawTriple.isPS4())
@@ -5992,6 +6010,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
+ Args.AddLastArg(CmdArgs, options::OPT_fms_hotpatch);
+
if (TC.SupportsProfiling()) {
Args.AddLastArg(CmdArgs, options::OPT_pg);
@@ -6149,6 +6169,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.MakeArgString(Twine("-fcf-protection=") + A->getValue()));
}
+ if (IsUsingLTO)
+ Args.AddLastArg(CmdArgs, options::OPT_mibt_seal);
+
// Forward -f options with positive and negative forms; we translate these by
// hand. Do not propagate PGO options to the GPU-side compilations as the
// profile info is for the host-side compilation only.
@@ -6663,6 +6686,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_dM);
Args.AddLastArg(CmdArgs, options::OPT_dD);
+ Args.AddLastArg(CmdArgs, options::OPT_dI);
Args.AddLastArg(CmdArgs, options::OPT_fmax_tokens_EQ);
diff --git a/clang/lib/Driver/ToolChains/Clang.h b/clang/lib/Driver/ToolChains/Clang.h
index 00e0490e069b..013cd2341e17 100644
--- a/clang/lib/Driver/ToolChains/Clang.h
+++ b/clang/lib/Driver/ToolChains/Clang.h
@@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_Clang_H
-#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_Clang_H
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLANG_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLANG_H
#include "MSVC.h"
#include "clang/Basic/DebugInfoOptions.h"
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 407f81a2ae09..1d30090ca21c 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -286,13 +286,13 @@ void tools::addLinkerCompressDebugSectionsOption(
const ToolChain &TC, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) {
// GNU ld supports --compress-debug-sections=none|zlib|zlib-gnu|zlib-gabi
- // whereas zlib is an alias to zlib-gabi. Therefore -gz=none|zlib|zlib-gnu
- // are translated to --compress-debug-sections=none|zlib|zlib-gnu.
- // -gz is not translated since ld --compress-debug-sections option requires an
+ // whereas zlib is an alias to zlib-gabi and zlib-gnu is obsoleted. Therefore
+ // -gz=none|zlib are translated to --compress-debug-sections=none|zlib. -gz
+ // is not translated since ld --compress-debug-sections option requires an
// argument.
if (const Arg *A = Args.getLastArg(options::OPT_gz_EQ)) {
StringRef V = A->getValue();
- if (V == "none" || V == "zlib" || V == "zlib-gnu")
+ if (V == "none" || V == "zlib")
CmdArgs.push_back(Args.MakeArgString("--compress-debug-sections=" + V));
else
TC.getDriver().Diag(diag::err_drv_unsupported_option_argument)
@@ -832,6 +832,10 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
return;
}
+ // Always link the static runtime for executable.
+ if (SanArgs.needsAsanRt())
+ HelperStaticRuntimes.push_back("asan_static");
+
// Each static runtime that has a DSO counterpart above is excluded below,
// but runtimes that exist only as static are not affected by needsSharedRt.
@@ -1186,10 +1190,9 @@ tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) {
options::OPT_fpic, options::OPT_fno_pic,
options::OPT_fPIE, options::OPT_fno_PIE,
options::OPT_fpie, options::OPT_fno_pie);
- if (Triple.isOSWindows() && LastPICArg &&
- LastPICArg ==
- Args.getLastArg(options::OPT_fPIC, options::OPT_fpic,
- options::OPT_fPIE, options::OPT_fpie)) {
+ if (Triple.isOSWindows() && !Triple.isOSCygMing() && LastPICArg &&
+ LastPICArg == Args.getLastArg(options::OPT_fPIC, options::OPT_fpic,
+ options::OPT_fPIE, options::OPT_fpie)) {
ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target)
<< LastPICArg->getSpelling() << Triple.str();
if (Triple.getArch() == llvm::Triple::x86_64)
@@ -1724,7 +1727,7 @@ bool tools::GetSDLFromOffloadArchive(
std::string OutputLib = D.GetTemporaryPath(
Twine(Prefix + Lib + "-" + Arch + "-" + Target).str(), "a");
- C.addTempFile(C.getArgs().MakeArgString(OutputLib.c_str()));
+ C.addTempFile(C.getArgs().MakeArgString(OutputLib));
ArgStringList CmdArgs;
SmallString<128> DeviceTriple;
@@ -1747,20 +1750,20 @@ bool tools::GetSDLFromOffloadArchive(
T.getToolChain().GetProgramPath("clang-offload-bundler"));
ArgStringList UBArgs;
- UBArgs.push_back(C.getArgs().MakeArgString(UnbundleArg.c_str()));
- UBArgs.push_back(C.getArgs().MakeArgString(TypeArg.c_str()));
- UBArgs.push_back(C.getArgs().MakeArgString(InputArg.c_str()));
- UBArgs.push_back(C.getArgs().MakeArgString(OffloadArg.c_str()));
- UBArgs.push_back(C.getArgs().MakeArgString(OutputArg.c_str()));
+ UBArgs.push_back(C.getArgs().MakeArgString(UnbundleArg));
+ UBArgs.push_back(C.getArgs().MakeArgString(TypeArg));
+ UBArgs.push_back(C.getArgs().MakeArgString(InputArg));
+ UBArgs.push_back(C.getArgs().MakeArgString(OffloadArg));
+ UBArgs.push_back(C.getArgs().MakeArgString(OutputArg));
// Add this flag to not exit from clang-offload-bundler if no compatible
// code object is found in heterogenous archive library.
std::string AdditionalArgs("-allow-missing-bundles");
- UBArgs.push_back(C.getArgs().MakeArgString(AdditionalArgs.c_str()));
+ UBArgs.push_back(C.getArgs().MakeArgString(AdditionalArgs));
C.addCommand(std::make_unique<Command>(
JA, T, ResponseFileSupport::AtFileCurCP(), UBProgram, UBArgs, Inputs,
- InputInfo(&JA, C.getArgs().MakeArgString(OutputLib.c_str()))));
+ InputInfo(&JA, C.getArgs().MakeArgString(OutputLib))));
if (postClangLink)
CC1Args.push_back("-mlink-builtin-bitcode");
diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp
index ee573b89bed1..7324339efaa6 100644
--- a/clang/lib/Driver/ToolChains/Cuda.cpp
+++ b/clang/lib/Driver/ToolChains/Cuda.cpp
@@ -612,8 +612,9 @@ void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(CubinF);
}
- AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, CmdArgs, "nvptx", GPUArch,
- false, false);
+ AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, CmdArgs, "nvptx",
+ GPUArch, /*isBitCodeSDL=*/false,
+ /*postClangLink=*/false);
// Find nvlink and pass it as "--nvlink-path=" argument of
// clang-nvlink-wrapper.
@@ -752,8 +753,9 @@ void CudaToolChain::addClangTargetOptions(
addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, BitcodeSuffix,
getTriple());
- AddStaticDeviceLibsPostLinking(getDriver(), DriverArgs, CC1Args, "nvptx", GpuArch,
- /* bitcode SDL?*/ true, /* PostClang Link? */ true);
+ AddStaticDeviceLibsPostLinking(getDriver(), DriverArgs, CC1Args, "nvptx",
+ GpuArch, /*isBitCodeSDL=*/true,
+ /*postClangLink=*/true);
}
}
diff --git a/clang/lib/Driver/ToolChains/FreeBSD.cpp b/clang/lib/Driver/ToolChains/FreeBSD.cpp
index de635f5816cf..05c58a8f43a8 100644
--- a/clang/lib/Driver/ToolChains/FreeBSD.cpp
+++ b/clang/lib/Driver/ToolChains/FreeBSD.cpp
@@ -247,7 +247,8 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
assert(Output.isNothing() && "Invalid output.");
}
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
+ options::OPT_r)) {
const char *crt1 = nullptr;
if (!Args.hasArg(options::OPT_shared)) {
if (Args.hasArg(options::OPT_pg))
@@ -295,7 +296,8 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
unsigned Major = ToolChain.getTriple().getOSMajorVersion();
bool Profiling = Args.hasArg(options::OPT_pg) && Major != 0 && Major < 14;
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,
+ options::OPT_r)) {
// Use the static OpenMP runtime with -static-openmp
bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) &&
!Args.hasArg(options::OPT_static);
@@ -358,7 +360,8 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
+ options::OPT_r)) {
if (Args.hasArg(options::OPT_shared) || IsPIE)
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o")));
else
diff --git a/clang/lib/Driver/ToolChains/Fuchsia.cpp b/clang/lib/Driver/ToolChains/Fuchsia.cpp
index a7afec6963a1..bd1600d060c8 100644
--- a/clang/lib/Driver/ToolChains/Fuchsia.cpp
+++ b/clang/lib/Driver/ToolChains/Fuchsia.cpp
@@ -109,7 +109,8 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
+ options::OPT_r)) {
if (!Args.hasArg(options::OPT_shared)) {
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("Scrt1.o")));
}
@@ -131,7 +132,8 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
ToolChain.addProfileRTLibs(Args, CmdArgs);
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,
+ options::OPT_r)) {
if (Args.hasArg(options::OPT_static))
CmdArgs.push_back("-Bdynamic");
@@ -191,9 +193,11 @@ Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple,
auto FilePaths = [&](const Multilib &M) -> std::vector<std::string> {
std::vector<std::string> FP;
- SmallString<128> P(getStdlibPath());
- llvm::sys::path::append(P, M.gccSuffix());
- FP.push_back(std::string(P.str()));
+ for (const std::string &Path : getStdlibPaths()) {
+ SmallString<128> P(Path);
+ llvm::sys::path::append(P, M.gccSuffix());
+ FP.push_back(std::string(P.str()));
+ }
return FP;
};
diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp
index 7aeadd84dfee..7a9570a686f4 100644
--- a/clang/lib/Driver/ToolChains/Gnu.cpp
+++ b/clang/lib/Driver/ToolChains/Gnu.cpp
@@ -487,7 +487,8 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
+ options::OPT_r)) {
if (!isAndroid && !IsIAMCU) {
const char *crt1 = nullptr;
if (!Args.hasArg(options::OPT_shared)) {
@@ -563,7 +564,8 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
getToolChain().addProfileRTLibs(Args, CmdArgs);
if (D.CCCIsCXX() &&
- !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,
+ options::OPT_r)) {
if (ToolChain.ShouldLinkCXXStdlib(Args)) {
bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
!Args.hasArg(options::OPT_static);
@@ -578,7 +580,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// Silence warnings when linking C code with a C++ '-stdlib' argument.
Args.ClaimAllArgs(options::OPT_stdlib_EQ);
- if (!Args.hasArg(options::OPT_nostdlib)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_r)) {
if (!Args.hasArg(options::OPT_nodefaultlibs)) {
if (IsStatic || IsStaticPIE)
CmdArgs.push_back("--start-group");
@@ -692,7 +694,7 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C,
CmdArgs.push_back("--compress-debug-sections");
} else {
StringRef Value = A->getValue();
- if (Value == "none" || Value == "zlib" || Value == "zlib-gnu") {
+ if (Value == "none" || Value == "zlib") {
CmdArgs.push_back(
Args.MakeArgString("--compress-debug-sections=" + Twine(Value)));
} else {
diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp
index e413640abad3..af74b108e04e 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -324,6 +324,12 @@ ToolChain::RuntimeLibType Linux::GetDefaultRuntimeLibType() const {
return Generic_ELF::GetDefaultRuntimeLibType();
}
+unsigned Linux::GetDefaultDwarfVersion() const {
+ if (getTriple().isAndroid())
+ return 4;
+ return ToolChain::GetDefaultDwarfVersion();
+}
+
ToolChain::CXXStdlibType Linux::GetDefaultCXXStdlibType() const {
if (getTriple().isAndroid())
return ToolChain::CST_Libcxx;
diff --git a/clang/lib/Driver/ToolChains/Linux.h b/clang/lib/Driver/ToolChains/Linux.h
index a5ec33bd44f1..a5648d79d655 100644
--- a/clang/lib/Driver/ToolChains/Linux.h
+++ b/clang/lib/Driver/ToolChains/Linux.h
@@ -40,6 +40,7 @@ public:
void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
RuntimeLibType GetDefaultRuntimeLibType() const override;
+ unsigned GetDefaultDwarfVersion() const override;
CXXStdlibType GetDefaultCXXStdlibType() const override;
bool
IsAArch64OutlineAtomicsDefault(const llvm::opt::ArgList &Args) const override;
diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp
index 66e9d8ab525a..18cef288f018 100644
--- a/clang/lib/Driver/ToolChains/MSVC.cpp
+++ b/clang/lib/Driver/ToolChains/MSVC.cpp
@@ -47,7 +47,14 @@
// Make sure this comes before MSVCSetupApi.h
#include <comdef.h>
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
+#endif
#include "MSVCSetupApi.h"
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
#include "llvm/Support/COM.h"
_COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration));
_COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2));
@@ -511,6 +518,11 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7))
CmdArgs.push_back("-debug");
+ // If we specify /hotpatch, let the linker add padding in front of each
+ // function, like MSVC does.
+ if (Args.hasArg(options::OPT_fms_hotpatch, options::OPT__SLASH_hotpatch))
+ CmdArgs.push_back("-functionpadmin");
+
// Pass on /Brepro if it was passed to the compiler.
// Note that /Brepro maps to -mno-incremental-linker-compatible.
bool DefaultIncrementalLinkerCompatible =
@@ -1333,6 +1345,15 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
"Include", windowsSDKIncludeVersion,
"winrt");
+ if (major >= 10) {
+ llvm::VersionTuple Tuple;
+ if (!Tuple.tryParse(windowsSDKIncludeVersion) &&
+ Tuple.getSubminor().getValueOr(0) >= 17134) {
+ AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
+ "Include", windowsSDKIncludeVersion,
+ "cppwinrt");
+ }
+ }
} else {
AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
"Include");
diff --git a/clang/lib/Driver/ToolChains/MSVC.h b/clang/lib/Driver/ToolChains/MSVC.h
index 8f033de09bf6..c842773996ed 100644
--- a/clang/lib/Driver/ToolChains/MSVC.h
+++ b/clang/lib/Driver/ToolChains/MSVC.h
@@ -69,6 +69,10 @@ public:
return llvm::DebuggerKind::Default;
}
+ unsigned GetDefaultDwarfVersion() const override {
+ return 4;
+ }
+
enum class SubDirectoryType {
Bin,
Include,
diff --git a/clang/lib/Driver/ToolChains/MSVCSetupApi.h b/clang/lib/Driver/ToolChains/MSVCSetupApi.h
index a890b85fd5e9..28e6e3e08e37 100644
--- a/clang/lib/Driver/ToolChains/MSVCSetupApi.h
+++ b/clang/lib/Driver/ToolChains/MSVCSetupApi.h
@@ -28,6 +28,11 @@
#pragma once
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
+#endif
+
// Constants
//
#ifndef E_NOTFOUND
@@ -512,3 +517,7 @@ STDMETHODIMP GetSetupConfiguration(_Out_ ISetupConfiguration **ppConfiguration,
#ifdef __cplusplus
}
#endif
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp
index ecce2f062bd7..0501f9737404 100644
--- a/clang/lib/Driver/ToolChains/MinGW.cpp
+++ b/clang/lib/Driver/ToolChains/MinGW.cpp
@@ -164,6 +164,9 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("--enable-auto-image-base");
}
+ if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
+ CmdArgs.push_back("--no-demangle");
+
CmdArgs.push_back("-o");
const char *OutputFile = Output.getFilename();
// GCC implicitly adds an .exe extension if it is given an output file name
@@ -486,10 +489,7 @@ bool toolchains::MinGW::isPIEDefault(const llvm::opt::ArgList &Args) const {
return false;
}
-bool toolchains::MinGW::isPICDefaultForced() const {
- return getArch() == llvm::Triple::x86_64 ||
- getArch() == llvm::Triple::aarch64;
-}
+bool toolchains::MinGW::isPICDefaultForced() const { return true; }
llvm::ExceptionHandling
toolchains::MinGW::GetExceptionModel(const ArgList &Args) const {
diff --git a/clang/lib/Driver/ToolChains/PPCLinux.cpp b/clang/lib/Driver/ToolChains/PPCLinux.cpp
index af2e3a21a0af..e480d8bd8703 100644
--- a/clang/lib/Driver/ToolChains/PPCLinux.cpp
+++ b/clang/lib/Driver/ToolChains/PPCLinux.cpp
@@ -8,11 +8,51 @@
#include "PPCLinux.h"
#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
+using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace llvm::opt;
+using namespace llvm::sys;
+
+// Glibc older than 2.32 doesn't fully support IEEE float128. Here we check
+// glibc version by looking at dynamic linker name.
+static bool GlibcSupportsFloat128(const std::string &Linker) {
+ llvm::SmallVector<char, 16> Path;
+
+ // Resolve potential symlinks to linker.
+ if (fs::real_path(Linker, Path))
+ return false;
+ llvm::StringRef LinkerName =
+ path::filename(llvm::StringRef(Path.data(), Path.size()));
+
+ // Since glibc 2.34, the installed .so file is not symlink anymore. But we can
+ // still safely assume it's newer than 2.32.
+ if (LinkerName.startswith("ld64.so"))
+ return true;
+
+ if (!LinkerName.startswith("ld-2."))
+ return false;
+ unsigned Minor = (LinkerName[5] - '0') * 10 + (LinkerName[6] - '0');
+ if (Minor < 32)
+ return false;
+
+ return true;
+}
+
+PPCLinuxToolChain::PPCLinuxToolChain(const Driver &D,
+ const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args)
+ : Linux(D, Triple, Args) {
+ if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
+ StringRef ABIName = A->getValue();
+ if (ABIName == "ieeelongdouble" && !SupportIEEEFloat128(D, Triple, Args))
+ D.Diag(diag::warn_drv_unsupported_float_abi_by_lib) << ABIName;
+ }
+}
void PPCLinuxToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
@@ -26,3 +66,20 @@ void PPCLinuxToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
Linux::AddClangSystemIncludeArgs(DriverArgs, CC1Args);
}
+
+bool PPCLinuxToolChain::SupportIEEEFloat128(
+ const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args) const {
+ if (!Triple.isLittleEndian() || !Triple.isPPC64())
+ return false;
+
+ if (Args.hasArg(options::OPT_nostdlib, options::OPT_nostdlibxx))
+ return true;
+
+ bool HasUnsupportedCXXLib =
+ ToolChain::GetCXXStdlibType(Args) == CST_Libcxx &&
+ GCCInstallation.getVersion().isOlderThan(12, 1, 0);
+
+ return GlibcSupportsFloat128(Linux::getDynamicLinker(Args)) &&
+ !(D.CCCIsCXX() && HasUnsupportedCXXLib);
+}
diff --git a/clang/lib/Driver/ToolChains/PPCLinux.h b/clang/lib/Driver/ToolChains/PPCLinux.h
index b3ef7b61dc3a..e0318ae8a3a2 100644
--- a/clang/lib/Driver/ToolChains/PPCLinux.h
+++ b/clang/lib/Driver/ToolChains/PPCLinux.h
@@ -18,12 +18,15 @@ namespace toolchains {
class LLVM_LIBRARY_VISIBILITY PPCLinuxToolChain : public Linux {
public:
PPCLinuxToolChain(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args)
- : Linux(D, Triple, Args) {}
+ const llvm::opt::ArgList &Args);
void
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
+
+private:
+ bool SupportIEEEFloat128(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args) const;
};
} // end namespace toolchains
diff --git a/clang/lib/Driver/ToolChains/PS4CPU.cpp b/clang/lib/Driver/ToolChains/PS4CPU.cpp
index 5783a733983a..bcf9147833dd 100644
--- a/clang/lib/Driver/ToolChains/PS4CPU.cpp
+++ b/clang/lib/Driver/ToolChains/PS4CPU.cpp
@@ -23,8 +23,6 @@ using namespace clang::driver;
using namespace clang;
using namespace llvm::opt;
-using clang::driver::tools::AddLinkerInputs;
-
void tools::PS4cpu::addProfileRTArgs(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
if ((Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
diff --git a/clang/lib/Driver/ToolChains/SPIRV.cpp b/clang/lib/Driver/ToolChains/SPIRV.cpp
index 50d03e79bbb0..27de69550853 100644
--- a/clang/lib/Driver/ToolChains/SPIRV.cpp
+++ b/clang/lib/Driver/ToolChains/SPIRV.cpp
@@ -70,3 +70,24 @@ clang::driver::Tool *SPIRVToolChain::getTool(Action::ActionClass AC) const {
}
return ToolChain::getTool(AC);
}
+clang::driver::Tool *SPIRVToolChain::buildLinker() const {
+ return new tools::SPIRV::Linker(*this);
+}
+
+void SPIRV::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const ToolChain &ToolChain = getToolChain();
+ std::string Linker = ToolChain.GetProgramPath(getShortName());
+ ArgStringList CmdArgs;
+ AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
+ Args.MakeArgString(Linker), CmdArgs,
+ Inputs, Output));
+}
diff --git a/clang/lib/Driver/ToolChains/SPIRV.h b/clang/lib/Driver/ToolChains/SPIRV.h
index 229f7018e3b5..a16ae3ca51fa 100644
--- a/clang/lib/Driver/ToolChains/SPIRV.h
+++ b/clang/lib/Driver/ToolChains/SPIRV.h
@@ -39,6 +39,17 @@ public:
const char *LinkingOutput) const override;
};
+class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+public:
+ Linker(const ToolChain &TC) : Tool("SPIRV::Linker", "spirv-link", 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;
+};
+
} // namespace SPIRV
} // namespace tools
@@ -68,6 +79,7 @@ public:
protected:
clang::driver::Tool *getTool(Action::ActionClass AC) const override;
+ Tool *buildLinker() const override;
private:
clang::driver::Tool *getTranslator() const;
diff --git a/clang/lib/Driver/ToolChains/VEToolchain.cpp b/clang/lib/Driver/ToolChains/VEToolchain.cpp
index 4cdeec7f9d8a..1e43796be1ff 100644
--- a/clang/lib/Driver/ToolChains/VEToolchain.cpp
+++ b/clang/lib/Driver/ToolChains/VEToolchain.cpp
@@ -48,7 +48,8 @@ VEToolChain::VEToolChain(const Driver &D, const llvm::Triple &Triple,
// ${BINPATH}/../lib/ve-unknown-linux-gnu, (== getStdlibPath)
// ${RESOURCEDIR}/lib/linux/ve, (== getArchSpecificLibPath)
// ${SYSROOT}/opt/nec/ve/lib,
- getFilePaths().push_back(getStdlibPath());
+ for (auto &Path : getStdlibPaths())
+ getFilePaths().push_back(std::move(Path));
getFilePaths().push_back(getArchSpecificLibPath());
getFilePaths().push_back(computeSysRoot() + "/opt/nec/ve/lib");
}
diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp
index a7298a9a71bf..3614272a5f74 100644
--- a/clang/lib/Driver/ToolChains/WebAssembly.cpp
+++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp
@@ -76,7 +76,7 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
ToolChain.AddFilePathLibArgs(Args, CmdArgs);
const char *Crt1 = "crt1.o";
- const char *Entry = NULL;
+ const char *Entry = nullptr;
// If crt1-command.o exists, it supports new-style commands, so use it.
// Otherwise, use the old crt1.o. This is a temporary transition measure.
diff --git a/clang/lib/Driver/ToolChains/WebAssembly.h b/clang/lib/Driver/ToolChains/WebAssembly.h
index c84e59675946..b4c3082a089a 100644
--- a/clang/lib/Driver/ToolChains/WebAssembly.h
+++ b/clang/lib/Driver/ToolChains/WebAssembly.h
@@ -51,6 +51,7 @@ private:
bool hasBlocksRuntime() const override;
bool SupportsProfiling() const override;
bool HasNativeLLVMSupport() const override;
+ unsigned GetDefaultDwarfVersion() const override { return 4; }
void
addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
diff --git a/clang/lib/Driver/Types.cpp b/clang/lib/Driver/Types.cpp
index 1bd187ad2fc0..8f6adc6c2ad1 100644
--- a/clang/lib/Driver/Types.cpp
+++ b/clang/lib/Driver/Types.cpp
@@ -143,6 +143,7 @@ bool types::isAcceptedByClang(ID Id) {
case TY_CXXModule: case TY_PP_CXXModule:
case TY_AST: case TY_ModuleFile: case TY_PCH:
case TY_LLVM_IR: case TY_LLVM_BC:
+ case TY_API_INFO:
return true;
}
}
diff --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
index a3d388a5ae44..589bf8d216ed 100644
--- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -704,7 +704,7 @@ static bool getLiteralInfo(SourceRange literalRange,
}
};
- while (1) {
+ while (true) {
if (Suff::has("u", text)) {
UpperU = false;
} else if (Suff::has("U", text)) {
diff --git a/clang/lib/Format/AffectedRangeManager.cpp b/clang/lib/Format/AffectedRangeManager.cpp
index 7ad1f7070d0a..f69f65c5ddf1 100644
--- a/clang/lib/Format/AffectedRangeManager.cpp
+++ b/clang/lib/Format/AffectedRangeManager.cpp
@@ -27,6 +27,7 @@ bool AffectedRangeManager::computeAffectedLines(
const AnnotatedLine *PreviousLine = nullptr;
while (I != E) {
AnnotatedLine *Line = *I;
+ assert(Line->First);
Line->LeadingEmptyLinesAffected = affectsLeadingEmptyLines(*Line->First);
// If a line is part of a preprocessor directive, it needs to be formatted
@@ -59,13 +60,10 @@ bool AffectedRangeManager::computeAffectedLines(
bool AffectedRangeManager::affectsCharSourceRange(
const CharSourceRange &Range) {
- for (SmallVectorImpl<CharSourceRange>::const_iterator I = Ranges.begin(),
- E = Ranges.end();
- I != E; ++I) {
- if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), I->getBegin()) &&
- !SourceMgr.isBeforeInTranslationUnit(I->getEnd(), Range.getBegin()))
+ for (const CharSourceRange &R : Ranges)
+ if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), R.getBegin()) &&
+ !SourceMgr.isBeforeInTranslationUnit(R.getEnd(), Range.getBegin()))
return true;
- }
return false;
}
@@ -116,6 +114,7 @@ bool AffectedRangeManager::nonPPLineAffected(
// affected.
bool SomeFirstChildAffected = false;
+ assert(Line->First);
for (FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {
// Determine whether 'Tok' was affected.
if (affectsTokenRange(*Tok, *Tok, IncludeLeadingNewlines))
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index 4225d6b67b0e..b66584652bc8 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -341,6 +341,8 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
if (State.Stack.back().BreakBeforeClosingBrace &&
Current.closesBlockOrBlockTypeList(Style))
return true;
+ if (State.Stack.back().BreakBeforeClosingParen && Current.is(tok::r_paren))
+ return true;
if (Previous.is(tok::semi) && State.LineContainsContinuedForLoopSection)
return true;
if (Style.Language == FormatStyle::LK_ObjC &&
@@ -485,7 +487,8 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
// different LineFormatter would be used otherwise.
if (Previous.ClosesTemplateDeclaration)
return Style.AlwaysBreakTemplateDeclarations != FormatStyle::BTDS_No;
- if (Previous.is(TT_FunctionAnnotationRParen))
+ if (Previous.is(TT_FunctionAnnotationRParen) &&
+ State.Line->Type != LT_PreprocessorDirective)
return true;
if (Previous.is(TT_LeadingJavaAnnotation) && Current.isNot(tok::l_paren) &&
Current.isNot(TT_LeadingJavaAnnotation))
@@ -540,13 +543,15 @@ unsigned ContinuationIndenter::addTokenToState(LineState &State, bool Newline,
bool DryRun,
unsigned ExtraSpaces) {
const FormatToken &Current = *State.NextToken;
+ assert(State.NextToken->Previous);
+ const FormatToken &Previous = *State.NextToken->Previous;
assert(!State.Stack.empty());
State.NoContinuation = false;
if ((Current.is(TT_ImplicitStringLiteral) &&
- (Current.Previous->Tok.getIdentifierInfo() == nullptr ||
- Current.Previous->Tok.getIdentifierInfo()->getPPKeywordID() ==
+ (Previous.Tok.getIdentifierInfo() == nullptr ||
+ Previous.Tok.getIdentifierInfo()->getPPKeywordID() ==
tok::pp_not_keyword))) {
unsigned EndColumn =
SourceMgr.getSpellingColumnNumber(Current.WhitespaceRange.getEnd());
@@ -576,7 +581,9 @@ unsigned ContinuationIndenter::addTokenToState(LineState &State, bool Newline,
void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
unsigned ExtraSpaces) {
FormatToken &Current = *State.NextToken;
+ assert(State.NextToken->Previous);
const FormatToken &Previous = *State.NextToken->Previous;
+
if (Current.is(tok::equal) &&
(State.Line->First->is(tok::kw_for) || Current.NestingLevel == 0) &&
State.Stack.back().VariablePos == 0) {
@@ -638,10 +645,12 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
State.Stack.back().ColonPos = FirstColonPos;
}
- // In "AlwaysBreak" mode, enforce wrapping directly after the parenthesis by
- // disallowing any further line breaks if there is no line break after the
- // opening parenthesis. Don't break if it doesn't conserve columns.
- if (Style.AlignAfterOpenBracket == FormatStyle::BAS_AlwaysBreak &&
+ // In "AlwaysBreak" or "BlockIndent" mode, enforce wrapping directly after the
+ // parenthesis by disallowing any further line breaks if there is no line
+ // break after the opening parenthesis. Don't break if it doesn't conserve
+ // columns.
+ if ((Style.AlignAfterOpenBracket == FormatStyle::BAS_AlwaysBreak ||
+ Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent) &&
(Previous.isOneOf(tok::l_paren, TT_TemplateOpener, tok::l_square) ||
(Previous.is(tok::l_brace) && Previous.isNot(BK_Block) &&
Style.Cpp11BracedListStyle)) &&
@@ -770,6 +779,7 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
bool DryRun) {
FormatToken &Current = *State.NextToken;
+ assert(State.NextToken->Previous);
const FormatToken &Previous = *State.NextToken->Previous;
// Extra penalty that needs to be added because of the way certain line
@@ -942,6 +952,10 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
opensProtoMessageField(*PreviousNonComment, Style)))
State.Stack.back().BreakBeforeClosingBrace = true;
+ if (PreviousNonComment && PreviousNonComment->is(tok::l_paren))
+ State.Stack.back().BreakBeforeClosingParen =
+ Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent;
+
if (State.Stack.back().AvoidBinPacking) {
// If we are breaking after '(', '{', '<', or this is the break after a ':'
// to start a member initializater list in a constructor, this should not
@@ -1036,6 +1050,9 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
(!Current.Next ||
Current.Next->isOneOf(tok::semi, tok::kw_const, tok::l_brace)))
return State.Stack[State.Stack.size() - 2].LastSpace;
+ if (Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent &&
+ Current.is(tok::r_paren) && State.Stack.size() > 1)
+ return State.Stack[State.Stack.size() - 2].LastSpace;
if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope())
return State.Stack[State.Stack.size() - 2].LastSpace;
if (Current.is(tok::identifier) && Current.Next &&
@@ -1288,10 +1305,9 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
State.Stack[i].NoLineBreak = true;
State.Stack[State.Stack.size() - 2].NestedBlockInlined = false;
}
- if (Previous &&
- (Previous->isOneOf(tok::l_paren, tok::comma, tok::colon) ||
- Previous->isOneOf(TT_BinaryOperator, TT_ConditionalExpr)) &&
- !Previous->isOneOf(TT_DictLiteral, TT_ObjCMethodExpr)) {
+ if (Previous && (Previous->isOneOf(TT_BinaryOperator, TT_ConditionalExpr) ||
+ (Previous->isOneOf(tok::l_paren, tok::comma, tok::colon) &&
+ !Previous->isOneOf(TT_DictLiteral, TT_ObjCMethodExpr)))) {
State.Stack.back().NestedBlockInlined =
!Newline && hasNestedBlockInlined(Previous, Current, Style);
}
diff --git a/clang/lib/Format/ContinuationIndenter.h b/clang/lib/Format/ContinuationIndenter.h
index b1b2611263a9..0eb53cbd0293 100644
--- a/clang/lib/Format/ContinuationIndenter.h
+++ b/clang/lib/Format/ContinuationIndenter.h
@@ -203,15 +203,15 @@ struct ParenState {
bool AvoidBinPacking, bool NoLineBreak)
: Tok(Tok), Indent(Indent), LastSpace(LastSpace),
NestedBlockIndent(Indent), IsAligned(false),
- BreakBeforeClosingBrace(false), AvoidBinPacking(AvoidBinPacking),
- BreakBeforeParameter(false), NoLineBreak(NoLineBreak),
- NoLineBreakInOperand(false), LastOperatorWrapped(true),
- ContainsLineBreak(false), ContainsUnwrappedBuilder(false),
- AlignColons(true), ObjCSelectorNameFound(false),
- HasMultipleNestedBlocks(false), NestedBlockInlined(false),
- IsInsideObjCArrayLiteral(false), IsCSharpGenericTypeConstraint(false),
- IsChainedConditional(false), IsWrappedConditional(false),
- UnindentOperator(false) {}
+ BreakBeforeClosingBrace(false), BreakBeforeClosingParen(false),
+ AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false),
+ NoLineBreak(NoLineBreak), NoLineBreakInOperand(false),
+ LastOperatorWrapped(true), ContainsLineBreak(false),
+ ContainsUnwrappedBuilder(false), AlignColons(true),
+ ObjCSelectorNameFound(false), HasMultipleNestedBlocks(false),
+ NestedBlockInlined(false), IsInsideObjCArrayLiteral(false),
+ IsCSharpGenericTypeConstraint(false), IsChainedConditional(false),
+ IsWrappedConditional(false), UnindentOperator(false) {}
/// \brief The token opening this parenthesis level, or nullptr if this level
/// is opened by fake parenthesis.
@@ -277,6 +277,13 @@ struct ParenState {
/// was a newline after the beginning left brace.
bool BreakBeforeClosingBrace : 1;
+ /// Whether a newline needs to be inserted before the block's closing
+ /// paren.
+ ///
+ /// We only want to insert a newline before the closing paren if there also
+ /// was a newline after the beginning left paren.
+ bool BreakBeforeClosingParen : 1;
+
/// Avoid bin packing, i.e. multiple parameters/elements on multiple
/// lines, in this context.
bool AvoidBinPacking : 1;
@@ -362,6 +369,8 @@ struct ParenState {
return IsAligned;
if (BreakBeforeClosingBrace != Other.BreakBeforeClosingBrace)
return BreakBeforeClosingBrace;
+ if (BreakBeforeClosingParen != Other.BreakBeforeClosingParen)
+ return BreakBeforeClosingParen;
if (QuestionColumn != Other.QuestionColumn)
return QuestionColumn < Other.QuestionColumn;
if (AvoidBinPacking != Other.AvoidBinPacking)
diff --git a/clang/lib/Format/DefinitionBlockSeparator.cpp b/clang/lib/Format/DefinitionBlockSeparator.cpp
new file mode 100644
index 000000000000..827564357f78
--- /dev/null
+++ b/clang/lib/Format/DefinitionBlockSeparator.cpp
@@ -0,0 +1,236 @@
+//===--- DefinitionBlockSeparator.cpp ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements DefinitionBlockSeparator, a TokenAnalyzer that inserts
+/// or removes empty lines separating definition blocks like classes, structs,
+/// functions, enums, and namespaces in between.
+///
+//===----------------------------------------------------------------------===//
+
+#include "DefinitionBlockSeparator.h"
+#include "llvm/Support/Debug.h"
+#define DEBUG_TYPE "definition-block-separator"
+
+namespace clang {
+namespace format {
+std::pair<tooling::Replacements, unsigned> DefinitionBlockSeparator::analyze(
+ TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
+ FormatTokenLexer &Tokens) {
+ assert(Style.SeparateDefinitionBlocks != FormatStyle::SDS_Leave);
+ AffectedRangeMgr.computeAffectedLines(AnnotatedLines);
+ tooling::Replacements Result;
+ separateBlocks(AnnotatedLines, Result, Tokens);
+ return {Result, 0};
+}
+
+void DefinitionBlockSeparator::separateBlocks(
+ SmallVectorImpl<AnnotatedLine *> &Lines, tooling::Replacements &Result,
+ FormatTokenLexer &Tokens) {
+ const bool IsNeverStyle =
+ Style.SeparateDefinitionBlocks == FormatStyle::SDS_Never;
+ const AdditionalKeywords &ExtraKeywords = Tokens.getKeywords();
+ auto LikelyDefinition = [this, ExtraKeywords](const AnnotatedLine *Line,
+ bool ExcludeEnum = false) {
+ if ((Line->MightBeFunctionDecl && Line->mightBeFunctionDefinition()) ||
+ Line->startsWithNamespace())
+ return true;
+ FormatToken *CurrentToken = Line->First;
+ while (CurrentToken) {
+ if (CurrentToken->isOneOf(tok::kw_class, tok::kw_struct) ||
+ (Style.isJavaScript() && CurrentToken->is(ExtraKeywords.kw_function)))
+ return true;
+ if (!ExcludeEnum && CurrentToken->is(tok::kw_enum))
+ return true;
+ CurrentToken = CurrentToken->Next;
+ }
+ return false;
+ };
+ unsigned NewlineCount =
+ (Style.SeparateDefinitionBlocks == FormatStyle::SDS_Always ? 1 : 0) + 1;
+ WhitespaceManager Whitespaces(
+ Env.getSourceManager(), Style,
+ Style.DeriveLineEnding
+ ? WhitespaceManager::inputUsesCRLF(
+ Env.getSourceManager().getBufferData(Env.getFileID()),
+ Style.UseCRLF)
+ : Style.UseCRLF);
+ for (unsigned I = 0; I < Lines.size(); ++I) {
+ const auto &CurrentLine = Lines[I];
+ if (CurrentLine->InPPDirective)
+ continue;
+ FormatToken *TargetToken = nullptr;
+ AnnotatedLine *TargetLine;
+ auto OpeningLineIndex = CurrentLine->MatchingOpeningBlockLineIndex;
+ AnnotatedLine *OpeningLine = nullptr;
+ const auto IsAccessSpecifierToken = [](const FormatToken *Token) {
+ return Token->isAccessSpecifier() || Token->isObjCAccessSpecifier();
+ };
+ const auto InsertReplacement = [&](const int NewlineToInsert) {
+ assert(TargetLine);
+ assert(TargetToken);
+
+ // Do not handle EOF newlines.
+ if (TargetToken->is(tok::eof))
+ return;
+ if (IsAccessSpecifierToken(TargetToken) ||
+ (OpeningLineIndex > 0 &&
+ IsAccessSpecifierToken(Lines[OpeningLineIndex - 1]->First)))
+ return;
+ if (!TargetLine->Affected)
+ return;
+ Whitespaces.replaceWhitespace(*TargetToken, NewlineToInsert,
+ TargetToken->OriginalColumn,
+ TargetToken->OriginalColumn);
+ };
+ const auto IsPPConditional = [&](const size_t LineIndex) {
+ const auto &Line = Lines[LineIndex];
+ return Line->First->is(tok::hash) && Line->First->Next &&
+ Line->First->Next->isOneOf(tok::pp_if, tok::pp_ifdef, tok::pp_else,
+ tok::pp_ifndef, tok::pp_elifndef,
+ tok::pp_elifdef, tok::pp_elif,
+ tok::pp_endif);
+ };
+ const auto FollowingOtherOpening = [&]() {
+ return OpeningLineIndex == 0 ||
+ Lines[OpeningLineIndex - 1]->Last->opensScope() ||
+ IsPPConditional(OpeningLineIndex - 1);
+ };
+ const auto HasEnumOnLine = [&]() {
+ FormatToken *CurrentToken = CurrentLine->First;
+ bool FoundEnumKeyword = false;
+ while (CurrentToken) {
+ if (CurrentToken->is(tok::kw_enum))
+ FoundEnumKeyword = true;
+ else if (FoundEnumKeyword && CurrentToken->is(tok::l_brace))
+ return true;
+ CurrentToken = CurrentToken->Next;
+ }
+ return FoundEnumKeyword && I + 1 < Lines.size() &&
+ Lines[I + 1]->First->is(tok::l_brace);
+ };
+
+ bool IsDefBlock = false;
+ const auto MayPrecedeDefinition = [&](const int Direction = -1) {
+ assert(Direction >= -1);
+ assert(Direction <= 1);
+ const size_t OperateIndex = OpeningLineIndex + Direction;
+ assert(OperateIndex < Lines.size());
+ const auto &OperateLine = Lines[OperateIndex];
+ if (LikelyDefinition(OperateLine))
+ return false;
+
+ if (OperateLine->First->is(tok::comment))
+ return true;
+
+ // A single line identifier that is not in the last line.
+ if (OperateLine->First->is(tok::identifier) &&
+ OperateLine->First == OperateLine->Last &&
+ OperateIndex + 1 < Lines.size()) {
+ // UnwrappedLineParser's recognition of free-standing macro like
+ // Q_OBJECT may also recognize some uppercased type names that may be
+ // used as return type as that kind of macros, which is a bit hard to
+ // distinguish one from another purely from token patterns. Here, we
+ // try not to add new lines below those identifiers.
+ AnnotatedLine *NextLine = Lines[OperateIndex + 1];
+ if (NextLine->MightBeFunctionDecl &&
+ NextLine->mightBeFunctionDefinition() &&
+ NextLine->First->NewlinesBefore == 1 &&
+ OperateLine->First->is(TT_FunctionLikeOrFreestandingMacro))
+ return true;
+ }
+
+ if ((Style.isCSharp() && OperateLine->First->is(TT_AttributeSquare)))
+ return true;
+ return false;
+ };
+
+ if (HasEnumOnLine() &&
+ !LikelyDefinition(CurrentLine, /*ExcludeEnum=*/true)) {
+ // We have no scope opening/closing information for enum.
+ IsDefBlock = true;
+ OpeningLineIndex = I;
+ while (OpeningLineIndex > 0 && MayPrecedeDefinition())
+ --OpeningLineIndex;
+ OpeningLine = Lines[OpeningLineIndex];
+ TargetLine = OpeningLine;
+ TargetToken = TargetLine->First;
+ if (!FollowingOtherOpening())
+ InsertReplacement(NewlineCount);
+ else if (IsNeverStyle)
+ InsertReplacement(OpeningLineIndex != 0);
+ TargetLine = CurrentLine;
+ TargetToken = TargetLine->First;
+ while (TargetToken && !TargetToken->is(tok::r_brace))
+ TargetToken = TargetToken->Next;
+ if (!TargetToken) {
+ while (I < Lines.size() && !Lines[I]->First->is(tok::r_brace))
+ ++I;
+ }
+ } else if (CurrentLine->First->closesScope()) {
+ if (OpeningLineIndex > Lines.size())
+ continue;
+ // Handling the case that opening brace has its own line, with checking
+ // whether the last line already had an opening brace to guard against
+ // misrecognition.
+ if (OpeningLineIndex > 0 &&
+ Lines[OpeningLineIndex]->First->is(tok::l_brace) &&
+ Lines[OpeningLineIndex - 1]->Last->isNot(tok::l_brace))
+ --OpeningLineIndex;
+ OpeningLine = Lines[OpeningLineIndex];
+ // Closing a function definition.
+ if (LikelyDefinition(OpeningLine)) {
+ IsDefBlock = true;
+ while (OpeningLineIndex > 0 && MayPrecedeDefinition())
+ --OpeningLineIndex;
+ OpeningLine = Lines[OpeningLineIndex];
+ TargetLine = OpeningLine;
+ TargetToken = TargetLine->First;
+ if (!FollowingOtherOpening()) {
+ // Avoid duplicated replacement.
+ if (TargetToken->isNot(tok::l_brace))
+ InsertReplacement(NewlineCount);
+ } else if (IsNeverStyle)
+ InsertReplacement(OpeningLineIndex != 0);
+ }
+ }
+
+ // Not the last token.
+ if (IsDefBlock && I + 1 < Lines.size()) {
+ OpeningLineIndex = I + 1;
+ TargetLine = Lines[OpeningLineIndex];
+ TargetToken = TargetLine->First;
+
+ // No empty line for continuously closing scopes. The token will be
+ // handled in another case if the line following is opening a
+ // definition.
+ if (!TargetToken->closesScope() && !IsPPConditional(OpeningLineIndex)) {
+ // Check whether current line may precede a definition line.
+ while (OpeningLineIndex + 1 < Lines.size() &&
+ MayPrecedeDefinition(/*Direction=*/0))
+ ++OpeningLineIndex;
+ TargetLine = Lines[OpeningLineIndex];
+ if (!LikelyDefinition(TargetLine)) {
+ OpeningLineIndex = I + 1;
+ TargetLine = Lines[I + 1];
+ TargetToken = TargetLine->First;
+ InsertReplacement(NewlineCount);
+ }
+ } else if (IsNeverStyle)
+ InsertReplacement(/*NewlineToInsert=*/1);
+ }
+ }
+ for (const auto &R : Whitespaces.generateReplacements())
+ // The add method returns an Error instance which simulates program exit
+ // code through overloading boolean operator, thus false here indicates
+ // success.
+ if (Result.add(R))
+ return;
+}
+} // namespace format
+} // namespace clang
diff --git a/clang/lib/Format/DefinitionBlockSeparator.h b/clang/lib/Format/DefinitionBlockSeparator.h
new file mode 100644
index 000000000000..31c0f34d6e19
--- /dev/null
+++ b/clang/lib/Format/DefinitionBlockSeparator.h
@@ -0,0 +1,41 @@
+//===--- DefinitionBlockSeparator.h -----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file declares DefinitionBlockSeparator, a TokenAnalyzer that inserts or
+/// removes empty lines separating definition blocks like classes, structs,
+/// functions, enums, and namespaces in between.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_FORMAT_DEFINITIONBLOCKSEPARATOR_H
+#define LLVM_CLANG_LIB_FORMAT_DEFINITIONBLOCKSEPARATOR_H
+
+#include "TokenAnalyzer.h"
+#include "WhitespaceManager.h"
+
+namespace clang {
+namespace format {
+class DefinitionBlockSeparator : public TokenAnalyzer {
+public:
+ DefinitionBlockSeparator(const Environment &Env, const FormatStyle &Style)
+ : TokenAnalyzer(Env, Style) {}
+
+ std::pair<tooling::Replacements, unsigned>
+ analyze(TokenAnnotator &Annotator,
+ SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
+ FormatTokenLexer &Tokens) override;
+
+private:
+ void separateBlocks(SmallVectorImpl<AnnotatedLine *> &Lines,
+ tooling::Replacements &Result, FormatTokenLexer &Tokens);
+};
+} // namespace format
+} // namespace clang
+
+#endif
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index be01daa38929..04e2915e3af6 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -16,6 +16,7 @@
#include "AffectedRangeManager.h"
#include "BreakableToken.h"
#include "ContinuationIndenter.h"
+#include "DefinitionBlockSeparator.h"
#include "FormatInternal.h"
#include "FormatTokenLexer.h"
#include "NamespaceEndCommentsFixer.h"
@@ -383,6 +384,7 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BracketAlignmentStyle> {
IO.enumCase(Value, "Align", FormatStyle::BAS_Align);
IO.enumCase(Value, "DontAlign", FormatStyle::BAS_DontAlign);
IO.enumCase(Value, "AlwaysBreak", FormatStyle::BAS_AlwaysBreak);
+ IO.enumCase(Value, "BlockIndent", FormatStyle::BAS_BlockIndent);
// For backward compatibility.
IO.enumCase(Value, "true", FormatStyle::BAS_Align);
@@ -430,6 +432,15 @@ template <> struct ScalarEnumerationTraits<FormatStyle::PointerAlignmentStyle> {
};
template <>
+struct ScalarEnumerationTraits<FormatStyle::SeparateDefinitionStyle> {
+ static void enumeration(IO &IO, FormatStyle::SeparateDefinitionStyle &Value) {
+ IO.enumCase(Value, "Leave", FormatStyle::SDS_Leave);
+ IO.enumCase(Value, "Always", FormatStyle::SDS_Always);
+ IO.enumCase(Value, "Never", FormatStyle::SDS_Never);
+ }
+};
+
+template <>
struct ScalarEnumerationTraits<FormatStyle::SpaceAroundPointerQualifiersStyle> {
static void
enumeration(IO &IO, FormatStyle::SpaceAroundPointerQualifiersStyle &Value) {
@@ -756,6 +767,8 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("PenaltyBreakComment", Style.PenaltyBreakComment);
IO.mapOptional("PenaltyBreakFirstLessLess",
Style.PenaltyBreakFirstLessLess);
+ IO.mapOptional("PenaltyBreakOpenParenthesis",
+ Style.PenaltyBreakOpenParenthesis);
IO.mapOptional("PenaltyBreakString", Style.PenaltyBreakString);
IO.mapOptional("PenaltyBreakTemplateDeclaration",
Style.PenaltyBreakTemplateDeclaration);
@@ -769,6 +782,8 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("RawStringFormats", Style.RawStringFormats);
IO.mapOptional("ReferenceAlignment", Style.ReferenceAlignment);
IO.mapOptional("ReflowComments", Style.ReflowComments);
+ IO.mapOptional("RemoveBracesLLVM", Style.RemoveBracesLLVM);
+ IO.mapOptional("SeparateDefinitionBlocks", Style.SeparateDefinitionBlocks);
IO.mapOptional("ShortNamespaceLines", Style.ShortNamespaceLines);
IO.mapOptional("SortIncludes", Style.SortIncludes);
IO.mapOptional("SortJavaStaticImport", Style.SortJavaStaticImport);
@@ -855,6 +870,7 @@ template <> struct MappingTraits<FormatStyle::SpaceBeforeParensCustom> {
IO.mapOptional("AfterFunctionDeclarationName",
Spacing.AfterFunctionDeclarationName);
IO.mapOptional("AfterIfMacros", Spacing.AfterIfMacros);
+ IO.mapOptional("AfterOverloadedOperator", Spacing.AfterOverloadedOperator);
IO.mapOptional("BeforeNonEmptyParentheses",
Spacing.BeforeNonEmptyParentheses);
}
@@ -1193,12 +1209,14 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.ObjCSpaceBeforeProtocolList = true;
LLVMStyle.PointerAlignment = FormatStyle::PAS_Right;
LLVMStyle.ReferenceAlignment = FormatStyle::RAS_Pointer;
+ LLVMStyle.SeparateDefinitionBlocks = FormatStyle::SDS_Leave;
LLVMStyle.ShortNamespaceLines = 1;
LLVMStyle.SpacesBeforeTrailingComments = 1;
LLVMStyle.Standard = FormatStyle::LS_Latest;
LLVMStyle.UseCRLF = false;
LLVMStyle.UseTab = FormatStyle::UT_Never;
LLVMStyle.ReflowComments = true;
+ LLVMStyle.RemoveBracesLLVM = false;
LLVMStyle.SpacesInParentheses = false;
LLVMStyle.SpacesInSquareBrackets = false;
LLVMStyle.SpaceInEmptyBlock = false;
@@ -1232,6 +1250,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.PenaltyExcessCharacter = 1000000;
LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 60;
LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19;
+ LLVMStyle.PenaltyBreakOpenParenthesis = 0;
LLVMStyle.PenaltyBreakTemplateDeclaration = prec::Relational;
LLVMStyle.PenaltyIndentedWhitespace = 0;
@@ -1732,6 +1751,45 @@ FormatStyle::GetLanguageStyle(FormatStyle::LanguageKind Language) const {
namespace {
+class BracesRemover : public TokenAnalyzer {
+public:
+ BracesRemover(const Environment &Env, const FormatStyle &Style)
+ : TokenAnalyzer(Env, Style) {}
+
+ std::pair<tooling::Replacements, unsigned>
+ analyze(TokenAnnotator &Annotator,
+ SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
+ FormatTokenLexer &Tokens) override {
+ AffectedRangeMgr.computeAffectedLines(AnnotatedLines);
+ tooling::Replacements Result;
+ removeBraces(AnnotatedLines, Result);
+ return {Result, 0};
+ }
+
+private:
+ // Remove optional braces.
+ void removeBraces(SmallVectorImpl<AnnotatedLine *> &Lines,
+ tooling::Replacements &Result) {
+ const auto &SourceMgr = Env.getSourceManager();
+ for (AnnotatedLine *Line : Lines) {
+ removeBraces(Line->Children, Result);
+ if (!Line->Affected)
+ continue;
+ for (FormatToken *Token = Line->First; Token; Token = Token->Next) {
+ if (!Token->Optional)
+ continue;
+ assert(Token->isOneOf(tok::l_brace, tok::r_brace));
+ const auto Start = Token == Line->Last
+ ? Token->WhitespaceRange.getBegin()
+ : Token->Tok.getLocation();
+ const auto Range =
+ CharSourceRange::getCharRange(Start, Token->Tok.getEndLoc());
+ cantFail(Result.add(tooling::Replacement(SourceMgr, Range, "")));
+ }
+ }
+ }
+};
+
class JavaScriptRequoter : public TokenAnalyzer {
public:
JavaScriptRequoter(const Environment &Env, const FormatStyle &Style)
@@ -1840,7 +1898,7 @@ public:
WhitespaceManager Whitespaces(
Env.getSourceManager(), Style,
Style.DeriveLineEnding
- ? inputUsesCRLF(
+ ? WhitespaceManager::inputUsesCRLF(
Env.getSourceManager().getBufferData(Env.getFileID()),
Style.UseCRLF)
: Style.UseCRLF);
@@ -1864,19 +1922,13 @@ public:
}
private:
- 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
hasCpp03IncompatibleFormat(const SmallVectorImpl<AnnotatedLine *> &Lines) {
for (const AnnotatedLine *Line : Lines) {
if (hasCpp03IncompatibleFormat(Line->Children))
return true;
for (FormatToken *Tok = Line->First->Next; Tok; Tok = Tok->Next) {
- if (Tok->WhitespaceRange.getBegin() == Tok->WhitespaceRange.getEnd()) {
+ if (!Tok->hasWhitespaceBefore()) {
if (Tok->is(tok::coloncolon) && Tok->Previous->is(TT_TemplateOpener))
return true;
if (Tok->is(TT_TemplateCloser) &&
@@ -1895,10 +1947,8 @@ private:
for (FormatToken *Tok = Line->First; Tok && Tok->Next; Tok = Tok->Next) {
if (!Tok->is(TT_PointerOrReference))
continue;
- bool SpaceBefore =
- Tok->WhitespaceRange.getBegin() != Tok->WhitespaceRange.getEnd();
- bool SpaceAfter = Tok->Next->WhitespaceRange.getBegin() !=
- Tok->Next->WhitespaceRange.getEnd();
+ bool SpaceBefore = Tok->hasWhitespaceBefore();
+ bool SpaceAfter = Tok->Next->hasWhitespaceBefore();
if (SpaceBefore && !SpaceAfter)
++AlignmentDiff;
if (!SpaceBefore && SpaceAfter)
@@ -2204,7 +2254,7 @@ private:
unsigned St = Idx, End = Idx;
while ((End + 1) < Tokens.size() &&
Tokens[End]->Next == Tokens[End + 1]) {
- End++;
+ ++End;
}
auto SR = CharSourceRange::getCharRange(Tokens[St]->Tok.getLocation(),
Tokens[End]->Tok.getEndLoc());
@@ -2440,7 +2490,7 @@ std::string replaceCRLF(const std::string &Code) {
do {
Pos = Code.find("\r\n", LastPos);
if (Pos == LastPos) {
- LastPos++;
+ ++LastPos;
continue;
}
if (Pos == std::string::npos) {
@@ -2586,8 +2636,9 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code,
bool MainIncludeFound = false;
bool FormattingOff = false;
+ // '[' must be the first and '-' the last character inside [...].
llvm::Regex RawStringRegex(
- "R\"(([\\[A-Za-z0-9_{}#<>%:;.?*+/^&\\$|~!=,'\\-]|])*)\\(");
+ "R\"([][A-Za-z0-9_{}#<>%:;.?*+/^&\\$|~!=,'-]*)\\(");
SmallVector<StringRef, 2> RawStringMatches;
std::string RawStringTermination = ")\"";
@@ -3038,6 +3089,11 @@ reformat(const FormatStyle &Style, StringRef Code,
});
}
+ if (Style.isCpp() && Style.RemoveBracesLLVM)
+ Passes.emplace_back([&](const Environment &Env) {
+ return BracesRemover(Env, Expanded).process();
+ });
+
if (Style.Language == FormatStyle::LK_Cpp) {
if (Style.FixNamespaceComments)
Passes.emplace_back([&](const Environment &Env) {
@@ -3050,6 +3106,11 @@ reformat(const FormatStyle &Style, StringRef Code,
});
}
+ if (Style.SeparateDefinitionBlocks != FormatStyle::SDS_Leave)
+ Passes.emplace_back([&](const Environment &Env) {
+ return DefinitionBlockSeparator(Env, Expanded).process();
+ });
+
if (Style.isJavaScript() && Style.JavaScriptQuotes != FormatStyle::JSQS_Leave)
Passes.emplace_back([&](const Environment &Env) {
return JavaScriptRequoter(Env, Expanded).process();
@@ -3138,6 +3199,16 @@ tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style,
return NamespaceEndCommentsFixer(*Env, Style).process().first;
}
+tooling::Replacements separateDefinitionBlocks(const FormatStyle &Style,
+ StringRef Code,
+ ArrayRef<tooling::Range> Ranges,
+ StringRef FileName) {
+ auto Env = Environment::make(Code, FileName, Ranges);
+ if (!Env)
+ return {};
+ return DefinitionBlockSeparator(*Env, Style).process().first;
+}
+
tooling::Replacements sortUsingDeclarations(const FormatStyle &Style,
StringRef Code,
ArrayRef<tooling::Range> Ranges,
@@ -3181,6 +3252,8 @@ const char *StyleOptionHelpDescription =
".clang-format file located in one of the parent\n"
"directories of the source file (or current\n"
"directory for stdin).\n"
+ "Use -style=file:<format_file_path> to explicitly specify"
+ "the configuration file.\n"
"Use -style=\"{key: value, ...}\" to set specific\n"
"parameters, e.g.:\n"
" -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
@@ -3233,6 +3306,18 @@ const char *DefaultFormatStyle = "file";
const char *DefaultFallbackStyle = "LLVM";
+llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+loadAndParseConfigFile(StringRef ConfigFile, llvm::vfs::FileSystem *FS,
+ FormatStyle *Style, bool AllowUnknownOptions) {
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
+ FS->getBufferForFile(ConfigFile.str());
+ if (auto EC = Text.getError())
+ return EC;
+ if (auto EC = parseConfiguration(*Text.get(), Style, AllowUnknownOptions))
+ return EC;
+ return Text;
+}
+
llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
StringRef FallbackStyleName,
StringRef Code, llvm::vfs::FileSystem *FS,
@@ -3263,6 +3348,28 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
return Style;
}
+ // User provided clang-format file using -style=file:path/to/format/file.
+ if (!Style.InheritsParentConfig &&
+ StyleName.startswith_insensitive("file:")) {
+ auto ConfigFile = StyleName.substr(5);
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
+ loadAndParseConfigFile(ConfigFile, FS, &Style, AllowUnknownOptions);
+ if (auto EC = Text.getError())
+ return make_string_error("Error reading " + ConfigFile + ": " +
+ EC.message());
+
+ LLVM_DEBUG(llvm::dbgs()
+ << "Using configuration file " << ConfigFile << "\n");
+
+ if (!Style.InheritsParentConfig)
+ return Style;
+
+ // Search for parent configs starting from the parent directory of
+ // ConfigFile.
+ FileName = ConfigFile;
+ ChildFormatTextToApply.emplace_back(std::move(*Text));
+ }
+
// If the style inherits the parent configuration it is a command line
// configuration, which wants to inherit, so we have to skip the check of the
// StyleName.
@@ -3288,6 +3395,16 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
auto dropDiagnosticHandler = [](const llvm::SMDiagnostic &, void *) {};
+ auto applyChildFormatTexts = [&](FormatStyle *Style) {
+ for (const auto &MemBuf : llvm::reverse(ChildFormatTextToApply)) {
+ auto EC = parseConfiguration(*MemBuf, Style, AllowUnknownOptions,
+ dropDiagnosticHandler);
+ // It was already correctly parsed.
+ assert(!EC);
+ static_cast<void>(EC);
+ }
+ };
+
for (StringRef Directory = Path; !Directory.empty();
Directory = llvm::sys::path::parent_path(Directory)) {
@@ -3308,19 +3425,16 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
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(), &Style, AllowUnknownOptions)) {
- if (ec == ParseError::Unsuitable) {
+ loadAndParseConfigFile(ConfigFile, FS, &Style, AllowUnknownOptions);
+ if (auto EC = Text.getError()) {
+ if (EC == ParseError::Unsuitable) {
if (!UnsuitableConfigFiles.empty())
UnsuitableConfigFiles.append(", ");
UnsuitableConfigFiles.append(ConfigFile);
continue;
}
return make_string_error("Error reading " + ConfigFile + ": " +
- ec.message());
+ EC.message());
}
LLVM_DEBUG(llvm::dbgs()
<< "Using configuration file " << ConfigFile << "\n");
@@ -3330,14 +3444,7 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
return Style;
LLVM_DEBUG(llvm::dbgs() << "Applying child configurations\n");
-
- for (const auto &MemBuf : llvm::reverse(ChildFormatTextToApply)) {
- auto Ec = parseConfiguration(*MemBuf, &Style, AllowUnknownOptions,
- dropDiagnosticHandler);
- // It was already correctly parsed.
- assert(!Ec);
- static_cast<void>(Ec);
- }
+ applyChildFormatTexts(&Style);
return Style;
}
@@ -3363,17 +3470,9 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
UnsuitableConfigFiles);
if (!ChildFormatTextToApply.empty()) {
- assert(ChildFormatTextToApply.size() == 1);
-
LLVM_DEBUG(llvm::dbgs()
- << "Applying child configuration on fallback style\n");
-
- auto Ec =
- parseConfiguration(*ChildFormatTextToApply.front(), &FallbackStyle,
- AllowUnknownOptions, dropDiagnosticHandler);
- // It was already correctly parsed.
- assert(!Ec);
- static_cast<void>(Ec);
+ << "Applying child configurations on fallback style\n");
+ applyChildFormatTexts(&FallbackStyle);
}
return FallbackStyle;
diff --git a/clang/lib/Format/FormatToken.cpp b/clang/lib/Format/FormatToken.cpp
index 57f8a5a45cbb..59d6f29bb54d 100644
--- a/clang/lib/Format/FormatToken.cpp
+++ b/clang/lib/Format/FormatToken.cpp
@@ -189,6 +189,7 @@ void CommaSeparatedList::precomputeFormattingInfos(const FormatToken *Token) {
bool HasSeparatingComment = false;
for (unsigned i = 0, e = Commas.size() + 1; i != e; ++i) {
+ assert(ItemBegin);
// Skip comments on their own line.
while (ItemBegin->HasUnescapedNewline && ItemBegin->isTrailingComment()) {
ItemBegin = ItemBegin->Next;
@@ -296,14 +297,11 @@ void CommaSeparatedList::precomputeFormattingInfos(const FormatToken *Token) {
const CommaSeparatedList::ColumnFormat *
CommaSeparatedList::getColumnFormat(unsigned RemainingCharacters) const {
const ColumnFormat *BestFormat = nullptr;
- for (SmallVector<ColumnFormat, 4>::const_reverse_iterator
- I = Formats.rbegin(),
- E = Formats.rend();
- I != E; ++I) {
- if (I->TotalWidth <= RemainingCharacters || I->Columns == 1) {
- if (BestFormat && I->LineCount > BestFormat->LineCount)
+ for (const ColumnFormat &Format : llvm::reverse(Formats)) {
+ if (Format.TotalWidth <= RemainingCharacters || Format.Columns == 1) {
+ if (BestFormat && Format.LineCount > BestFormat->LineCount)
break;
- BestFormat = &*I;
+ BestFormat = &Format;
}
}
return BestFormat;
diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h
index d410ede32240..a64329802ee3 100644
--- a/clang/lib/Format/FormatToken.h
+++ b/clang/lib/Format/FormatToken.h
@@ -51,6 +51,7 @@ namespace format {
TYPE(FunctionAnnotationRParen) \
TYPE(FunctionDeclarationName) \
TYPE(FunctionLBrace) \
+ TYPE(FunctionLikeOrFreestandingMacro) \
TYPE(FunctionTypeLParen) \
TYPE(IfMacro) \
TYPE(ImplicitStringLiteral) \
@@ -95,6 +96,7 @@ namespace format {
TYPE(PointerOrReference) \
TYPE(PureVirtualSpecifier) \
TYPE(RangeBasedForLoopColon) \
+ TYPE(RecordLBrace) \
TYPE(RegexLiteral) \
TYPE(SelectorName) \
TYPE(StartOfName) \
@@ -442,6 +444,9 @@ public:
/// This starts an array initializer.
bool IsArrayInitializer = false;
+ /// Is optional and can be removed.
+ bool Optional = false;
+
/// If this token starts a block, this contains all the unwrapped lines
/// in it.
SmallVector<AnnotatedLine *, 1> Children;
@@ -634,6 +639,12 @@ public:
return WhitespaceRange.getEnd();
}
+ /// Returns \c true if the range of whitespace immediately preceding the \c
+ /// Token is not empty.
+ bool hasWhitespaceBefore() const {
+ return WhitespaceRange.getBegin() != WhitespaceRange.getEnd();
+ }
+
prec::Level getPrecedence() const {
return getBinOpPrecedence(Tok.getKind(), /*GreaterThanIsOperator=*/true,
/*CPlusPlus11=*/true);
diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp
index 7736a7042f86..c9166f4b17aa 100644
--- a/clang/lib/Format/FormatTokenLexer.cpp
+++ b/clang/lib/Format/FormatTokenLexer.cpp
@@ -429,18 +429,21 @@ bool FormatTokenLexer::tryMergeLessLess() {
if (Tokens.size() < 3)
return false;
- bool FourthTokenIsLess = false;
- if (Tokens.size() > 3)
- FourthTokenIsLess = (Tokens.end() - 4)[0]->is(tok::less);
-
auto First = Tokens.end() - 3;
- if (First[2]->is(tok::less) || First[1]->isNot(tok::less) ||
- First[0]->isNot(tok::less) || FourthTokenIsLess)
+ if (First[0]->isNot(tok::less) || First[1]->isNot(tok::less))
return false;
// Only merge if there currently is no whitespace between the two "<".
- if (First[1]->WhitespaceRange.getBegin() !=
- First[1]->WhitespaceRange.getEnd())
+ if (First[1]->hasWhitespaceBefore())
+ return false;
+
+ auto X = Tokens.size() > 3 ? First[-1] : nullptr;
+ auto Y = First[2];
+ if ((X && X->is(tok::less)) || Y->is(tok::less))
+ return false;
+
+ // Do not remove a whitespace between the two "<" e.g. "operator< <>".
+ if (X && X->is(tok::kw_operator) && Y->is(tok::greater))
return false;
First[0]->Tok.setKind(tok::lessless);
@@ -461,8 +464,7 @@ bool FormatTokenLexer::tryMergeTokens(ArrayRef<tok::TokenKind> Kinds,
return false;
unsigned AddLength = 0;
for (unsigned i = 1; i < Kinds.size(); ++i) {
- if (!First[i]->is(Kinds[i]) || First[i]->WhitespaceRange.getBegin() !=
- First[i]->WhitespaceRange.getEnd())
+ if (!First[i]->is(Kinds[i]) || First[i]->hasWhitespaceBefore())
return false;
AddLength += First[i]->TokenText.size();
}
diff --git a/clang/lib/Format/NamespaceEndCommentsFixer.cpp b/clang/lib/Format/NamespaceEndCommentsFixer.cpp
index 38ab5b9df76d..0c34c6126c21 100644
--- a/clang/lib/Format/NamespaceEndCommentsFixer.cpp
+++ b/clang/lib/Format/NamespaceEndCommentsFixer.cpp
@@ -28,7 +28,7 @@ std::string computeName(const FormatToken *NamespaceTok) {
assert(NamespaceTok &&
NamespaceTok->isOneOf(tok::kw_namespace, TT_NamespaceMacro) &&
"expecting a namespace token");
- std::string name = "";
+ std::string name;
const FormatToken *Tok = NamespaceTok->getNextNonComment();
if (NamespaceTok->is(TT_NamespaceMacro)) {
// Collects all the non-comment tokens between opening parenthesis
@@ -224,7 +224,7 @@ std::pair<tooling::Replacements, unsigned> NamespaceEndCommentsFixer::analyze(
return {Fixes, 0};
}
- std::string AllNamespaceNames = "";
+ std::string AllNamespaceNames;
size_t StartLineIndex = SIZE_MAX;
StringRef NamespaceTokenText;
unsigned int CompactedNamespacesCount = 0;
@@ -260,8 +260,9 @@ std::pair<tooling::Replacements, unsigned> NamespaceEndCommentsFixer::analyze(
// remove end comment, it will be merged in next one
updateEndComment(EndCommentPrevTok, std::string(), SourceMgr, &Fixes);
}
- CompactedNamespacesCount++;
- AllNamespaceNames = "::" + NamespaceName + AllNamespaceNames;
+ ++CompactedNamespacesCount;
+ if (!NamespaceName.empty())
+ AllNamespaceNames = "::" + NamespaceName + AllNamespaceNames;
continue;
}
NamespaceName += AllNamespaceNames;
diff --git a/clang/lib/Format/QualifierAlignmentFixer.cpp b/clang/lib/Format/QualifierAlignmentFixer.cpp
index 5a89225c7fc8..b3a4684bead1 100644
--- a/clang/lib/Format/QualifierAlignmentFixer.cpp
+++ b/clang/lib/Format/QualifierAlignmentFixer.cpp
@@ -88,11 +88,11 @@ std::pair<tooling::Replacements, unsigned> QualifierAlignmentFixer::analyze(
// Don't make replacements that replace nothing.
tooling::Replacements NonNoOpFixes;
- for (auto I = Fixes.begin(), E = Fixes.end(); I != E; ++I) {
- StringRef OriginalCode = Code.substr(I->getOffset(), I->getLength());
+ for (const tooling::Replacement &Fix : Fixes) {
+ StringRef OriginalCode = Code.substr(Fix.getOffset(), Fix.getLength());
- if (!OriginalCode.equals(I->getReplacementText())) {
- auto Err = NonNoOpFixes.add(*I);
+ if (!OriginalCode.equals(Fix.getReplacementText())) {
+ auto Err = NonNoOpFixes.add(Fix);
if (Err)
llvm::errs() << "Error adding replacements : "
<< llvm::toString(std::move(Err)) << "\n";
@@ -204,9 +204,9 @@ static void rotateTokens(const SourceManager &SourceMgr,
replaceToken(SourceMgr, Fixes, Range, NewText);
}
-FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight(
+const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight(
const SourceManager &SourceMgr, const AdditionalKeywords &Keywords,
- tooling::Replacements &Fixes, FormatToken *Tok,
+ tooling::Replacements &Fixes, const FormatToken *Tok,
const std::string &Qualifier, tok::TokenKind QualifierType) {
// We only need to think about streams that begin with a qualifier.
if (!Tok->is(QualifierType))
@@ -261,10 +261,8 @@ FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight(
// Move to the end of any template class members e.g.
// `Foo<int>::iterator`.
if (Next && Next->startsSequence(TT_TemplateCloser, tok::coloncolon,
- tok::identifier)) {
- Next = Next->Next->Next;
+ tok::identifier))
return Tok;
- }
assert(Next && "Missing template opener");
Next = Next->Next;
}
@@ -281,16 +279,16 @@ FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight(
return Tok;
}
-FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft(
+const FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft(
const SourceManager &SourceMgr, const AdditionalKeywords &Keywords,
- tooling::Replacements &Fixes, FormatToken *Tok,
+ tooling::Replacements &Fixes, const FormatToken *Tok,
const std::string &Qualifier, tok::TokenKind QualifierType) {
// if Tok is an identifier and possibly a macro then don't convert.
if (LeftRightQualifierAlignmentFixer::isPossibleMacro(Tok))
return Tok;
- FormatToken *Qual = Tok;
- FormatToken *LastQual = Qual;
+ const FormatToken *Qual = Tok;
+ const FormatToken *LastQual = Qual;
while (Qual && isQualifierOrType(Qual, ConfiguredQualifierTokens)) {
LastQual = Qual;
Qual = Qual->Next;
@@ -326,7 +324,7 @@ FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft(
Tok->Previous->isOneOf(tok::star, tok::ampamp, tok::amp)) {
return Tok;
}
- FormatToken *Next = Tok->Next;
+ const FormatToken *Next = Tok->Next;
// The case `std::Foo<T> const` -> `const std::Foo<T> &&`
while (Next && Next->isOneOf(tok::identifier, tok::coloncolon))
Next = Next->Next;
@@ -334,6 +332,8 @@ FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft(
Next->Previous->startsSequence(tok::identifier, TT_TemplateOpener)) {
// Read from to the end of the TemplateOpener to
// TemplateCloser const ArrayRef<int> a; const ArrayRef<int> &a;
+ if (Next->is(tok::comment) && Next->getNextNonComment())
+ Next = Next->getNextNonComment();
assert(Next->MatchingParen && "Missing template closer");
Next = Next->MatchingParen->Next;
@@ -394,11 +394,12 @@ LeftRightQualifierAlignmentFixer::analyze(
tok::TokenKind QualifierToken = getTokenFromQualifier(Qualifier);
assert(QualifierToken != tok::identifier && "Unrecognised Qualifier");
- for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) {
- FormatToken *First = AnnotatedLines[I]->First;
- const auto *Last = AnnotatedLines[I]->Last;
+ for (AnnotatedLine *Line : AnnotatedLines) {
+ FormatToken *First = Line->First;
+ const auto *Last = Line->Last;
- for (auto *Tok = First; Tok && Tok != Last && Tok->Next; Tok = Tok->Next) {
+ for (const auto *Tok = First; Tok && Tok != Last && Tok->Next;
+ Tok = Tok->Next) {
if (Tok->is(tok::comment))
continue;
if (RightAlign)
diff --git a/clang/lib/Format/QualifierAlignmentFixer.h b/clang/lib/Format/QualifierAlignmentFixer.h
index 7abd25687564..30ef96b8b0a7 100644
--- a/clang/lib/Format/QualifierAlignmentFixer.h
+++ b/clang/lib/Format/QualifierAlignmentFixer.h
@@ -72,17 +72,19 @@ public:
static tok::TokenKind getTokenFromQualifier(const std::string &Qualifier);
- FormatToken *analyzeRight(const SourceManager &SourceMgr,
- const AdditionalKeywords &Keywords,
- tooling::Replacements &Fixes, FormatToken *Tok,
- const std::string &Qualifier,
- tok::TokenKind QualifierType);
+ const FormatToken *analyzeRight(const SourceManager &SourceMgr,
+ const AdditionalKeywords &Keywords,
+ tooling::Replacements &Fixes,
+ const FormatToken *Tok,
+ const std::string &Qualifier,
+ tok::TokenKind QualifierType);
- FormatToken *analyzeLeft(const SourceManager &SourceMgr,
- const AdditionalKeywords &Keywords,
- tooling::Replacements &Fixes, FormatToken *Tok,
- const std::string &Qualifier,
- tok::TokenKind QualifierType);
+ const FormatToken *analyzeLeft(const SourceManager &SourceMgr,
+ const AdditionalKeywords &Keywords,
+ tooling::Replacements &Fixes,
+ const FormatToken *Tok,
+ const std::string &Qualifier,
+ tok::TokenKind QualifierType);
// is the Token a simple or qualifier type
static bool isQualifierOrType(const FormatToken *Tok,
diff --git a/clang/lib/Format/SortJavaScriptImports.cpp b/clang/lib/Format/SortJavaScriptImports.cpp
index 77dc0d683e5f..e4107525a7ff 100644
--- a/clang/lib/Format/SortJavaScriptImports.cpp
+++ b/clang/lib/Format/SortJavaScriptImports.cpp
@@ -78,6 +78,7 @@ struct JsModuleReference {
ABSOLUTE, // from 'something'
RELATIVE_PARENT, // from '../*'
RELATIVE, // from './*'
+ ALIAS, // import X = A.B;
};
ReferenceCategory Category = ReferenceCategory::SIDE_EFFECT;
// The URL imported, e.g. `import .. from 'url';`. Empty for `export {a, b};`.
@@ -105,10 +106,12 @@ bool operator<(const JsModuleReference &LHS, const JsModuleReference &RHS) {
return LHS.IsExport < RHS.IsExport;
if (LHS.Category != RHS.Category)
return LHS.Category < RHS.Category;
- if (LHS.Category == JsModuleReference::ReferenceCategory::SIDE_EFFECT)
- // Side effect imports might be ordering sensitive. Consider them equal so
- // that they maintain their relative order in the stable sort below.
- // This retains transitivity because LHS.Category == RHS.Category here.
+ if (LHS.Category == JsModuleReference::ReferenceCategory::SIDE_EFFECT ||
+ LHS.Category == JsModuleReference::ReferenceCategory::ALIAS)
+ // Side effect imports and aliases might be ordering sensitive. Consider
+ // them equal so that they maintain their relative order in the stable sort
+ // below. This retains transitivity because LHS.Category == RHS.Category
+ // here.
return false;
// Empty URLs sort *last* (for export {...};).
if (LHS.URL.empty() != RHS.URL.empty())
@@ -260,13 +263,13 @@ private:
while (Start != References.end() && Start->FormattingOff) {
// Skip over all imports w/ disabled formatting.
ReferencesSorted.push_back(*Start);
- Start++;
+ ++Start;
}
SmallVector<JsModuleReference, 16> SortChunk;
while (Start != References.end() && !Start->FormattingOff) {
// Skip over all imports w/ disabled formatting.
SortChunk.push_back(*Start);
- Start++;
+ ++Start;
}
llvm::stable_sort(SortChunk);
mergeModuleReferences(SortChunk);
@@ -338,10 +341,12 @@ private:
// Stitch together the module reference start...
Buffer += getSourceText(Reference.Range.getBegin(), Reference.SymbolsStart);
// ... then the references in order ...
- for (auto I = Symbols.begin(), E = Symbols.end(); I != E; ++I) {
- if (I != Symbols.begin())
+ if (!Symbols.empty()) {
+ Buffer += getSourceText(Symbols.front().Range);
+ for (const JsImportedSymbol &Symbol : llvm::drop_begin(Symbols)) {
Buffer += ",";
- Buffer += getSourceText(I->Range);
+ Buffer += getSourceText(Symbol.Range);
+ }
}
// ... followed by the module reference end.
Buffer += getSourceText(Reference.SymbolsEnd, Reference.Range.getEnd());
@@ -359,6 +364,7 @@ private:
bool AnyImportAffected = false;
bool FormattingOff = false;
for (auto *Line : AnnotatedLines) {
+ assert(Line->First);
Current = Line->First;
LineEnd = Line->Last;
// clang-format comments toggle formatting on/off.
@@ -395,6 +401,8 @@ private:
JsModuleReference Reference;
Reference.FormattingOff = FormattingOff;
Reference.Range.setBegin(Start);
+ // References w/o a URL, e.g. export {A}, groups with RELATIVE.
+ Reference.Category = JsModuleReference::ReferenceCategory::RELATIVE;
if (!parseModuleReference(Keywords, Reference)) {
if (!FirstNonImportLine)
FirstNonImportLine = Line; // if no comment before.
@@ -410,9 +418,8 @@ private:
<< ", cat: " << Reference.Category
<< ", url: " << Reference.URL
<< ", prefix: " << Reference.Prefix;
- for (size_t I = 0; I < Reference.Symbols.size(); ++I)
- llvm::dbgs() << ", " << Reference.Symbols[I].Symbol << " as "
- << Reference.Symbols[I].Alias;
+ for (const JsImportedSymbol &Symbol : Reference.Symbols)
+ llvm::dbgs() << ", " << Symbol.Symbol << " as " << Symbol.Alias;
llvm::dbgs() << ", text: " << getSourceText(Reference.Range);
llvm::dbgs() << "}\n";
});
@@ -461,9 +468,6 @@ private:
Reference.Category = JsModuleReference::ReferenceCategory::RELATIVE;
else
Reference.Category = JsModuleReference::ReferenceCategory::ABSOLUTE;
- } else {
- // w/o URL groups with "empty".
- Reference.Category = JsModuleReference::ReferenceCategory::RELATIVE;
}
return true;
}
@@ -499,6 +503,21 @@ private:
nextToken();
if (Current->is(Keywords.kw_from))
return true;
+ // import X = A.B.C;
+ if (Current->is(tok::equal)) {
+ Reference.Category = JsModuleReference::ReferenceCategory::ALIAS;
+ nextToken();
+ while (Current->is(tok::identifier)) {
+ nextToken();
+ if (Current->is(tok::semi)) {
+ nextToken();
+ return true;
+ }
+ if (!Current->is(tok::period))
+ return false;
+ nextToken();
+ }
+ }
if (Current->isNot(tok::comma))
return false;
nextToken(); // eat comma.
diff --git a/clang/lib/Format/TokenAnalyzer.cpp b/clang/lib/Format/TokenAnalyzer.cpp
index d83e837ca134..d0754e0c1112 100644
--- a/clang/lib/Format/TokenAnalyzer.cpp
+++ b/clang/lib/Format/TokenAnalyzer.cpp
@@ -127,11 +127,8 @@ std::pair<tooling::Replacements, unsigned> TokenAnalyzer::process() {
LLVM_DEBUG({
llvm::dbgs() << "Replacements for run " << Run << ":\n";
- for (tooling::Replacements::const_iterator I = RunResult.first.begin(),
- E = RunResult.first.end();
- I != E; ++I) {
- llvm::dbgs() << I->toString() << "\n";
- }
+ for (const tooling::Replacement &Fix : RunResult.first)
+ llvm::dbgs() << Fix.toString() << "\n";
});
for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
delete AnnotatedLines[i];
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 505a7250572b..9d130dbb02eb 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -75,7 +75,7 @@ public:
: Style(Style), Line(Line), CurrentToken(Line.First), AutoFound(false),
Keywords(Keywords) {
Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/false));
- resetTokenMetadata(CurrentToken);
+ resetTokenMetadata();
}
private:
@@ -780,6 +780,7 @@ private:
unsigned CommaCount = 0;
while (CurrentToken) {
if (CurrentToken->is(tok::r_brace)) {
+ assert(Left->Optional == CurrentToken->Optional);
Left->MatchingParen = CurrentToken;
CurrentToken->MatchingParen = Left;
if (Style.AlignArrayOfStructures != FormatStyle::AIAS_None) {
@@ -1409,8 +1410,8 @@ private:
Tok.Next->Next->Next && Tok.Next->Next->Next->is(tok::l_paren);
}
- void resetTokenMetadata(FormatToken *Token) {
- if (!Token)
+ void resetTokenMetadata() {
+ if (!CurrentToken)
return;
// Reset token type in case we have already looked at it and then
@@ -1422,7 +1423,8 @@ private:
TT_LambdaArrow, TT_NamespaceMacro, TT_OverloadedOperator,
TT_RegexLiteral, TT_TemplateString, TT_ObjCStringLiteral,
TT_UntouchableMacroFunc, TT_ConstraintJunctions,
- TT_StatementAttributeLikeMacro))
+ TT_StatementAttributeLikeMacro, TT_FunctionLikeOrFreestandingMacro,
+ TT_RecordLBrace))
CurrentToken->setType(TT_Unknown);
CurrentToken->Role.reset();
CurrentToken->MatchingParen = nullptr;
@@ -1431,15 +1433,16 @@ private:
}
void next() {
- if (CurrentToken) {
- CurrentToken->NestingLevel = Contexts.size() - 1;
- CurrentToken->BindingStrength = Contexts.back().BindingStrength;
- modifyContext(*CurrentToken);
- determineTokenType(*CurrentToken);
- CurrentToken = CurrentToken->Next;
- }
+ if (!CurrentToken)
+ return;
+
+ CurrentToken->NestingLevel = Contexts.size() - 1;
+ CurrentToken->BindingStrength = Contexts.back().BindingStrength;
+ modifyContext(*CurrentToken);
+ determineTokenType(*CurrentToken);
+ CurrentToken = CurrentToken->Next;
- resetTokenMetadata(CurrentToken);
+ resetTokenMetadata();
}
/// A struct to hold information valid in a specific context, e.g.
@@ -1563,9 +1566,9 @@ private:
int ParenLevel = 0;
while (Current) {
if (Current->is(tok::l_paren))
- ParenLevel++;
+ ++ParenLevel;
if (Current->is(tok::r_paren))
- ParenLevel--;
+ --ParenLevel;
if (ParenLevel < 1)
break;
Current = Current->Next;
@@ -1589,9 +1592,9 @@ private:
break;
}
if (TemplateCloser->is(tok::less))
- NestingLevel++;
+ ++NestingLevel;
if (TemplateCloser->is(tok::greater))
- NestingLevel--;
+ --NestingLevel;
if (NestingLevel < 1)
break;
TemplateCloser = TemplateCloser->Next;
@@ -1882,15 +1885,23 @@ private:
FormatToken *LeftOfParens = Tok.MatchingParen->getPreviousNonComment();
if (LeftOfParens) {
- // If there is a closing parenthesis left of the current parentheses,
- // look past it as these might be chained casts.
- if (LeftOfParens->is(tok::r_paren)) {
+ // If there is a closing parenthesis left of the current
+ // parentheses, look past it as these might be chained casts.
+ if (LeftOfParens->is(tok::r_paren) &&
+ LeftOfParens->isNot(TT_CastRParen)) {
if (!LeftOfParens->MatchingParen ||
!LeftOfParens->MatchingParen->Previous)
return false;
LeftOfParens = LeftOfParens->MatchingParen->Previous;
}
+ // The Condition directly below this one will see the operator arguments
+ // as a (void *foo) cast.
+ // void operator delete(void *foo) ATTRIB;
+ if (LeftOfParens->Tok.getIdentifierInfo() && LeftOfParens->Previous &&
+ LeftOfParens->Previous->is(tok::kw_operator))
+ return false;
+
// If there is an identifier (or with a few exceptions a keyword) right
// before the parentheses, this is unlikely to be a cast.
if (LeftOfParens->Tok.getIdentifierInfo() &&
@@ -2343,9 +2354,10 @@ private:
void TokenAnnotator::setCommentLineLevels(
SmallVectorImpl<AnnotatedLine *> &Lines) {
const AnnotatedLine *NextNonCommentLine = nullptr;
- for (AnnotatedLine *AL : llvm::reverse(Lines)) {
+ for (AnnotatedLine *Line : llvm::reverse(Lines)) {
+ assert(Line->First);
bool CommentLine = true;
- for (const FormatToken *Tok = AL->First; Tok; Tok = Tok->Next) {
+ for (const FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {
if (!Tok->is(tok::comment)) {
CommentLine = false;
break;
@@ -2357,20 +2369,21 @@ void TokenAnnotator::setCommentLineLevels(
if (NextNonCommentLine && CommentLine &&
NextNonCommentLine->First->NewlinesBefore <= 1 &&
NextNonCommentLine->First->OriginalColumn ==
- AL->First->OriginalColumn) {
+ Line->First->OriginalColumn) {
// Align comments for preprocessor lines with the # in column 0 if
// preprocessor lines are not indented. Otherwise, align with the next
// line.
- AL->Level = (Style.IndentPPDirectives != FormatStyle::PPDIS_BeforeHash &&
- (NextNonCommentLine->Type == LT_PreprocessorDirective ||
- NextNonCommentLine->Type == LT_ImportStatement))
- ? 0
- : NextNonCommentLine->Level;
+ Line->Level =
+ (Style.IndentPPDirectives != FormatStyle::PPDIS_BeforeHash &&
+ (NextNonCommentLine->Type == LT_PreprocessorDirective ||
+ NextNonCommentLine->Type == LT_ImportStatement))
+ ? 0
+ : NextNonCommentLine->Level;
} else {
- NextNonCommentLine = AL->First->isNot(tok::r_brace) ? AL : nullptr;
+ NextNonCommentLine = Line->First->isNot(tok::r_brace) ? Line : nullptr;
}
- setCommentLineLevels(AL->Children);
+ setCommentLineLevels(Line->Children);
}
}
@@ -2549,11 +2562,8 @@ bool TokenAnnotator::mustBreakForReturnType(const AnnotatedLine &Line) const {
}
void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
- for (SmallVectorImpl<AnnotatedLine *>::iterator I = Line.Children.begin(),
- E = Line.Children.end();
- I != E; ++I) {
- calculateFormattingInformation(**I);
- }
+ for (AnnotatedLine *ChildLine : Line.Children)
+ calculateFormattingInformation(*ChildLine);
Line.First->TotalLength =
Line.First->IsMultiline ? Style.ColumnLimit
@@ -2569,9 +2579,9 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
while (Current) {
if (isFunctionDeclarationName(Style.isCpp(), *Current, Line))
Current->setType(TT_FunctionDeclarationName);
+ const FormatToken *Prev = Current->Previous;
if (Current->is(TT_LineComment)) {
- if (Current->Previous->is(BK_BracedInit) &&
- Current->Previous->opensScope())
+ if (Prev->is(BK_BracedInit) && Prev->opensScope())
Current->SpacesRequiredBefore =
(Style.Cpp11BracedListStyle && !Style.SpacesInParentheses) ? 0 : 1;
else
@@ -2612,12 +2622,11 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
Current->CanBreakBefore =
Current->MustBreakBefore || canBreakBefore(Line, *Current);
unsigned ChildSize = 0;
- if (Current->Previous->Children.size() == 1) {
- FormatToken &LastOfChild = *Current->Previous->Children[0]->Last;
+ if (Prev->Children.size() == 1) {
+ FormatToken &LastOfChild = *Prev->Children[0]->Last;
ChildSize = LastOfChild.isTrailingComment() ? Style.ColumnLimit
: LastOfChild.TotalLength + 1;
}
- const FormatToken *Prev = Current->Previous;
if (Current->MustBreakBefore || Prev->Children.size() > 1 ||
(Prev->Children.size() == 1 &&
Prev->Children[0]->First->MustBreakBefore) ||
@@ -2857,6 +2866,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
Left.Previous->isOneOf(tok::identifier, tok::greater))
return 500;
+ if (Left.is(tok::l_paren) && Style.PenaltyBreakOpenParenthesis != 0)
+ return Style.PenaltyBreakOpenParenthesis;
if (Left.is(tok::l_paren) && InFunctionDecl &&
Style.AlignAfterOpenBracket != FormatStyle::BAS_DontAlign)
return 100;
@@ -2921,9 +2932,15 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
}
bool TokenAnnotator::spaceRequiredBeforeParens(const FormatToken &Right) const {
- return Style.SpaceBeforeParens == FormatStyle::SBPO_Always ||
- (Style.SpaceBeforeParensOptions.BeforeNonEmptyParentheses &&
- Right.ParameterCount > 0);
+ if (Style.SpaceBeforeParens == FormatStyle::SBPO_Always)
+ return true;
+ if (Right.is(TT_OverloadedOperatorLParen) &&
+ Style.SpaceBeforeParensOptions.AfterOverloadedOperator)
+ return true;
+ if (Style.SpaceBeforeParensOptions.BeforeNonEmptyParentheses &&
+ Right.ParameterCount > 0)
+ return true;
+ return false;
}
bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
@@ -3290,9 +3307,11 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
const FormatToken &Right) {
const FormatToken &Left = *Right.Previous;
- auto HasExistingWhitespace = [&Right]() {
- return Right.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd();
- };
+
+ // If the token is finalized don't touch it (as it could be in a
+ // clang-format-off section).
+ if (Left.Finalized)
+ return Right.hasWhitespaceBefore();
if (Right.Tok.getIdentifierInfo() && Left.Tok.getIdentifierInfo())
return true; // Never ever merge two identifiers.
@@ -3307,7 +3326,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
// or import .....;
if (Left.is(Keywords.kw_import) && Right.isOneOf(tok::less, tok::ellipsis))
return true;
- // No space between module :.
+ // Space between `module :` and `import :`.
if (Left.isOneOf(Keywords.kw_module, Keywords.kw_import) &&
Right.is(TT_ModulePartitionColon))
return true;
@@ -3321,12 +3340,18 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
if (Left.is(tok::ellipsis) && Right.is(tok::identifier) &&
Line.First->is(Keywords.kw_import))
return false;
+ // Space in __attribute__((attr)) ::type.
+ if (Left.is(TT_AttributeParen) && Right.is(tok::coloncolon))
+ return true;
if (Left.is(tok::kw_operator))
return Right.is(tok::coloncolon);
if (Right.is(tok::l_brace) && Right.is(BK_BracedInit) &&
!Left.opensScope() && Style.SpaceBeforeCpp11BracedList)
return true;
+ if (Left.is(tok::less) && Left.is(TT_OverloadedOperator) &&
+ Right.is(TT_TemplateOpener))
+ return true;
} else if (Style.Language == FormatStyle::LK_Proto ||
Style.Language == FormatStyle::LK_TextProto) {
if (Right.is(tok::period) &&
@@ -3351,7 +3376,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
// Preserve the existence of a space before a percent for cases like 0x%04x
// and "%d %d"
if (Left.is(tok::numeric_constant) && Right.is(tok::percent))
- return HasExistingWhitespace();
+ return Right.hasWhitespaceBefore();
} else if (Style.isJson()) {
if (Right.is(tok::colon))
return false;
@@ -3532,7 +3557,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
return true;
}
if (Left.is(TT_ImplicitStringLiteral))
- return HasExistingWhitespace();
+ return Right.hasWhitespaceBefore();
if (Line.Type == LT_ObjCMethodDecl) {
if (Left.is(TT_ObjCMethodSpecifier))
return true;
@@ -3617,11 +3642,11 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
return Style.SpaceAfterCStyleCast ||
Right.isOneOf(TT_BinaryOperator, TT_SelectorName);
- auto ShouldAddSpacesInAngles = [this, &HasExistingWhitespace]() {
+ auto ShouldAddSpacesInAngles = [this, &Right]() {
if (this->Style.SpacesInAngles == FormatStyle::SIAS_Always)
return true;
if (this->Style.SpacesInAngles == FormatStyle::SIAS_Leave)
- return HasExistingWhitespace();
+ return Right.hasWhitespaceBefore();
return false;
};
@@ -3647,7 +3672,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
// Generally don't remove existing spaces between an identifier and "::".
// 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 HasExistingWhitespace();
+ return Right.hasWhitespaceBefore();
if (Right.is(tok::coloncolon) &&
!Left.isOneOf(tok::l_brace, tok::comment, tok::l_paren))
// Put a space between < and :: in vector< ::std::string >
@@ -3856,16 +3881,14 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
(Right.NewlinesBefore > 0 && Right.HasUnescapedNewline);
if (Left.isTrailingComment())
return true;
- if (Right.Previous->IsUnterminatedLiteral)
+ if (Left.IsUnterminatedLiteral)
return true;
- if (Right.is(tok::lessless) && Right.Next &&
- Right.Previous->is(tok::string_literal) &&
+ if (Right.is(tok::lessless) && Right.Next && Left.is(tok::string_literal) &&
Right.Next->is(tok::string_literal))
return true;
// Can break after template<> declaration
- if (Right.Previous->ClosesTemplateDeclaration &&
- Right.Previous->MatchingParen &&
- Right.Previous->MatchingParen->NestingLevel == 0) {
+ if (Left.ClosesTemplateDeclaration && Left.MatchingParen &&
+ Left.MatchingParen->NestingLevel == 0) {
// Put concepts on the next line e.g.
// template<typename T>
// concept ...
@@ -3898,9 +3921,8 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
// has made a deliberate choice and might have aligned the contents of the
// string literal accordingly. Thus, we try keep existing line breaks.
return Right.IsMultiline && Right.NewlinesBefore > 0;
- if ((Right.Previous->is(tok::l_brace) ||
- (Right.Previous->is(tok::less) && Right.Previous->Previous &&
- Right.Previous->Previous->is(tok::equal))) &&
+ if ((Left.is(tok::l_brace) || (Left.is(tok::less) && Left.Previous &&
+ Left.Previous->is(tok::equal))) &&
Right.NestingLevel == 1 && Style.Language == FormatStyle::LK_Proto) {
// Don't put enums or option definitions onto single lines in protocol
// buffers.
@@ -4004,7 +4026,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
Right.is(TT_SelectorName) && !Right.is(tok::r_square) && Right.Next) {
// Keep `@submessage` together in:
// @submessage { key: value }
- if (Right.Previous && Right.Previous->is(tok::at))
+ if (Left.is(tok::at))
return false;
// Look for the scope opener after selector in cases like:
// selector { ...
@@ -4300,7 +4322,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
if (Right.is(TT_ImplicitStringLiteral))
return false;
- if (Right.is(tok::r_paren) || Right.is(TT_TemplateCloser))
+ if (Right.is(TT_TemplateCloser))
return false;
if (Right.is(tok::r_square) && Right.MatchingParen &&
Right.MatchingParen->is(TT_LambdaLSquare))
@@ -4311,6 +4333,18 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
if (Right.is(tok::r_brace))
return Right.MatchingParen && Right.MatchingParen->is(BK_Block);
+ // We only break before r_paren if we're in a block indented context.
+ if (Right.is(tok::r_paren)) {
+ if (Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent) {
+ return Right.MatchingParen &&
+ !(Right.MatchingParen->Previous &&
+ (Right.MatchingParen->Previous->is(tok::kw_for) ||
+ Right.MatchingParen->Previous->isIf()));
+ }
+
+ return false;
+ }
+
// Allow breaking after a trailing annotation, e.g. after a method
// declaration.
if (Left.is(TT_TrailingAnnotation))
diff --git a/clang/lib/Format/TokenAnnotator.h b/clang/lib/Format/TokenAnnotator.h
index 6e5e62cd4d82..ecd9dbb0f864 100644
--- a/clang/lib/Format/TokenAnnotator.h
+++ b/clang/lib/Format/TokenAnnotator.h
@@ -19,8 +19,6 @@
#include "clang/Format/Format.h"
namespace clang {
-class SourceManager;
-
namespace format {
enum LineType {
@@ -53,10 +51,9 @@ public:
// left them in a different state.
First->Previous = nullptr;
FormatToken *Current = First;
- for (auto I = ++Line.Tokens.begin(), E = Line.Tokens.end(); I != E; ++I) {
- const UnwrappedLineNode &Node = *I;
- Current->Next = I->Tok;
- I->Tok->Previous = Current;
+ for (const UnwrappedLineNode &Node : llvm::drop_begin(Line.Tokens)) {
+ Current->Next = Node.Tok;
+ Node.Tok->Previous = Current;
Current = Current->Next;
Current->Children.clear();
for (const auto &Child : Node.Children) {
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp
index f652a4e7088f..0172a224335c 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -262,14 +262,48 @@ private:
}
}
- // FIXME: TheLine->Level != 0 might or might not be the right check to do.
- // If necessary, change to something smarter.
- bool MergeShortFunctions =
- Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_All ||
- (Style.AllowShortFunctionsOnASingleLine >= FormatStyle::SFS_Empty &&
- I[1]->First->is(tok::r_brace)) ||
- (Style.AllowShortFunctionsOnASingleLine & FormatStyle::SFS_InlineOnly &&
- TheLine->Level != 0);
+ auto ShouldMergeShortFunctions =
+ [this, B = AnnotatedLines.begin()](
+ SmallVectorImpl<AnnotatedLine *>::const_iterator I) {
+ if (Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_All)
+ return true;
+ if (Style.AllowShortFunctionsOnASingleLine >=
+ FormatStyle::SFS_Empty &&
+ I[1]->First->is(tok::r_brace))
+ return true;
+
+ if (Style.AllowShortFunctionsOnASingleLine &
+ FormatStyle::SFS_InlineOnly) {
+ // Just checking TheLine->Level != 0 is not enough, because it
+ // provokes treating functions inside indented namespaces as short.
+ if (Style.isJavaScript() && (*I)->Last->is(TT_FunctionLBrace))
+ return true;
+
+ if ((*I)->Level != 0) {
+ if (I == B)
+ return false;
+
+ // TODO: Use IndentTracker to avoid loop?
+ // Find the last line with lower level.
+ auto J = I - 1;
+ for (; J != B; --J)
+ if ((*J)->Level < (*I)->Level)
+ break;
+
+ // Check if the found line starts a record.
+ for (const FormatToken *RecordTok = (*J)->Last; RecordTok;
+ RecordTok = RecordTok->Previous)
+ if (RecordTok->is(tok::l_brace))
+ return RecordTok->is(TT_RecordLBrace);
+
+ return false;
+ }
+ }
+
+ return false;
+ };
+
+ bool MergeShortFunctions = ShouldMergeShortFunctions(I);
if (Style.CompactNamespaces) {
if (auto nsToken = TheLine->First->getNamespaceToken()) {
@@ -313,7 +347,8 @@ private:
}
// Try to merge a control statement block with left brace unwrapped
if (TheLine->Last->is(tok::l_brace) && TheLine->First != TheLine->Last &&
- TheLine->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for)) {
+ TheLine->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for,
+ TT_ForEachMacro)) {
return Style.AllowShortBlocksOnASingleLine != FormatStyle::SBS_Never
? tryMergeSimpleBlock(I, E, Limit)
: 0;
@@ -336,7 +371,7 @@ private:
: 0;
} else if (I[1]->First->is(tok::l_brace) &&
TheLine->First->isOneOf(tok::kw_if, tok::kw_else, tok::kw_while,
- tok::kw_for)) {
+ tok::kw_for, TT_ForEachMacro)) {
return (Style.BraceWrapping.AfterControlStatement ==
FormatStyle::BWACS_Always)
? tryMergeSimpleBlock(I, E, Limit)
@@ -391,7 +426,7 @@ private:
}
}
- // Try to merge a block with left brace wrapped that wasn't yet covered
+ // Try to merge a block with left brace unwrapped that wasn't yet covered
if (TheLine->Last->is(tok::l_brace)) {
const FormatToken *Tok = TheLine->First;
bool ShouldMerge = false;
@@ -451,7 +486,8 @@ private:
? tryMergeSimpleControlStatement(I, E, Limit)
: 0;
}
- if (TheLine->First->isOneOf(tok::kw_for, tok::kw_while, tok::kw_do)) {
+ if (TheLine->First->isOneOf(tok::kw_for, tok::kw_while, tok::kw_do,
+ TT_ForEachMacro)) {
return Style.AllowShortLoopsOnASingleLine
? tryMergeSimpleControlStatement(I, E, Limit)
: 0;
@@ -499,13 +535,14 @@ private:
if (!Line.First->is(tok::kw_do) && !Line.First->is(tok::kw_else) &&
!Line.Last->is(tok::kw_else) && Line.Last->isNot(tok::r_paren))
return 0;
- // Only merge do while if do is the only statement on the line.
+ // Only merge `do while` if `do` is the only statement on the line.
if (Line.First->is(tok::kw_do) && !Line.Last->is(tok::kw_do))
return 0;
if (1 + I[1]->Last->TotalLength > Limit)
return 0;
+ // Don't merge with loops, ifs, a single semicolon or a line comment.
if (I[1]->First->isOneOf(tok::semi, tok::kw_if, tok::kw_for, tok::kw_while,
- TT_LineComment))
+ TT_ForEachMacro, TT_LineComment))
return 0;
// Only inline simple if's (no nested if or else), unless specified
if (Style.AllowShortIfStatementsOnASingleLine ==
@@ -593,8 +630,8 @@ private:
}
if (Line.First->isOneOf(tok::kw_if, tok::kw_else, tok::kw_while, tok::kw_do,
tok::kw_try, tok::kw___try, tok::kw_catch,
- tok::kw___finally, tok::kw_for, tok::r_brace,
- Keywords.kw___except)) {
+ tok::kw___finally, tok::kw_for, TT_ForEachMacro,
+ tok::r_brace, Keywords.kw___except)) {
if (Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never)
return 0;
if (Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Empty &&
@@ -614,12 +651,14 @@ private:
I + 2 != E && !I[2]->First->is(tok::r_brace))
return 0;
if (!Style.AllowShortLoopsOnASingleLine &&
- Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for) &&
+ Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for,
+ TT_ForEachMacro) &&
!Style.BraceWrapping.AfterControlStatement &&
!I[1]->First->is(tok::r_brace))
return 0;
if (!Style.AllowShortLoopsOnASingleLine &&
- Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for) &&
+ Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for,
+ TT_ForEachMacro) &&
Style.BraceWrapping.AfterControlStatement ==
FormatStyle::BWACS_Always &&
I + 2 != E && !I[2]->First->is(tok::r_brace))
@@ -1060,9 +1099,9 @@ private:
FormatDecision LastFormat = Node->State.NextToken->getDecision();
if (LastFormat == FD_Unformatted || LastFormat == FD_Continue)
- addNextStateToQueue(Penalty, Node, /*NewLine=*/false, Count, Queue);
+ addNextStateToQueue(Penalty, Node, /*NewLine=*/false, &Count, &Queue);
if (LastFormat == FD_Unformatted || LastFormat == FD_Break)
- addNextStateToQueue(Penalty, Node, /*NewLine=*/true, Count, Queue);
+ addNextStateToQueue(Penalty, Node, /*NewLine=*/true, &Count, &Queue);
}
if (Queue.empty()) {
@@ -1088,7 +1127,7 @@ private:
/// Assume the current state is \p PreviousNode and has been reached with a
/// penalty of \p Penalty. Insert a line break if \p NewLine is \c true.
void addNextStateToQueue(unsigned Penalty, StateNode *PreviousNode,
- bool NewLine, unsigned &Count, QueueType &Queue) {
+ bool NewLine, unsigned *Count, QueueType *Queue) {
if (NewLine && !Indenter->canBreak(PreviousNode->State))
return;
if (!NewLine && Indenter->mustBreak(PreviousNode->State))
@@ -1101,29 +1140,29 @@ private:
Penalty += Indenter->addTokenToState(Node->State, NewLine, true);
- Queue.push(QueueItem(OrderedPenalty(Penalty, Count), Node));
- ++Count;
+ Queue->push(QueueItem(OrderedPenalty(Penalty, *Count), Node));
+ ++(*Count);
}
/// Applies the best formatting by reconstructing the path in the
/// solution space that leads to \c Best.
void reconstructPath(LineState &State, StateNode *Best) {
- std::deque<StateNode *> Path;
+ llvm::SmallVector<StateNode *> Path;
// We do not need a break before the initial token.
while (Best->Previous) {
- Path.push_front(Best);
+ Path.push_back(Best);
Best = Best->Previous;
}
- for (auto I = Path.begin(), E = Path.end(); I != E; ++I) {
+ for (const auto &Node : llvm::reverse(Path)) {
unsigned Penalty = 0;
- formatChildren(State, (*I)->NewLine, /*DryRun=*/false, Penalty);
- Penalty += Indenter->addTokenToState(State, (*I)->NewLine, false);
+ formatChildren(State, Node->NewLine, /*DryRun=*/false, Penalty);
+ Penalty += Indenter->addTokenToState(State, Node->NewLine, false);
LLVM_DEBUG({
- printLineState((*I)->Previous->State);
- if ((*I)->NewLine) {
+ printLineState(Node->Previous->State);
+ if (Node->NewLine) {
llvm::dbgs() << "Penalty for placing "
- << (*I)->Previous->State.NextToken->Tok.getName()
+ << Node->Previous->State.NextToken->Tok.getName()
<< " on a new line: " << Penalty << "\n";
}
});
@@ -1162,7 +1201,9 @@ unsigned UnwrappedLineFormatter::format(
bool FirstLine = true;
for (const AnnotatedLine *Line =
Joiner.getNextMergedLine(DryRun, IndentTracker);
- Line; Line = NextLine, FirstLine = false) {
+ Line; PrevPrevLine = PreviousLine, PreviousLine = Line, Line = NextLine,
+ FirstLine = false) {
+ assert(Line->First);
const AnnotatedLine &TheLine = *Line;
unsigned Indent = IndentTracker.getIndent();
@@ -1190,7 +1231,7 @@ unsigned UnwrappedLineFormatter::format(
if (ShouldFormat && TheLine.Type != LT_Invalid) {
if (!DryRun) {
- bool LastLine = Line->First->is(tok::eof);
+ bool LastLine = TheLine.First->is(tok::eof);
formatFirstToken(TheLine, PreviousLine, PrevPrevLine, Lines, Indent,
LastLine ? LastStartColumn : NextStartColumn + Indent);
}
@@ -1252,8 +1293,6 @@ unsigned UnwrappedLineFormatter::format(
}
if (!DryRun)
markFinalized(TheLine.First);
- PrevPrevLine = PreviousLine;
- PreviousLine = &TheLine;
}
PenaltyCache[CacheKey] = Penalty;
return Penalty;
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index b6e55aab708f..35be2fa3eb62 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -14,6 +14,7 @@
#include "UnwrappedLineParser.h"
#include "FormatToken.h"
+#include "TokenAnnotator.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
@@ -32,7 +33,7 @@ public:
// Returns the next token in the token stream.
virtual FormatToken *getNextToken() = 0;
- // Returns the token precedint the token returned by the last call to
+ // Returns the token preceding the token returned by the last call to
// getNextToken() in the token stream, or nullptr if no such token exists.
virtual FormatToken *getPreviousToken() = 0;
@@ -57,7 +58,7 @@ namespace {
class ScopedDeclarationState {
public:
- ScopedDeclarationState(UnwrappedLine &Line, std::vector<bool> &Stack,
+ ScopedDeclarationState(UnwrappedLine &Line, llvm::BitVector &Stack,
bool MustBeDeclaration)
: Line(Line), Stack(Stack) {
Line.MustBeDeclaration = MustBeDeclaration;
@@ -73,7 +74,7 @@ public:
private:
UnwrappedLine &Line;
- std::vector<bool> &Stack;
+ llvm::BitVector &Stack;
};
static bool isLineComment(const FormatToken &FormatTok) {
@@ -246,8 +247,7 @@ public:
}
FormatToken *getPreviousToken() override {
- assert(Position > 0);
- return Tokens[Position - 1];
+ return Position > 0 ? Tokens[Position - 1] : nullptr;
}
FormatToken *peekNextToken() override {
@@ -316,6 +316,7 @@ void UnwrappedLineParser::reset() {
PreprocessorDirectives.clear();
CurrentLines = &Lines;
DeclarationScopeStack.clear();
+ NestedTooDeep.clear();
PPStack.clear();
Line->FirstStartColumn = FirstStartColumn;
}
@@ -343,11 +344,9 @@ void UnwrappedLineParser::parse() {
pushToken(FormatTok);
addUnwrappedLine();
- for (SmallVectorImpl<UnwrappedLine>::iterator I = Lines.begin(),
- E = Lines.end();
- I != E; ++I) {
- Callback.consumeUnwrappedLine(*I);
- }
+ for (const UnwrappedLine &Line : Lines)
+ Callback.consumeUnwrappedLine(Line);
+
Callback.finishRun();
Lines.clear();
while (!PPLevelBranchIndex.empty() &&
@@ -431,7 +430,47 @@ void UnwrappedLineParser::parseCSharpAttribute() {
} while (!eof());
}
-void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) {
+bool UnwrappedLineParser::precededByCommentOrPPDirective() const {
+ if (!Lines.empty() && Lines.back().InPPDirective)
+ return true;
+
+ const FormatToken *Previous = Tokens->getPreviousToken();
+ return Previous && Previous->is(tok::comment) &&
+ (Previous->IsMultiline || Previous->NewlinesBefore > 0);
+}
+
+bool UnwrappedLineParser::mightFitOnOneLine() const {
+ const auto ColumnLimit = Style.ColumnLimit;
+ if (ColumnLimit == 0)
+ return true;
+
+ if (Lines.empty())
+ return true;
+
+ const auto &PreviousLine = Lines.back();
+ const auto &Tokens = PreviousLine.Tokens;
+ assert(!Tokens.empty());
+ const auto *LastToken = Tokens.back().Tok;
+ assert(LastToken);
+ if (!LastToken->isOneOf(tok::semi, tok::comment))
+ return true;
+
+ AnnotatedLine Line(PreviousLine);
+ assert(Line.Last == LastToken);
+
+ TokenAnnotator Annotator(Style, Keywords);
+ Annotator.annotate(Line);
+ Annotator.calculateFormattingInformation(Line);
+
+ return Line.Level * Style.IndentWidth + LastToken->TotalLength <= ColumnLimit;
+}
+
+// Returns true if a simple block, or false otherwise. (A simple block has a
+// single statement that fits on a single line.)
+bool UnwrappedLineParser::parseLevel(bool HasOpeningBrace, IfStmtKind *IfKind) {
+ const bool IsPrecededByCommentOrPPDirective =
+ !Style.RemoveBracesLLVM || precededByCommentOrPPDirective();
+ unsigned StatementCount = 0;
bool SwitchLabelEncountered = false;
do {
tok::TokenKind kind = FormatTok->Tok.getKind();
@@ -452,11 +491,24 @@ void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) {
if (!FormatTok->is(TT_MacroBlockBegin) && tryToParseBracedList())
continue;
parseBlock();
+ ++StatementCount;
+ assert(StatementCount > 0 && "StatementCount overflow!");
addUnwrappedLine();
break;
case tok::r_brace:
- if (HasOpeningBrace)
- return;
+ if (HasOpeningBrace) {
+ if (!Style.RemoveBracesLLVM)
+ return false;
+ if (FormatTok->isNot(tok::r_brace) || StatementCount != 1 ||
+ IsPrecededByCommentOrPPDirective ||
+ precededByCommentOrPPDirective()) {
+ return false;
+ }
+ const FormatToken *Next = Tokens->peekNextToken();
+ if (Next->is(tok::comment) && Next->NewlinesBefore == 0)
+ return false;
+ return mightFitOnOneLine();
+ }
nextToken();
addUnwrappedLine();
break;
@@ -496,10 +548,13 @@ void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) {
}
LLVM_FALLTHROUGH;
default:
- parseStructuralElement(!HasOpeningBrace);
+ parseStructuralElement(IfKind, !HasOpeningBrace);
+ ++StatementCount;
+ assert(StatementCount > 0 && "StatementCount overflow!");
break;
}
} while (!eof());
+ return false;
}
void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
@@ -655,11 +710,13 @@ size_t UnwrappedLineParser::computePPHash() const {
return h;
}
-void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, unsigned AddLevels,
- bool MunchSemi,
- bool UnindentWhitesmithsBraces) {
+UnwrappedLineParser::IfStmtKind
+UnwrappedLineParser::parseBlock(bool MustBeDeclaration, unsigned AddLevels,
+ bool MunchSemi,
+ bool UnindentWhitesmithsBraces) {
assert(FormatTok->isOneOf(tok::l_brace, TT_MacroBlockBegin) &&
"'{' or macro block token expected");
+ FormatToken *Tok = FormatTok;
const bool MacroBlock = FormatTok->is(TT_MacroBlockBegin);
FormatTok->setBlockKind(BK_Block);
@@ -694,16 +751,28 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, unsigned AddLevels,
MustBeDeclaration);
if (AddLevels > 0u && Style.BreakBeforeBraces != FormatStyle::BS_Whitesmiths)
Line->Level += AddLevels;
- parseLevel(/*HasOpeningBrace=*/true);
+
+ IfStmtKind IfKind = IfStmtKind::NotIf;
+ const bool SimpleBlock = parseLevel(/*HasOpeningBrace=*/true, &IfKind);
if (eof())
- return;
+ return IfKind;
if (MacroBlock ? !FormatTok->is(TT_MacroBlockEnd)
: !FormatTok->is(tok::r_brace)) {
Line->Level = InitialLevel;
FormatTok->setBlockKind(BK_Block);
- return;
+ return IfKind;
+ }
+
+ if (SimpleBlock && Tok->is(tok::l_brace)) {
+ assert(FormatTok->is(tok::r_brace));
+ const FormatToken *Previous = Tokens->getPreviousToken();
+ assert(Previous);
+ if (Previous->isNot(tok::r_brace) || Previous->Optional) {
+ Tok->MatchingParen = FormatTok;
+ FormatTok->MatchingParen = Tok;
+ }
}
size_t PPEndHash = computePPHash();
@@ -734,6 +803,8 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, unsigned AddLevels,
CurrentLines->size() - 1;
}
}
+
+ return IfKind;
}
static bool isGoogScope(const UnwrappedLine &Line) {
@@ -782,6 +853,8 @@ static bool ShouldBreakBeforeBrace(const FormatStyle &Style,
return Style.BraceWrapping.AfterUnion;
if (InitialToken.is(tok::kw_struct))
return Style.BraceWrapping.AfterStruct;
+ if (InitialToken.is(tok::kw_enum))
+ return Style.BraceWrapping.AfterEnum;
return false;
}
@@ -969,8 +1042,7 @@ void UnwrappedLineParser::parsePPDefine() {
nextToken();
if (FormatTok->Tok.getKind() == tok::l_paren &&
- FormatTok->WhitespaceRange.getBegin() ==
- FormatTok->WhitespaceRange.getEnd()) {
+ !FormatTok->hasWhitespaceBefore()) {
parseParens();
}
if (Style.IndentPPDirectives != FormatStyle::PPDIS_None)
@@ -1186,7 +1258,8 @@ void UnwrappedLineParser::readTokenWithJavaScriptASI() {
return addUnwrappedLine();
}
-void UnwrappedLineParser::parseStructuralElement(bool IsTopLevel) {
+void UnwrappedLineParser::parseStructuralElement(IfStmtKind *IfKind,
+ bool IsTopLevel) {
if (Style.Language == FormatStyle::LK_TableGen &&
FormatTok->is(tok::pp_include)) {
nextToken();
@@ -1229,7 +1302,7 @@ void UnwrappedLineParser::parseStructuralElement(bool IsTopLevel) {
if (Style.isJavaScript() && Line->MustBeDeclaration)
// field/method declaration.
break;
- parseIfThenElse();
+ parseIfThenElse(IfKind);
return;
case tok::kw_for:
case tok::kw_while:
@@ -1523,8 +1596,16 @@ void UnwrappedLineParser::parseStructuralElement(bool IsTopLevel) {
// structural element.
// FIXME: Figure out cases where this is not true, and add projections
// for them (the one we know is missing are lambdas).
- if (Style.BraceWrapping.AfterFunction)
+ if (Style.Language == FormatStyle::LK_Java &&
+ Line->Tokens.front().Tok->is(Keywords.kw_synchronized)) {
+ // If necessary, we could set the type to something different than
+ // TT_FunctionLBrace.
+ if (Style.BraceWrapping.AfterControlStatement ==
+ FormatStyle::BWACS_Always)
+ addUnwrappedLine();
+ } else if (Style.BraceWrapping.AfterFunction) {
addUnwrappedLine();
+ }
FormatTok->setType(TT_FunctionLBrace);
parseBlock();
addUnwrappedLine();
@@ -1601,6 +1682,8 @@ void UnwrappedLineParser::parseStructuralElement(bool IsTopLevel) {
// See if the following token should start a new unwrapped line.
StringRef Text = FormatTok->TokenText;
+
+ FormatToken *PreviousToken = FormatTok;
nextToken();
// JS doesn't have macros, and within classes colons indicate fields, not
@@ -1629,6 +1712,7 @@ void UnwrappedLineParser::parseStructuralElement(bool IsTopLevel) {
if (FollowedByNewline && (Text.size() >= 5 || FunctionLike) &&
tokenCanStartNewLine(*FormatTok) && Text == Text.upper()) {
+ PreviousToken->setType(TT_FunctionLikeOrFreestandingMacro);
addUnwrappedLine();
return;
}
@@ -1772,6 +1856,7 @@ bool UnwrappedLineParser::tryToParseLambda() {
return false;
bool SeenArrow = false;
+ bool InTemplateParameterList = false;
while (FormatTok->isNot(tok::l_brace)) {
if (FormatTok->isSimpleTypeSpecifier()) {
@@ -1784,6 +1869,17 @@ bool UnwrappedLineParser::tryToParseLambda() {
case tok::l_paren:
parseParens();
break;
+ case tok::l_square:
+ parseSquare();
+ break;
+ case tok::kw_class:
+ case tok::kw_template:
+ case tok::kw_typename:
+ assert(FormatTok->Previous);
+ if (FormatTok->Previous->is(tok::less))
+ InTemplateParameterList = true;
+ nextToken();
+ break;
case tok::amp:
case tok::star:
case tok::kw_const:
@@ -1793,11 +1889,8 @@ bool UnwrappedLineParser::tryToParseLambda() {
case tok::identifier:
case tok::numeric_constant:
case tok::coloncolon:
- case tok::kw_class:
case tok::kw_mutable:
case tok::kw_noexcept:
- case tok::kw_template:
- case tok::kw_typename:
nextToken();
break;
// Specialization of a template with an integer parameter can contain
@@ -1834,7 +1927,7 @@ bool UnwrappedLineParser::tryToParseLambda() {
case tok::ellipsis:
case tok::kw_true:
case tok::kw_false:
- if (SeenArrow) {
+ if (SeenArrow || InTemplateParameterList) {
nextToken();
break;
}
@@ -2128,7 +2221,39 @@ void UnwrappedLineParser::parseSquare(bool LambdaIntroducer) {
} while (!eof());
}
-void UnwrappedLineParser::parseIfThenElse() {
+void UnwrappedLineParser::keepAncestorBraces() {
+ if (!Style.RemoveBracesLLVM)
+ return;
+
+ const int MaxNestingLevels = 2;
+ const int Size = NestedTooDeep.size();
+ if (Size >= MaxNestingLevels)
+ NestedTooDeep[Size - MaxNestingLevels] = true;
+ NestedTooDeep.push_back(false);
+}
+
+static void markOptionalBraces(FormatToken *LeftBrace) {
+ if (!LeftBrace)
+ return;
+
+ assert(LeftBrace->is(tok::l_brace));
+
+ FormatToken *RightBrace = LeftBrace->MatchingParen;
+ if (!RightBrace) {
+ assert(!LeftBrace->Optional);
+ return;
+ }
+
+ assert(RightBrace->is(tok::r_brace));
+ assert(RightBrace->MatchingParen == LeftBrace);
+ assert(LeftBrace->Optional == RightBrace->Optional);
+
+ LeftBrace->Optional = true;
+ RightBrace->Optional = true;
+}
+
+FormatToken *UnwrappedLineParser::parseIfThenElse(IfStmtKind *IfKind,
+ bool KeepBraces) {
auto HandleAttributes = [this]() {
// Handle AttributeMacro, e.g. `if (x) UNLIKELY`.
if (FormatTok->is(TT_AttributeMacro))
@@ -2145,10 +2270,17 @@ void UnwrappedLineParser::parseIfThenElse() {
if (FormatTok->Tok.is(tok::l_paren))
parseParens();
HandleAttributes();
+
bool NeedsUnwrappedLine = false;
+ keepAncestorBraces();
+
+ FormatToken *IfLeftBrace = nullptr;
+ IfStmtKind IfBlockKind = IfStmtKind::NotIf;
+
if (FormatTok->Tok.is(tok::l_brace)) {
+ IfLeftBrace = FormatTok;
CompoundStatementIndenter Indenter(this, Style, Line->Level);
- parseBlock();
+ IfBlockKind = parseBlock();
if (Style.BraceWrapping.BeforeElse)
addUnwrappedLine();
else
@@ -2159,22 +2291,48 @@ void UnwrappedLineParser::parseIfThenElse() {
parseStructuralElement();
--Line->Level;
}
+
+ bool KeepIfBraces = false;
+ if (Style.RemoveBracesLLVM) {
+ assert(!NestedTooDeep.empty());
+ KeepIfBraces = (IfLeftBrace && !IfLeftBrace->MatchingParen) ||
+ NestedTooDeep.back() || IfBlockKind == IfStmtKind::IfOnly ||
+ IfBlockKind == IfStmtKind::IfElseIf;
+ }
+
+ FormatToken *ElseLeftBrace = nullptr;
+ IfStmtKind Kind = IfStmtKind::IfOnly;
+
if (FormatTok->Tok.is(tok::kw_else)) {
+ if (Style.RemoveBracesLLVM) {
+ NestedTooDeep.back() = false;
+ Kind = IfStmtKind::IfElse;
+ }
nextToken();
HandleAttributes();
if (FormatTok->Tok.is(tok::l_brace)) {
+ ElseLeftBrace = FormatTok;
CompoundStatementIndenter Indenter(this, Style, Line->Level);
- parseBlock();
+ if (parseBlock() == IfStmtKind::IfOnly)
+ Kind = IfStmtKind::IfElseIf;
addUnwrappedLine();
} else if (FormatTok->Tok.is(tok::kw_if)) {
FormatToken *Previous = Tokens->getPreviousToken();
- bool PrecededByComment = Previous && Previous->is(tok::comment);
- if (PrecededByComment) {
+ const bool IsPrecededByComment = Previous && Previous->is(tok::comment);
+ if (IsPrecededByComment) {
addUnwrappedLine();
++Line->Level;
}
- parseIfThenElse();
- if (PrecededByComment)
+ bool TooDeep = true;
+ if (Style.RemoveBracesLLVM) {
+ Kind = IfStmtKind::IfElseIf;
+ TooDeep = NestedTooDeep.pop_back_val();
+ }
+ ElseLeftBrace =
+ parseIfThenElse(/*IfKind=*/nullptr, KeepBraces || KeepIfBraces);
+ if (Style.RemoveBracesLLVM)
+ NestedTooDeep.push_back(TooDeep);
+ if (IsPrecededByComment)
--Line->Level;
} else {
addUnwrappedLine();
@@ -2184,9 +2342,40 @@ void UnwrappedLineParser::parseIfThenElse() {
addUnwrappedLine();
--Line->Level;
}
- } else if (NeedsUnwrappedLine) {
- addUnwrappedLine();
+ } else {
+ if (Style.RemoveBracesLLVM)
+ KeepIfBraces = KeepIfBraces || IfBlockKind == IfStmtKind::IfElse;
+ if (NeedsUnwrappedLine)
+ addUnwrappedLine();
+ }
+
+ if (!Style.RemoveBracesLLVM)
+ return nullptr;
+
+ assert(!NestedTooDeep.empty());
+ const bool KeepElseBraces =
+ (ElseLeftBrace && !ElseLeftBrace->MatchingParen) || NestedTooDeep.back();
+
+ NestedTooDeep.pop_back();
+
+ if (!KeepBraces && !KeepIfBraces && !KeepElseBraces) {
+ markOptionalBraces(IfLeftBrace);
+ markOptionalBraces(ElseLeftBrace);
+ } else if (IfLeftBrace) {
+ FormatToken *IfRightBrace = IfLeftBrace->MatchingParen;
+ if (IfRightBrace) {
+ assert(IfRightBrace->MatchingParen == IfLeftBrace);
+ assert(!IfLeftBrace->Optional);
+ assert(!IfRightBrace->Optional);
+ IfLeftBrace->MatchingParen = nullptr;
+ IfRightBrace->MatchingParen = nullptr;
+ }
}
+
+ if (IfKind)
+ *IfKind = Kind;
+
+ return IfLeftBrace;
}
void UnwrappedLineParser::parseTryCatch() {
@@ -2224,6 +2413,9 @@ void UnwrappedLineParser::parseTryCatch() {
if (Style.Language == FormatStyle::LK_Java && FormatTok->is(tok::l_paren)) {
parseParens();
}
+
+ keepAncestorBraces();
+
if (FormatTok->is(tok::l_brace)) {
CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock();
@@ -2241,7 +2433,7 @@ void UnwrappedLineParser::parseTryCatch() {
parseStructuralElement();
--Line->Level;
}
- while (1) {
+ while (true) {
if (FormatTok->is(tok::at))
nextToken();
if (!(FormatTok->isOneOf(tok::kw_catch, Keywords.kw___except,
@@ -2257,8 +2449,11 @@ void UnwrappedLineParser::parseTryCatch() {
parseParens();
continue;
}
- if (FormatTok->isOneOf(tok::semi, tok::r_brace, tok::eof))
+ if (FormatTok->isOneOf(tok::semi, tok::r_brace, tok::eof)) {
+ if (Style.RemoveBracesLLVM)
+ NestedTooDeep.pop_back();
return;
+ }
nextToken();
}
NeedsUnwrappedLine = false;
@@ -2269,6 +2464,10 @@ void UnwrappedLineParser::parseTryCatch() {
else
NeedsUnwrappedLine = true;
}
+
+ if (Style.RemoveBracesLLVM)
+ NestedTooDeep.pop_back();
+
if (NeedsUnwrappedLine)
addUnwrappedLine();
}
@@ -2283,7 +2482,8 @@ void UnwrappedLineParser::parseNamespace() {
parseParens();
} else {
while (FormatTok->isOneOf(tok::identifier, tok::coloncolon, tok::kw_inline,
- tok::l_square, tok::period)) {
+ tok::l_square, tok::period) ||
+ (Style.isCSharp() && FormatTok->is(tok::kw_union))) {
if (FormatTok->is(tok::l_square))
parseSquare();
else
@@ -2375,9 +2575,18 @@ void UnwrappedLineParser::parseForOrWhileLoop() {
nextToken();
if (FormatTok->Tok.is(tok::l_paren))
parseParens();
+
+ keepAncestorBraces();
+
if (FormatTok->Tok.is(tok::l_brace)) {
+ FormatToken *LeftBrace = FormatTok;
CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock();
+ if (Style.RemoveBracesLLVM) {
+ assert(!NestedTooDeep.empty());
+ if (!NestedTooDeep.back())
+ markOptionalBraces(LeftBrace);
+ }
addUnwrappedLine();
} else {
addUnwrappedLine();
@@ -2385,11 +2594,17 @@ void UnwrappedLineParser::parseForOrWhileLoop() {
parseStructuralElement();
--Line->Level;
}
+
+ if (Style.RemoveBracesLLVM)
+ NestedTooDeep.pop_back();
}
void UnwrappedLineParser::parseDoWhile() {
assert(FormatTok->Tok.is(tok::kw_do) && "'do' expected");
nextToken();
+
+ keepAncestorBraces();
+
if (FormatTok->Tok.is(tok::l_brace)) {
CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock();
@@ -2402,6 +2617,9 @@ void UnwrappedLineParser::parseDoWhile() {
--Line->Level;
}
+ if (Style.RemoveBracesLLVM)
+ NestedTooDeep.pop_back();
+
// FIXME: Add error handling.
if (!FormatTok->Tok.is(tok::kw_while)) {
addUnwrappedLine();
@@ -2438,7 +2656,7 @@ void UnwrappedLineParser::parseLabel(bool LeftAlignLabel) {
addUnwrappedLine();
if (!Style.IndentCaseBlocks &&
Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths) {
- Line->Level++;
+ ++Line->Level;
}
}
parseStructuralElement();
@@ -2471,6 +2689,9 @@ void UnwrappedLineParser::parseSwitch() {
nextToken();
if (FormatTok->Tok.is(tok::l_paren))
parseParens();
+
+ keepAncestorBraces();
+
if (FormatTok->Tok.is(tok::l_brace)) {
CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock();
@@ -2481,6 +2702,9 @@ void UnwrappedLineParser::parseSwitch() {
parseStructuralElement();
--Line->Level;
}
+
+ if (Style.RemoveBracesLLVM)
+ NestedTooDeep.pop_back();
}
void UnwrappedLineParser::parseAccessSpecifier() {
@@ -2597,7 +2821,7 @@ void UnwrappedLineParser::parseRequires() {
if (FormatTok->Previous && FormatTok->Previous->is(tok::greater)) {
addUnwrappedLine();
if (Style.IndentRequires) {
- Line->Level++;
+ ++Line->Level;
}
}
nextToken();
@@ -2606,12 +2830,12 @@ void UnwrappedLineParser::parseRequires() {
}
bool UnwrappedLineParser::parseEnum() {
+ const FormatToken &InitialToken = *FormatTok;
+
// Won't be 'enum' for NS_ENUMs.
if (FormatTok->Tok.is(tok::kw_enum))
nextToken();
- const FormatToken &InitialToken = *FormatTok;
-
// In TypeScript, "enum" can also be used as property name, e.g. in interface
// declarations. An "enum" keyword followed by a colon would be a syntax
// error and thus assume it is just an identifier.
@@ -2645,6 +2869,7 @@ bool UnwrappedLineParser::parseEnum() {
// Just a declaration or something is wrong.
if (FormatTok->isNot(tok::l_brace))
return true;
+ FormatTok->setType(TT_RecordLBrace);
FormatTok->setBlockKind(BK_Block);
if (Style.Language == FormatStyle::LK_Java) {
@@ -2864,6 +3089,15 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
if (!tryToParseBracedList())
break;
}
+ if (FormatTok->is(tok::l_square)) {
+ FormatToken *Previous = FormatTok->Previous;
+ if (!Previous || Previous->isNot(tok::r_paren)) {
+ // Don't try parsing a lambda if we had a closing parenthesis before,
+ // it was probably a pointer to an array: int (*)[].
+ if (!tryToParseLambda())
+ break;
+ }
+ }
if (FormatTok->Tok.is(tok::semi))
return;
if (Style.isCSharp() && FormatTok->is(Keywords.kw_where)) {
@@ -2876,6 +3110,7 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
}
}
if (FormatTok->Tok.is(tok::l_brace)) {
+ FormatTok->setType(TT_RecordLBrace);
if (ParseAsExpr) {
parseChildBlock();
} else {
@@ -3264,10 +3499,7 @@ continuesLineCommentSection(const FormatToken &FormatTok,
void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) {
bool JustComments = Line->Tokens.empty();
- for (SmallVectorImpl<FormatToken *>::const_iterator
- I = CommentsBeforeNextToken.begin(),
- E = CommentsBeforeNextToken.end();
- I != E; ++I) {
+ for (FormatToken *Tok : CommentsBeforeNextToken) {
// Line comments that belong to the same line comment section are put on the
// same line since later we might want to reflow content between them.
// Additional fine-grained breaking of line comment sections is controlled
@@ -3276,11 +3508,11 @@ void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) {
//
// FIXME: Consider putting separate line comment sections as children to the
// unwrapped line instead.
- (*I)->ContinuesLineCommentSection =
- continuesLineCommentSection(**I, *Line, CommentPragmasRegex);
- if (isOnNewLine(**I) && JustComments && !(*I)->ContinuesLineCommentSection)
+ Tok->ContinuesLineCommentSection =
+ continuesLineCommentSection(*Tok, *Line, CommentPragmasRegex);
+ if (isOnNewLine(*Tok) && JustComments && !Tok->ContinuesLineCommentSection)
addUnwrappedLine();
- pushToken(*I);
+ pushToken(Tok);
}
if (NewlineBeforeNext && JustComments)
addUnwrappedLine();
diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h
index 0c79723d50fc..3f64d57c7bff 100644
--- a/clang/lib/Format/UnwrappedLineParser.h
+++ b/clang/lib/Format/UnwrappedLineParser.h
@@ -18,6 +18,7 @@
#include "FormatToken.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Format/Format.h"
+#include "llvm/ADT/BitVector.h"
#include "llvm/Support/Regex.h"
#include <stack>
#include <vector>
@@ -81,12 +82,21 @@ public:
void parse();
private:
+ enum class IfStmtKind {
+ NotIf, // Not an if statement.
+ IfOnly, // An if statement without the else clause.
+ IfElse, // An if statement followed by else but not else if.
+ IfElseIf // An if statement followed by else if.
+ };
+
void reset();
void parseFile();
- void parseLevel(bool HasOpeningBrace);
- void parseBlock(bool MustBeDeclaration = false, unsigned AddLevels = 1u,
- bool MunchSemi = true,
- bool UnindentWhitesmithsBraces = false);
+ bool precededByCommentOrPPDirective() const;
+ bool mightFitOnOneLine() const;
+ bool parseLevel(bool HasOpeningBrace, IfStmtKind *IfKind = nullptr);
+ IfStmtKind parseBlock(bool MustBeDeclaration = false, unsigned AddLevels = 1u,
+ bool MunchSemi = true,
+ bool UnindentWhitesmithsBraces = false);
void parseChildBlock();
void parsePPDirective();
void parsePPDefine();
@@ -96,13 +106,15 @@ private:
void parsePPEndIf();
void parsePPUnknown();
void readTokenWithJavaScriptASI();
- void parseStructuralElement(bool IsTopLevel = false);
+ void parseStructuralElement(IfStmtKind *IfKind = nullptr,
+ bool IsTopLevel = false);
bool tryToParseBracedList();
bool parseBracedList(bool ContinueOnSemicolons = false, bool IsEnum = false,
tok::TokenKind ClosingBraceKind = tok::r_brace);
void parseParens();
void parseSquare(bool LambdaIntroducer = false);
- void parseIfThenElse();
+ void keepAncestorBraces();
+ FormatToken *parseIfThenElse(IfStmtKind *IfKind, bool KeepBraces = false);
void parseTryCatch();
void parseForOrWhileLoop();
void parseDoWhile();
@@ -220,7 +232,7 @@ private:
// We store for each line whether it must be a declaration depending on
// whether we are in a compound statement or not.
- std::vector<bool> DeclarationScopeStack;
+ llvm::BitVector DeclarationScopeStack;
const FormatStyle &Style;
const AdditionalKeywords &Keywords;
@@ -235,6 +247,10 @@ private:
// owned outside of and handed into the UnwrappedLineParser.
ArrayRef<FormatToken *> AllTokens;
+ // Keeps a stack of the states of nested control statements (true if the
+ // statement contains more than some predefined number of nested statements).
+ SmallVector<bool, 8> NestedTooDeep;
+
// Represents preprocessor branch type, so we can find matching
// #if/#else/#endif directives.
enum PPBranchKind {
diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp
index 96a66da0f82b..0d2e507ac587 100644
--- a/clang/lib/Format/WhitespaceManager.cpp
+++ b/clang/lib/Format/WhitespaceManager.cpp
@@ -74,6 +74,12 @@ WhitespaceManager::addReplacement(const tooling::Replacement &Replacement) {
return Replaces.add(Replacement);
}
+bool WhitespaceManager::inputUsesCRLF(StringRef Text, bool DefaultToCRLF) {
+ size_t LF = Text.count('\n');
+ size_t CR = Text.count('\r') * 2;
+ return LF == CR ? DefaultToCRLF : CR > LF;
+}
+
void WhitespaceManager::replaceWhitespaceInToken(
const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars,
StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective,
@@ -304,7 +310,7 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End,
unsigned PreviousNonComment = i - 1;
while (PreviousNonComment > Start &&
Changes[PreviousNonComment].Tok->is(tok::comment))
- PreviousNonComment--;
+ --PreviousNonComment;
if (i != Start && Changes[i].indentAndNestingLevel() >
Changes[PreviousNonComment].indentAndNestingLevel())
ScopeStack.push_back(i);
@@ -362,6 +368,13 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End,
Changes[i].Tok->Previous->is(TT_ConditionalExpr))
return true;
+ // Continued braced list.
+ if (ScopeStart > Start + 1 &&
+ Changes[ScopeStart - 2].Tok->isNot(tok::identifier) &&
+ Changes[ScopeStart - 1].Tok->is(tok::l_brace) &&
+ Changes[i].Tok->isNot(tok::r_brace))
+ return true;
+
return false;
};
@@ -718,6 +731,11 @@ void WhitespaceManager::alignConsecutiveAssignments() {
if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0)
return false;
+ // Do not align operator= overloads.
+ FormatToken *Previous = C.Tok->getPreviousNonComment();
+ if (Previous && Previous->is(tok::kw_operator))
+ return false;
+
return C.Tok->is(tok::equal);
},
Changes, /*StartAt=*/0, Style.AlignConsecutiveAssignments);
@@ -1160,7 +1178,7 @@ WhitespaceManager::CellDescriptions WhitespaceManager::getCells(unsigned Start,
NextNonComment = NextNonComment->getNextNonComment();
auto j = i;
while (Changes[j].Tok != NextNonComment && j < End)
- j++;
+ ++j;
if (j < End && Changes[j].NewlinesBefore == 0 &&
Changes[j].Tok->isNot(tok::r_brace)) {
Changes[j].NewlinesBefore = 1;
diff --git a/clang/lib/Format/WhitespaceManager.h b/clang/lib/Format/WhitespaceManager.h
index 029f4159b748..42f958f68ba6 100644
--- a/clang/lib/Format/WhitespaceManager.h
+++ b/clang/lib/Format/WhitespaceManager.h
@@ -45,6 +45,9 @@ public:
bool useCRLF() const { return UseCRLF; }
+ /// Infers whether the input is using CRLF.
+ static bool inputUsesCRLF(StringRef Text, bool DefaultToCRLF);
+
/// Replaces the whitespace in front of \p Tok. Only call once for
/// each \c AnnotatedToken.
///
@@ -242,7 +245,7 @@ private:
/// as described by \p CellDescs.
void alignArrayInitializersRightJustified(CellDescriptions &&CellDescs);
- /// Align Array Initializers being careful to leftt justify the columns
+ /// Align Array Initializers being careful to left justify the columns
/// as described by \p CellDescs.
void alignArrayInitializersLeftJustified(CellDescriptions &&CellDescs);
diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp
index 52589677ca28..5f587cc1c023 100644
--- a/clang/lib/Frontend/ASTUnit.cpp
+++ b/clang/lib/Frontend/ASTUnit.cpp
@@ -817,7 +817,7 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
AST->Reader = new ASTReader(
PP, *AST->ModuleCache, AST->Ctx.get(), PCHContainerRdr, {},
/*isysroot=*/"",
- /*DisableValidation=*/disableValid, AllowASTWithCompilerErrors);
+ /*DisableValidationKind=*/disableValid, AllowASTWithCompilerErrors);
AST->Reader->setListener(std::make_unique<ASTInfoCollector>(
*AST->PP, AST->Ctx.get(), *AST->HSOpts, *AST->PPOpts, *AST->LangOpts,
@@ -1922,9 +1922,10 @@ namespace {
void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
OverloadCandidate *Candidates,
unsigned NumCandidates,
- SourceLocation OpenParLoc) override {
+ SourceLocation OpenParLoc,
+ bool Braced) override {
Next.ProcessOverloadCandidates(S, CurrentArg, Candidates, NumCandidates,
- OpenParLoc);
+ OpenParLoc, Braced);
}
CodeCompletionAllocator &getAllocator() override {
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index 31e7ea3d243d..2465a7e2453b 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -37,6 +37,7 @@
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/GlobalModuleIndex.h"
#include "clang/Serialization/InMemoryModuleCache.h"
+#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/BuryPointer.h"
#include "llvm/Support/CrashRecoveryContext.h"
@@ -996,6 +997,11 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
// DesiredStackSpace available.
noteBottomOfStack();
+ auto FinishDiagnosticClient = llvm::make_scope_exit([&]() {
+ // Notify the diagnostic client that all files were processed.
+ getDiagnosticClient().finish();
+ });
+
raw_ostream &OS = getVerboseOutputStream();
if (!Act.PrepareToExecute(*this))
@@ -1034,9 +1040,6 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
}
}
- // Notify the diagnostic client that all files were processed.
- getDiagnostics().getClient()->finish();
-
if (getDiagnosticOpts().ShowCarets) {
// We can have multiple diagnostics sharing one diagnostic client.
// Get the total number of warnings/errors from the client.
@@ -1414,7 +1417,7 @@ static bool compileModuleAndReadASTBehindLock(
StringRef Dir = llvm::sys::path::parent_path(ModuleFileName);
llvm::sys::fs::create_directories(Dir);
- while (1) {
+ while (true) {
llvm::LockFileManager Locked(ModuleFileName);
switch (Locked) {
case llvm::LockFileManager::LFS_Error:
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index b71addd84bfd..7f1ce3da7e7e 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -438,7 +438,7 @@ static T extractMaskValue(T KeyPath) {
}(EXTRACTOR(KEYPATH)); \
}
-static const StringRef GetInputKindName(InputKind IK);
+static StringRef GetInputKindName(InputKind IK);
static bool FixupInvocation(CompilerInvocation &Invocation,
DiagnosticsEngine &Diags, const ArgList &Args,
@@ -1814,6 +1814,9 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
}
+ if (Opts.PrepareForLTO && Args.hasArg(OPT_mibt_seal))
+ Opts.IBTSeal = 1;
+
for (auto *A :
Args.filtered(OPT_mlink_bitcode_file, OPT_mlink_builtin_bitcode)) {
CodeGenOptions::BitcodeFileToLink F;
@@ -2405,6 +2408,7 @@ static const auto &getFrontendActionTable() {
{frontend::EmitCodeGenOnly, OPT_emit_codegen_only},
{frontend::EmitCodeGenOnly, OPT_emit_codegen_only},
{frontend::EmitObj, OPT_emit_obj},
+ {frontend::ExtractAPI, OPT_extract_api},
{frontend::FixIt, OPT_fixit_EQ},
{frontend::FixIt, OPT_fixit},
@@ -3291,7 +3295,7 @@ static bool IsInputCompatibleWithStandard(InputKind IK,
}
/// Get language name for given input kind.
-static const StringRef GetInputKindName(InputKind IK) {
+static StringRef GetInputKindName(InputKind IK) {
switch (IK.getLanguage()) {
case Language::C:
return "C";
@@ -4144,6 +4148,7 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {
case frontend::EmitLLVMOnly:
case frontend::EmitCodeGenOnly:
case frontend::EmitObj:
+ case frontend::ExtractAPI:
case frontend::FixIt:
case frontend::GenerateModule:
case frontend::GenerateModuleInterface:
diff --git a/clang/lib/Frontend/ExtractAPIConsumer.cpp b/clang/lib/Frontend/ExtractAPIConsumer.cpp
new file mode 100644
index 000000000000..cdf67f3c327a
--- /dev/null
+++ b/clang/lib/Frontend/ExtractAPIConsumer.cpp
@@ -0,0 +1,32 @@
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+
+using namespace clang;
+
+namespace {
+class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
+public:
+ bool VisitNamedDecl(NamedDecl *Decl) {
+ llvm::outs() << Decl->getName() << "\n";
+ return true;
+ }
+};
+
+class ExtractAPIConsumer : public ASTConsumer {
+public:
+ void HandleTranslationUnit(ASTContext &Context) override {
+ Visitor.TraverseDecl(Context.getTranslationUnitDecl());
+ }
+
+private:
+ ExtractAPIVisitor Visitor;
+};
+} // namespace
+
+std::unique_ptr<ASTConsumer>
+ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
+ return std::make_unique<ExtractAPIConsumer>();
+}
diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp
index fb8132a5e40a..ad2e6039477f 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -8,9 +8,10 @@
#include "clang/Frontend/FrontendActions.h"
#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/Decl.h"
#include "clang/Basic/FileManager.h"
-#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/LangStandard.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/ASTConsumers.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
@@ -23,6 +24,7 @@
#include "clang/Sema/TemplateInstCallback.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/ASTWriter.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
@@ -310,9 +312,8 @@ bool GenerateHeaderModuleAction::BeginSourceFileAction(
auto &HS = CI.getPreprocessor().getHeaderSearchInfo();
SmallVector<Module::Header, 16> Headers;
for (StringRef Name : ModuleHeaders) {
- const DirectoryLookup *CurDir = nullptr;
Optional<FileEntryRef> FE = HS.LookupFile(
- Name, SourceLocation(), /*Angled*/ false, nullptr, CurDir, None,
+ Name, SourceLocation(), /*Angled*/ false, nullptr, nullptr, None,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
if (!FE) {
CI.getDiagnostics().Report(diag::err_module_header_file_not_found)
@@ -481,25 +482,92 @@ private:
Out << "---" << YAML << "\n";
}
+ static void printEntryName(const Sema &TheSema, const Decl *Entity,
+ llvm::raw_string_ostream &OS) {
+ auto *NamedTemplate = cast<NamedDecl>(Entity);
+
+ PrintingPolicy Policy = TheSema.Context.getPrintingPolicy();
+ // FIXME: Also ask for FullyQualifiedNames?
+ Policy.SuppressDefaultTemplateArgs = false;
+ NamedTemplate->getNameForDiagnostic(OS, Policy, true);
+
+ if (!OS.str().empty())
+ return;
+
+ Decl *Ctx = Decl::castFromDeclContext(NamedTemplate->getDeclContext());
+ NamedDecl *NamedCtx = dyn_cast_or_null<NamedDecl>(Ctx);
+
+ if (const auto *Decl = dyn_cast<TagDecl>(NamedTemplate)) {
+ if (const auto *R = dyn_cast<RecordDecl>(Decl)) {
+ if (R->isLambda()) {
+ OS << "lambda at ";
+ Decl->getLocation().print(OS, TheSema.getSourceManager());
+ return;
+ }
+ }
+ OS << "unnamed " << Decl->getKindName();
+ return;
+ }
+
+ if (const auto *Decl = dyn_cast<ParmVarDecl>(NamedTemplate)) {
+ OS << "unnamed function parameter " << Decl->getFunctionScopeIndex()
+ << " ";
+ if (Decl->getFunctionScopeDepth() > 0)
+ OS << "(at depth " << Decl->getFunctionScopeDepth() << ") ";
+ OS << "of ";
+ NamedCtx->getNameForDiagnostic(OS, TheSema.getLangOpts(), true);
+ return;
+ }
+
+ if (const auto *Decl = dyn_cast<TemplateTypeParmDecl>(NamedTemplate)) {
+ if (const Type *Ty = Decl->getTypeForDecl()) {
+ if (const auto *TTPT = dyn_cast_or_null<TemplateTypeParmType>(Ty)) {
+ OS << "unnamed template type parameter " << TTPT->getIndex() << " ";
+ if (TTPT->getDepth() > 0)
+ OS << "(at depth " << TTPT->getDepth() << ") ";
+ OS << "of ";
+ NamedCtx->getNameForDiagnostic(OS, TheSema.getLangOpts(), true);
+ return;
+ }
+ }
+ }
+
+ if (const auto *Decl = dyn_cast<NonTypeTemplateParmDecl>(NamedTemplate)) {
+ OS << "unnamed template non-type parameter " << Decl->getIndex() << " ";
+ if (Decl->getDepth() > 0)
+ OS << "(at depth " << Decl->getDepth() << ") ";
+ OS << "of ";
+ NamedCtx->getNameForDiagnostic(OS, TheSema.getLangOpts(), true);
+ return;
+ }
+
+ if (const auto *Decl = dyn_cast<TemplateTemplateParmDecl>(NamedTemplate)) {
+ OS << "unnamed template template parameter " << Decl->getIndex() << " ";
+ if (Decl->getDepth() > 0)
+ OS << "(at depth " << Decl->getDepth() << ") ";
+ OS << "of ";
+ NamedCtx->getNameForDiagnostic(OS, TheSema.getLangOpts(), true);
+ return;
+ }
+
+ llvm_unreachable("Failed to retrieve a name for this entry!");
+ OS << "unnamed identifier";
+ }
+
template <bool BeginInstantiation>
static TemplightEntry getTemplightEntry(const Sema &TheSema,
const CodeSynthesisContext &Inst) {
TemplightEntry Entry;
Entry.Kind = toString(Inst.Kind);
Entry.Event = BeginInstantiation ? "Begin" : "End";
- if (auto *NamedTemplate = dyn_cast_or_null<NamedDecl>(Inst.Entity)) {
- llvm::raw_string_ostream OS(Entry.Name);
- PrintingPolicy Policy = TheSema.Context.getPrintingPolicy();
- // FIXME: Also ask for FullyQualifiedNames?
- Policy.SuppressDefaultTemplateArgs = false;
- NamedTemplate->getNameForDiagnostic(OS, Policy, true);
- const PresumedLoc DefLoc =
+ llvm::raw_string_ostream OS(Entry.Name);
+ printEntryName(TheSema, Inst.Entity, OS);
+ const PresumedLoc DefLoc =
TheSema.getSourceManager().getPresumedLoc(Inst.Entity->getLocation());
- if(!DefLoc.isInvalid())
- Entry.DefinitionLocation = std::string(DefLoc.getFilename()) + ":" +
- std::to_string(DefLoc.getLine()) + ":" +
- std::to_string(DefLoc.getColumn());
- }
+ if (!DefLoc.isInvalid())
+ Entry.DefinitionLocation = std::string(DefLoc.getFilename()) + ":" +
+ std::to_string(DefLoc.getLine()) + ":" +
+ std::to_string(DefLoc.getColumn());
const PresumedLoc PoiLoc =
TheSema.getSourceManager().getPresumedLoc(Inst.PointOfInstantiation);
if (!PoiLoc.isInvalid()) {
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index 629f99110661..a9023a7a1171 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -194,7 +194,7 @@ static void DefineType(const Twine &MacroName, TargetInfo::IntType Ty,
Builder.defineMacro(MacroName, TargetInfo::getTypeName(Ty));
}
-static void DefineTypeWidth(StringRef MacroName, TargetInfo::IntType Ty,
+static void DefineTypeWidth(const Twine &MacroName, TargetInfo::IntType Ty,
const TargetInfo &TI, MacroBuilder &Builder) {
Builder.defineMacro(MacroName, Twine(TI.getTypeWidth(Ty)));
}
@@ -205,6 +205,16 @@ static void DefineTypeSizeof(StringRef MacroName, unsigned BitWidth,
Twine(BitWidth / TI.getCharWidth()));
}
+// This will generate a macro based on the prefix with `_MAX__` as the suffix
+// for the max value representable for the type, and a macro with a `_WIDTH__`
+// suffix for the width of the type.
+static void DefineTypeSizeAndWidth(const Twine &Prefix, TargetInfo::IntType Ty,
+ const TargetInfo &TI,
+ MacroBuilder &Builder) {
+ DefineTypeSize(Prefix + "_MAX__", Ty, TI, Builder);
+ DefineTypeWidth(Prefix + "_WIDTH__", Ty, TI, Builder);
+}
+
static void DefineExactWidthIntType(TargetInfo::IntType Ty,
const TargetInfo &TI,
MacroBuilder &Builder) {
@@ -241,6 +251,8 @@ static void DefineExactWidthIntTypeSize(TargetInfo::IntType Ty,
if (TypeWidth == 64)
Ty = IsSigned ? TI.getInt64Type() : TI.getUInt64Type();
+ // We don't need to define a _WIDTH macro for the exact-width types because
+ // we already know the width.
const char *Prefix = IsSigned ? "__INT" : "__UINT";
DefineTypeSize(Prefix + Twine(TypeWidth) + "_MAX__", Ty, TI, Builder);
}
@@ -254,7 +266,12 @@ static void DefineLeastWidthIntType(unsigned TypeWidth, bool IsSigned,
const char *Prefix = IsSigned ? "__INT_LEAST" : "__UINT_LEAST";
DefineType(Prefix + Twine(TypeWidth) + "_TYPE__", Ty, Builder);
- DefineTypeSize(Prefix + Twine(TypeWidth) + "_MAX__", Ty, TI, Builder);
+ // We only want the *_WIDTH macro for the signed types to avoid too many
+ // predefined macros (the unsigned width and the signed width are identical.)
+ if (IsSigned)
+ DefineTypeSizeAndWidth(Prefix + Twine(TypeWidth), Ty, TI, Builder);
+ else
+ DefineTypeSize(Prefix + Twine(TypeWidth) + "_MAX__", Ty, TI, Builder);
DefineFmt(Prefix + Twine(TypeWidth), Ty, TI, Builder);
}
@@ -268,8 +285,12 @@ static void DefineFastIntType(unsigned TypeWidth, bool IsSigned,
const char *Prefix = IsSigned ? "__INT_FAST" : "__UINT_FAST";
DefineType(Prefix + Twine(TypeWidth) + "_TYPE__", Ty, Builder);
- DefineTypeSize(Prefix + Twine(TypeWidth) + "_MAX__", Ty, TI, Builder);
-
+ // We only want the *_WIDTH macro for the signed types to avoid too many
+ // predefined macros (the unsigned width and the signed width are identical.)
+ if (IsSigned)
+ DefineTypeSizeAndWidth(Prefix + Twine(TypeWidth), Ty, TI, Builder);
+ else
+ DefineTypeSize(Prefix + Twine(TypeWidth) + "_MAX__", Ty, TI, Builder);
DefineFmt(Prefix + Twine(TypeWidth), Ty, TI, Builder);
}
@@ -887,20 +908,26 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
assert(TI.getCharWidth() == 8 && "Only support 8-bit char so far");
Builder.defineMacro("__CHAR_BIT__", Twine(TI.getCharWidth()));
+ Builder.defineMacro("__BOOL_WIDTH__", Twine(TI.getBoolWidth()));
+ Builder.defineMacro("__SHRT_WIDTH__", Twine(TI.getShortWidth()));
+ Builder.defineMacro("__INT_WIDTH__", Twine(TI.getIntWidth()));
+ Builder.defineMacro("__LONG_WIDTH__", Twine(TI.getLongWidth()));
+ Builder.defineMacro("__LLONG_WIDTH__", Twine(TI.getLongLongWidth()));
+
DefineTypeSize("__SCHAR_MAX__", TargetInfo::SignedChar, TI, Builder);
DefineTypeSize("__SHRT_MAX__", TargetInfo::SignedShort, TI, Builder);
DefineTypeSize("__INT_MAX__", TargetInfo::SignedInt, TI, Builder);
DefineTypeSize("__LONG_MAX__", TargetInfo::SignedLong, TI, Builder);
DefineTypeSize("__LONG_LONG_MAX__", TargetInfo::SignedLongLong, TI, Builder);
- DefineTypeSize("__WCHAR_MAX__", TI.getWCharType(), TI, Builder);
- DefineTypeSize("__WINT_MAX__", TI.getWIntType(), TI, Builder);
- DefineTypeSize("__INTMAX_MAX__", TI.getIntMaxType(), TI, Builder);
- DefineTypeSize("__SIZE_MAX__", TI.getSizeType(), TI, Builder);
+ DefineTypeSizeAndWidth("__WCHAR", TI.getWCharType(), TI, Builder);
+ DefineTypeSizeAndWidth("__WINT", TI.getWIntType(), TI, Builder);
+ DefineTypeSizeAndWidth("__INTMAX", TI.getIntMaxType(), TI, Builder);
+ DefineTypeSizeAndWidth("__SIZE", TI.getSizeType(), TI, Builder);
- DefineTypeSize("__UINTMAX_MAX__", TI.getUIntMaxType(), TI, Builder);
- DefineTypeSize("__PTRDIFF_MAX__", TI.getPtrDiffType(0), TI, Builder);
- DefineTypeSize("__INTPTR_MAX__", TI.getIntPtrType(), TI, Builder);
- DefineTypeSize("__UINTPTR_MAX__", TI.getUIntPtrType(), TI, Builder);
+ DefineTypeSizeAndWidth("__UINTMAX", TI.getUIntMaxType(), TI, Builder);
+ DefineTypeSizeAndWidth("__PTRDIFF", TI.getPtrDiffType(0), TI, Builder);
+ DefineTypeSizeAndWidth("__INTPTR", TI.getIntPtrType(), TI, Builder);
+ DefineTypeSizeAndWidth("__UINTPTR", TI.getUIntPtrType(), TI, Builder);
DefineTypeSizeof("__SIZEOF_DOUBLE__", TI.getDoubleWidth(), TI, Builder);
DefineTypeSizeof("__SIZEOF_FLOAT__", TI.getFloatWidth(), TI, Builder);
@@ -929,29 +956,29 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
DefineFmt("__UINTMAX", TI.getUIntMaxType(), TI, Builder);
Builder.defineMacro("__UINTMAX_C_SUFFIX__",
TI.getTypeConstantSuffix(TI.getUIntMaxType()));
- DefineTypeWidth("__INTMAX_WIDTH__", TI.getIntMaxType(), TI, Builder);
DefineType("__PTRDIFF_TYPE__", TI.getPtrDiffType(0), Builder);
DefineFmt("__PTRDIFF", TI.getPtrDiffType(0), TI, Builder);
- DefineTypeWidth("__PTRDIFF_WIDTH__", TI.getPtrDiffType(0), TI, Builder);
DefineType("__INTPTR_TYPE__", TI.getIntPtrType(), Builder);
DefineFmt("__INTPTR", TI.getIntPtrType(), TI, Builder);
- DefineTypeWidth("__INTPTR_WIDTH__", TI.getIntPtrType(), TI, Builder);
DefineType("__SIZE_TYPE__", TI.getSizeType(), Builder);
DefineFmt("__SIZE", TI.getSizeType(), TI, Builder);
- DefineTypeWidth("__SIZE_WIDTH__", TI.getSizeType(), TI, Builder);
DefineType("__WCHAR_TYPE__", TI.getWCharType(), Builder);
- DefineTypeWidth("__WCHAR_WIDTH__", TI.getWCharType(), TI, Builder);
DefineType("__WINT_TYPE__", TI.getWIntType(), Builder);
- DefineTypeWidth("__WINT_WIDTH__", TI.getWIntType(), TI, Builder);
- DefineTypeWidth("__SIG_ATOMIC_WIDTH__", TI.getSigAtomicType(), TI, Builder);
- DefineTypeSize("__SIG_ATOMIC_MAX__", TI.getSigAtomicType(), TI, Builder);
+ DefineTypeSizeAndWidth("__SIG_ATOMIC", TI.getSigAtomicType(), TI, Builder);
DefineType("__CHAR16_TYPE__", TI.getChar16Type(), Builder);
DefineType("__CHAR32_TYPE__", TI.getChar32Type(), Builder);
- DefineTypeWidth("__UINTMAX_WIDTH__", TI.getUIntMaxType(), TI, Builder);
DefineType("__UINTPTR_TYPE__", TI.getUIntPtrType(), Builder);
DefineFmt("__UINTPTR", TI.getUIntPtrType(), TI, Builder);
- DefineTypeWidth("__UINTPTR_WIDTH__", TI.getUIntPtrType(), TI, Builder);
+
+ // The C standard requires the width of uintptr_t and intptr_t to be the same,
+ // per 7.20.2.4p1. Same for intmax_t and uintmax_t, per 7.20.2.5p1.
+ assert(TI.getTypeWidth(TI.getUIntPtrType()) ==
+ TI.getTypeWidth(TI.getIntPtrType()) &&
+ "uintptr_t and intptr_t have different widths?");
+ assert(TI.getTypeWidth(TI.getUIntMaxType()) ==
+ TI.getTypeWidth(TI.getIntMaxType()) &&
+ "uintmax_t and intmax_t have different widths?");
if (TI.hasFloat16Type())
DefineFloatMacros(Builder, "FLT16", &TI.getHalfFormat(), "F16");
@@ -1039,6 +1066,9 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("__USER_LABEL_PREFIX__", TI.getUserLabelPrefix());
+ if (!LangOpts.MathErrno)
+ Builder.defineMacro("__NO_MATH_ERRNO__");
+
if (LangOpts.FastMath || LangOpts.FiniteMathOnly)
Builder.defineMacro("__FINITE_MATH_ONLY__", "1");
else
diff --git a/clang/lib/Frontend/MultiplexConsumer.cpp b/clang/lib/Frontend/MultiplexConsumer.cpp
index 5abbb3a235b4..34bbc365e647 100644
--- a/clang/lib/Frontend/MultiplexConsumer.cpp
+++ b/clang/lib/Frontend/MultiplexConsumer.cpp
@@ -236,10 +236,10 @@ void MultiplexASTMutationListener::AddedAttributeToRecord(
MultiplexConsumer::MultiplexConsumer(
std::vector<std::unique_ptr<ASTConsumer>> C)
- : Consumers(std::move(C)), MutationListener(), DeserializationListener() {
+ : Consumers(std::move(C)) {
// Collect the mutation listeners and deserialization listeners of all
// children, and create a multiplex listener each if so.
- std::vector<ASTMutationListener*> mutationListeners;
+ std::vector<ASTMutationListener *> mutationListeners;
std::vector<ASTDeserializationListener*> serializationListeners;
for (auto &Consumer : Consumers) {
if (auto *mutationListener = Consumer->GetASTMutationListener())
diff --git a/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/clang/lib/Frontend/PrintPreprocessedOutput.cpp
index 45df86ef91cd..1d0022bda474 100644
--- a/clang/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/clang/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -792,7 +792,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
bool IsStartOfLine = false;
char Buffer[256];
- while (1) {
+ while (true) {
// Two lines joined with line continuation ('\' as last character on the
// line) must be emitted as one line even though Tok.getLine() returns two
// different values. In this situation Tok.isAtStartOfLine() is false even
diff --git a/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp b/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp
index 3f2a78127477..3e8d582f90c2 100644
--- a/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp
+++ b/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp
@@ -14,7 +14,6 @@
#include "clang/Rewrite/Frontend/Rewriters.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
-#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Pragma.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/SmallString.h"
@@ -31,10 +30,8 @@ class InclusionRewriter : public PPCallbacks {
struct IncludedFile {
FileID Id;
SrcMgr::CharacteristicKind FileType;
- const DirectoryLookup *DirLookup;
- IncludedFile(FileID Id, SrcMgr::CharacteristicKind FileType,
- const DirectoryLookup *DirLookup)
- : Id(Id), FileType(FileType), DirLookup(DirLookup) {}
+ IncludedFile(FileID Id, SrcMgr::CharacteristicKind FileType)
+ : Id(Id), FileType(FileType) {}
};
Preprocessor &PP; ///< Used to find inclusion directives.
SourceManager &SM; ///< Used to read and manage source files.
@@ -57,8 +54,7 @@ class InclusionRewriter : public PPCallbacks {
public:
InclusionRewriter(Preprocessor &PP, raw_ostream &OS, bool ShowLineMarkers,
bool UseLineDirectives);
- void Process(FileID FileId, SrcMgr::CharacteristicKind FileType,
- const DirectoryLookup *DirLookup);
+ void Process(FileID FileId, SrcMgr::CharacteristicKind FileType);
void setPredefinesBuffer(const llvm::MemoryBufferRef &Buf) {
PredefinesBuffer = Buf;
}
@@ -162,8 +158,7 @@ void InclusionRewriter::FileChanged(SourceLocation Loc,
return;
FileID Id = FullSourceLoc(Loc, SM).getFileID();
auto P = FileIncludes.insert(
- std::make_pair(LastInclusionLocation,
- IncludedFile(Id, NewFileType, PP.GetCurDirLookup())));
+ std::make_pair(LastInclusionLocation, IncludedFile(Id, NewFileType)));
(void)P;
assert(P.second && "Unexpected revisitation of the same include directive");
LastInclusionLocation = SourceLocation();
@@ -256,28 +251,12 @@ bool InclusionRewriter::IsIfAtLocationTrue(SourceLocation Loc) const {
return false;
}
-/// Detect the likely line ending style of \p FromFile by examining the first
-/// newline found within it.
-static StringRef DetectEOL(const MemoryBufferRef &FromFile) {
- // Detect what line endings the file uses, so that added content does not mix
- // the style. We need to check for "\r\n" first because "\n\r" will match
- // "\r\n\r\n".
- const char *Pos = strchr(FromFile.getBufferStart(), '\n');
- if (!Pos)
- return "\n";
- if (Pos - 1 >= FromFile.getBufferStart() && Pos[-1] == '\r')
- return "\r\n";
- if (Pos + 1 < FromFile.getBufferEnd() && Pos[1] == '\r')
- return "\n\r";
- return "\n";
-}
-
void InclusionRewriter::detectMainFileEOL() {
Optional<MemoryBufferRef> FromFile = *SM.getBufferOrNone(SM.getMainFileID());
assert(FromFile);
if (!FromFile)
return; // Should never happen, but whatever.
- MainEOL = DetectEOL(*FromFile);
+ MainEOL = FromFile->getBuffer().detectEOL();
}
/// Writes out bytes from \p FromFile, starting at \p NextToWrite and ending at
@@ -371,8 +350,7 @@ StringRef InclusionRewriter::NextIdentifierName(Lexer &RawLex,
/// Use a raw lexer to analyze \p FileId, incrementally copying parts of it
/// and including content of included files recursively.
void InclusionRewriter::Process(FileID FileId,
- SrcMgr::CharacteristicKind FileType,
- const DirectoryLookup *DirLookup) {
+ SrcMgr::CharacteristicKind FileType) {
MemoryBufferRef FromFile;
{
auto B = SM.getBufferOrNone(FileId);
@@ -384,7 +362,7 @@ void InclusionRewriter::Process(FileID FileId,
Lexer RawLex(FileId, FromFile, PP.getSourceManager(), PP.getLangOpts());
RawLex.SetCommentRetentionState(false);
- StringRef LocalEOL = DetectEOL(FromFile);
+ StringRef LocalEOL = FromFile.getBuffer().detectEOL();
// Per the GNU docs: "1" indicates entering a new file.
if (FileId == SM.getMainFileID() || FileId == PP.getPredefinesFileID())
@@ -433,7 +411,7 @@ void InclusionRewriter::Process(FileID FileId,
<< Mod->getFullModuleName(true) << "\n";
// Include and recursively process the file.
- Process(Inc->Id, Inc->FileType, Inc->DirLookup);
+ Process(Inc->Id, Inc->FileType);
if (Mod)
OS << "#pragma clang module end /*"
@@ -559,7 +537,7 @@ void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS,
Rewrite->handleModuleBegin(Tok);
} while (Tok.isNot(tok::eof));
Rewrite->setPredefinesBuffer(SM.getBufferOrFake(PP.getPredefinesFileID()));
- Rewrite->Process(PP.getPredefinesFileID(), SrcMgr::C_User, nullptr);
- Rewrite->Process(SM.getMainFileID(), SrcMgr::C_User, nullptr);
+ Rewrite->Process(PP.getPredefinesFileID(), SrcMgr::C_User);
+ Rewrite->Process(SM.getMainFileID(), SrcMgr::C_User);
OS->flush();
}
diff --git a/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp b/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp
index 462aeda6e027..fc8fce4b42b8 100644
--- a/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp
+++ b/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp
@@ -95,8 +95,7 @@ class SDiagsMerger : SerializedDiagnosticReader {
AbbrevLookup DiagFlagLookup;
public:
- SDiagsMerger(SDiagsWriter &Writer)
- : SerializedDiagnosticReader(), Writer(Writer) {}
+ SDiagsMerger(SDiagsWriter &Writer) : Writer(Writer) {}
std::error_code mergeRecordsFromFile(const char *File) {
return readDiagnostics(File);
diff --git a/clang/lib/Frontend/TextDiagnostic.cpp b/clang/lib/Frontend/TextDiagnostic.cpp
index 8df7496c6ddd..1c4a76e68953 100644
--- a/clang/lib/Frontend/TextDiagnostic.cpp
+++ b/clang/lib/Frontend/TextDiagnostic.cpp
@@ -44,7 +44,7 @@ static const enum raw_ostream::Colors savedColor =
/// Add highlights to differences in template strings.
static void applyTemplateHighlighting(raw_ostream &OS, StringRef Str,
bool &Normal, bool Bold) {
- while (1) {
+ while (true) {
size_t Pos = Str.find(ToggleHighlight);
OS << Str.slice(0, Pos);
if (Pos == StringRef::npos)
diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index 2759625ae254..f67dceea9135 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -541,9 +541,8 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
ExpectedLoc = SourceLocation();
} else {
// Lookup file via Preprocessor, like a #include.
- const DirectoryLookup *CurDir;
Optional<FileEntryRef> File =
- PP->LookupFile(Pos, Filename, false, nullptr, nullptr, CurDir,
+ PP->LookupFile(Pos, Filename, false, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr);
if (!File) {
Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 8e18f33af0cb..8a8a13743762 100644
--- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -57,6 +57,8 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
case EmitLLVMOnly: return std::make_unique<EmitLLVMOnlyAction>();
case EmitCodeGenOnly: return std::make_unique<EmitCodeGenOnlyAction>();
case EmitObj: return std::make_unique<EmitObjAction>();
+ case ExtractAPI:
+ return std::make_unique<ExtractAPIAction>();
case FixIt: return std::make_unique<FixItAction>();
case GenerateModule:
return std::make_unique<GenerateModuleFromModuleMapAction>();
diff --git a/clang/lib/Headers/__clang_cuda_math.h b/clang/lib/Headers/__clang_cuda_math.h
index 538556f394da..e447590393ec 100644
--- a/clang/lib/Headers/__clang_cuda_math.h
+++ b/clang/lib/Headers/__clang_cuda_math.h
@@ -345,4 +345,4 @@ __DEVICE__ float ynf(int __a, float __b) { return __nv_ynf(__a, __b); }
#pragma pop_macro("__DEVICE_VOID__")
#pragma pop_macro("__FAST_OR_SLOW")
-#endif // __CLANG_CUDA_DEVICE_FUNCTIONS_H__
+#endif // __CLANG_CUDA_MATH_H__
diff --git a/clang/lib/Headers/__clang_hip_runtime_wrapper.h b/clang/lib/Headers/__clang_hip_runtime_wrapper.h
index 73021d256cba..10cec58ed12f 100644
--- a/clang/lib/Headers/__clang_hip_runtime_wrapper.h
+++ b/clang/lib/Headers/__clang_hip_runtime_wrapper.h
@@ -50,6 +50,9 @@ extern "C" {
#include <cmath>
#include <cstdlib>
#include <stdlib.h>
+#if __has_include("hip/hip_version.h")
+#include "hip/hip_version.h"
+#endif // __has_include("hip/hip_version.h")
#else
typedef __SIZE_TYPE__ size_t;
// Define macros which are needed to declare HIP device API's without standard
@@ -74,25 +77,35 @@ typedef __SIZE_TYPE__ __hip_size_t;
extern "C" {
#endif //__cplusplus
+#if HIP_VERSION_MAJOR * 100 + HIP_VERSION_MINOR >= 405
+extern "C" __device__ unsigned long long __ockl_dm_alloc(unsigned long long __size);
+extern "C" __device__ void __ockl_dm_dealloc(unsigned long long __addr);
+__attribute__((weak)) inline __device__ void *malloc(__hip_size_t __size) {
+ return (void *) __ockl_dm_alloc(__size);
+}
+__attribute__((weak)) inline __device__ void free(void *__ptr) {
+ __ockl_dm_dealloc((unsigned long long)__ptr);
+}
+#else // HIP version check
#if __HIP_ENABLE_DEVICE_MALLOC__
__device__ void *__hip_malloc(__hip_size_t __size);
__device__ void *__hip_free(void *__ptr);
__attribute__((weak)) inline __device__ void *malloc(__hip_size_t __size) {
return __hip_malloc(__size);
}
-__attribute__((weak)) inline __device__ void *free(void *__ptr) {
- return __hip_free(__ptr);
+__attribute__((weak)) inline __device__ void free(void *__ptr) {
+ __hip_free(__ptr);
}
#else
__attribute__((weak)) inline __device__ void *malloc(__hip_size_t __size) {
__builtin_trap();
return (void *)0;
}
-__attribute__((weak)) inline __device__ void *free(void *__ptr) {
+__attribute__((weak)) inline __device__ void free(void *__ptr) {
__builtin_trap();
- return (void *)0;
}
#endif
+#endif // HIP version check
#ifdef __cplusplus
} // extern "C"
diff --git a/clang/lib/Headers/avx2intrin.h b/clang/lib/Headers/avx2intrin.h
index 5064c87c2bb1..e33514a60ff3 100644
--- a/clang/lib/Headers/avx2intrin.h
+++ b/clang/lib/Headers/avx2intrin.h
@@ -26,19 +26,19 @@
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_abs_epi8(__m256i __a)
{
- return (__m256i)__builtin_ia32_pabsb256((__v32qi)__a);
+ return (__m256i)__builtin_elementwise_abs((__v32qs)__a);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_abs_epi16(__m256i __a)
{
- return (__m256i)__builtin_ia32_pabsw256((__v16hi)__a);
+ return (__m256i)__builtin_elementwise_abs((__v16hi)__a);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_abs_epi32(__m256i __a)
{
- return (__m256i)__builtin_ia32_pabsd256((__v8si)__a);
+ return (__m256i)__builtin_elementwise_abs((__v8si)__a);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
@@ -253,73 +253,73 @@ _mm256_madd_epi16(__m256i __a, __m256i __b)
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_max_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmaxsb256((__v32qi)__a, (__v32qi)__b);
+ return (__m256i)__builtin_elementwise_max((__v32qs)__a, (__v32qs)__b);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_max_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmaxsw256((__v16hi)__a, (__v16hi)__b);
+ return (__m256i)__builtin_elementwise_max((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_max_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmaxsd256((__v8si)__a, (__v8si)__b);
+ return (__m256i)__builtin_elementwise_max((__v8si)__a, (__v8si)__b);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_max_epu8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmaxub256((__v32qi)__a, (__v32qi)__b);
+ return (__m256i)__builtin_elementwise_max((__v32qu)__a, (__v32qu)__b);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_max_epu16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmaxuw256((__v16hi)__a, (__v16hi)__b);
+ return (__m256i)__builtin_elementwise_max((__v16hu)__a, (__v16hu)__b);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_max_epu32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmaxud256((__v8si)__a, (__v8si)__b);
+ return (__m256i)__builtin_elementwise_max((__v8su)__a, (__v8su)__b);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_min_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pminsb256((__v32qi)__a, (__v32qi)__b);
+ return (__m256i)__builtin_elementwise_min((__v32qs)__a, (__v32qs)__b);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_min_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pminsw256((__v16hi)__a, (__v16hi)__b);
+ return (__m256i)__builtin_elementwise_min((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_min_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pminsd256((__v8si)__a, (__v8si)__b);
+ return (__m256i)__builtin_elementwise_min((__v8si)__a, (__v8si)__b);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_min_epu8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pminub256((__v32qi)__a, (__v32qi)__b);
+ return (__m256i)__builtin_elementwise_min((__v32qu)__a, (__v32qu)__b);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_min_epu16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pminuw256 ((__v16hi)__a, (__v16hi)__b);
+ return (__m256i)__builtin_elementwise_min((__v16hu)__a, (__v16hu)__b);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_min_epu32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pminud256((__v8si)__a, (__v8si)__b);
+ return (__m256i)__builtin_elementwise_min((__v8su)__a, (__v8su)__b);
}
static __inline__ int __DEFAULT_FN_ATTRS256
diff --git a/clang/lib/Headers/avx512bwintrin.h b/clang/lib/Headers/avx512bwintrin.h
index 6aee8aed8487..522ef100bab1 100644
--- a/clang/lib/Headers/avx512bwintrin.h
+++ b/clang/lib/Headers/avx512bwintrin.h
@@ -485,7 +485,7 @@ _mm512_mask_blend_epi16 (__mmask32 __U, __m512i __A, __m512i __W)
static __inline__ __m512i __DEFAULT_FN_ATTRS512
_mm512_abs_epi8 (__m512i __A)
{
- return (__m512i)__builtin_ia32_pabsb512((__v64qi)__A);
+ return (__m512i)__builtin_elementwise_abs((__v64qs)__A);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS512
@@ -507,7 +507,7 @@ _mm512_maskz_abs_epi8 (__mmask64 __U, __m512i __A)
static __inline__ __m512i __DEFAULT_FN_ATTRS512
_mm512_abs_epi16 (__m512i __A)
{
- return (__m512i)__builtin_ia32_pabsw512((__v32hi)__A);
+ return (__m512i)__builtin_elementwise_abs((__v32hi)__A);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS512
@@ -751,7 +751,7 @@ _mm512_maskz_avg_epu16 (__mmask32 __U, __m512i __A, __m512i __B)
static __inline__ __m512i __DEFAULT_FN_ATTRS512
_mm512_max_epi8 (__m512i __A, __m512i __B)
{
- return (__m512i)__builtin_ia32_pmaxsb512((__v64qi) __A, (__v64qi) __B);
+ return (__m512i)__builtin_elementwise_max((__v64qs) __A, (__v64qs) __B);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS512
@@ -773,7 +773,7 @@ _mm512_mask_max_epi8 (__m512i __W, __mmask64 __M, __m512i __A, __m512i __B)
static __inline__ __m512i __DEFAULT_FN_ATTRS512
_mm512_max_epi16 (__m512i __A, __m512i __B)
{
- return (__m512i)__builtin_ia32_pmaxsw512((__v32hi) __A, (__v32hi) __B);
+ return (__m512i)__builtin_elementwise_max((__v32hi) __A, (__v32hi) __B);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS512
@@ -796,7 +796,7 @@ _mm512_mask_max_epi16 (__m512i __W, __mmask32 __M, __m512i __A,
static __inline__ __m512i __DEFAULT_FN_ATTRS512
_mm512_max_epu8 (__m512i __A, __m512i __B)
{
- return (__m512i)__builtin_ia32_pmaxub512((__v64qi)__A, (__v64qi)__B);
+ return (__m512i)__builtin_elementwise_max((__v64qu)__A, (__v64qu)__B);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS512
@@ -818,7 +818,7 @@ _mm512_mask_max_epu8 (__m512i __W, __mmask64 __M, __m512i __A, __m512i __B)
static __inline__ __m512i __DEFAULT_FN_ATTRS512
_mm512_max_epu16 (__m512i __A, __m512i __B)
{
- return (__m512i)__builtin_ia32_pmaxuw512((__v32hi)__A, (__v32hi)__B);
+ return (__m512i)__builtin_elementwise_max((__v32hu)__A, (__v32hu)__B);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS512
@@ -840,7 +840,7 @@ _mm512_mask_max_epu16 (__m512i __W, __mmask32 __M, __m512i __A, __m512i __B)
static __inline__ __m512i __DEFAULT_FN_ATTRS512
_mm512_min_epi8 (__m512i __A, __m512i __B)
{
- return (__m512i)__builtin_ia32_pminsb512((__v64qi) __A, (__v64qi) __B);
+ return (__m512i)__builtin_elementwise_min((__v64qs) __A, (__v64qs) __B);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS512
@@ -862,7 +862,7 @@ _mm512_mask_min_epi8 (__m512i __W, __mmask64 __M, __m512i __A, __m512i __B)
static __inline__ __m512i __DEFAULT_FN_ATTRS512
_mm512_min_epi16 (__m512i __A, __m512i __B)
{
- return (__m512i)__builtin_ia32_pminsw512((__v32hi) __A, (__v32hi) __B);
+ return (__m512i)__builtin_elementwise_min((__v32hi) __A, (__v32hi) __B);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS512
@@ -884,7 +884,7 @@ _mm512_mask_min_epi16 (__m512i __W, __mmask32 __M, __m512i __A, __m512i __B)
static __inline__ __m512i __DEFAULT_FN_ATTRS512
_mm512_min_epu8 (__m512i __A, __m512i __B)
{
- return (__m512i)__builtin_ia32_pminub512((__v64qi)__A, (__v64qi)__B);
+ return (__m512i)__builtin_elementwise_min((__v64qu)__A, (__v64qu)__B);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS512
@@ -906,7 +906,7 @@ _mm512_mask_min_epu8 (__m512i __W, __mmask64 __M, __m512i __A, __m512i __B)
static __inline__ __m512i __DEFAULT_FN_ATTRS512
_mm512_min_epu16 (__m512i __A, __m512i __B)
{
- return (__m512i)__builtin_ia32_pminuw512((__v32hi)__A, (__v32hi)__B);
+ return (__m512i)__builtin_elementwise_min((__v32hu)__A, (__v32hu)__B);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS512
diff --git a/clang/lib/Headers/avx512fintrin.h b/clang/lib/Headers/avx512fintrin.h
index df298640523b..50e0e287d9fc 100644
--- a/clang/lib/Headers/avx512fintrin.h
+++ b/clang/lib/Headers/avx512fintrin.h
@@ -26,6 +26,10 @@ typedef unsigned short __v32hu __attribute__((__vector_size__(64)));
typedef unsigned long long __v8du __attribute__((__vector_size__(64)));
typedef unsigned int __v16su __attribute__((__vector_size__(64)));
+/* We need an explicitly signed variant for char. Note that this shouldn't
+ * appear in the interface though. */
+typedef signed char __v64qs __attribute__((__vector_size__(64)));
+
typedef float __m512 __attribute__((__vector_size__(64), __aligned__(64)));
typedef double __m512d __attribute__((__vector_size__(64), __aligned__(64)));
typedef long long __m512i __attribute__((__vector_size__(64), __aligned__(64)));
@@ -1086,7 +1090,7 @@ static __inline __m512i
__DEFAULT_FN_ATTRS512
_mm512_max_epi32(__m512i __A, __m512i __B)
{
- return (__m512i)__builtin_ia32_pmaxsd512((__v16si)__A, (__v16si)__B);
+ return (__m512i)__builtin_elementwise_max((__v16si)__A, (__v16si)__B);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS512
@@ -1108,7 +1112,7 @@ _mm512_maskz_max_epi32 (__mmask16 __M, __m512i __A, __m512i __B)
static __inline __m512i __DEFAULT_FN_ATTRS512
_mm512_max_epu32(__m512i __A, __m512i __B)
{
- return (__m512i)__builtin_ia32_pmaxud512((__v16si)__A, (__v16si)__B);
+ return (__m512i)__builtin_elementwise_max((__v16su)__A, (__v16su)__B);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS512
@@ -1130,7 +1134,7 @@ _mm512_maskz_max_epu32 (__mmask16 __M, __m512i __A, __m512i __B)
static __inline __m512i __DEFAULT_FN_ATTRS512
_mm512_max_epi64(__m512i __A, __m512i __B)
{
- return (__m512i)__builtin_ia32_pmaxsq512((__v8di)__A, (__v8di)__B);
+ return (__m512i)__builtin_elementwise_max((__v8di)__A, (__v8di)__B);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS512
@@ -1152,7 +1156,7 @@ _mm512_maskz_max_epi64 (__mmask8 __M, __m512i __A, __m512i __B)
static __inline __m512i __DEFAULT_FN_ATTRS512
_mm512_max_epu64(__m512i __A, __m512i __B)
{
- return (__m512i)__builtin_ia32_pmaxuq512((__v8di)__A, (__v8di)__B);
+ return (__m512i)__builtin_elementwise_max((__v8du)__A, (__v8du)__B);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS512
@@ -1321,7 +1325,7 @@ static __inline __m512i
__DEFAULT_FN_ATTRS512
_mm512_min_epi32(__m512i __A, __m512i __B)
{
- return (__m512i)__builtin_ia32_pminsd512((__v16si)__A, (__v16si)__B);
+ return (__m512i)__builtin_elementwise_min((__v16si)__A, (__v16si)__B);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS512
@@ -1343,7 +1347,7 @@ _mm512_maskz_min_epi32 (__mmask16 __M, __m512i __A, __m512i __B)
static __inline __m512i __DEFAULT_FN_ATTRS512
_mm512_min_epu32(__m512i __A, __m512i __B)
{
- return (__m512i)__builtin_ia32_pminud512((__v16si)__A, (__v16si)__B);
+ return (__m512i)__builtin_elementwise_min((__v16su)__A, (__v16su)__B);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS512
@@ -1365,7 +1369,7 @@ _mm512_maskz_min_epu32 (__mmask16 __M, __m512i __A, __m512i __B)
static __inline __m512i __DEFAULT_FN_ATTRS512
_mm512_min_epi64(__m512i __A, __m512i __B)
{
- return (__m512i)__builtin_ia32_pminsq512((__v8di)__A, (__v8di)__B);
+ return (__m512i)__builtin_elementwise_min((__v8di)__A, (__v8di)__B);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS512
@@ -1387,7 +1391,7 @@ _mm512_maskz_min_epi64 (__mmask8 __M, __m512i __A, __m512i __B)
static __inline __m512i __DEFAULT_FN_ATTRS512
_mm512_min_epu64(__m512i __A, __m512i __B)
{
- return (__m512i)__builtin_ia32_pminuq512((__v8di)__A, (__v8di)__B);
+ return (__m512i)__builtin_elementwise_min((__v8du)__A, (__v8du)__B);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS512
@@ -1846,7 +1850,7 @@ _mm512_mask_ceil_pd (__m512d __W, __mmask8 __U, __m512d __A)
static __inline __m512i __DEFAULT_FN_ATTRS512
_mm512_abs_epi64(__m512i __A)
{
- return (__m512i)__builtin_ia32_pabsq512((__v8di)__A);
+ return (__m512i)__builtin_elementwise_abs((__v8di)__A);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS512
@@ -1868,7 +1872,7 @@ _mm512_maskz_abs_epi64 (__mmask8 __U, __m512i __A)
static __inline __m512i __DEFAULT_FN_ATTRS512
_mm512_abs_epi32(__m512i __A)
{
- return (__m512i)__builtin_ia32_pabsd512((__v16si) __A);
+ return (__m512i)__builtin_elementwise_abs((__v16si) __A);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS512
@@ -9320,11 +9324,11 @@ static __inline__ long long __DEFAULT_FN_ATTRS512 _mm512_reduce_mul_epi64(__m512
}
static __inline__ long long __DEFAULT_FN_ATTRS512 _mm512_reduce_and_epi64(__m512i __W) {
- return __builtin_ia32_reduce_and_q512(__W);
+ return __builtin_reduce_and((__v8di)__W);
}
static __inline__ long long __DEFAULT_FN_ATTRS512 _mm512_reduce_or_epi64(__m512i __W) {
- return __builtin_ia32_reduce_or_q512(__W);
+ return __builtin_reduce_or((__v8di)__W);
}
static __inline__ long long __DEFAULT_FN_ATTRS512
@@ -9342,13 +9346,13 @@ _mm512_mask_reduce_mul_epi64(__mmask8 __M, __m512i __W) {
static __inline__ long long __DEFAULT_FN_ATTRS512
_mm512_mask_reduce_and_epi64(__mmask8 __M, __m512i __W) {
__W = _mm512_mask_mov_epi64(_mm512_set1_epi64(~0ULL), __M, __W);
- return __builtin_ia32_reduce_and_q512(__W);
+ return __builtin_reduce_and((__v8di)__W);
}
static __inline__ long long __DEFAULT_FN_ATTRS512
_mm512_mask_reduce_or_epi64(__mmask8 __M, __m512i __W) {
__W = _mm512_maskz_mov_epi64(__M, __W);
- return __builtin_ia32_reduce_or_q512(__W);
+ return __builtin_reduce_or((__v8di)__W);
}
// -0.0 is used to ignore the start value since it is the neutral value of
@@ -9386,12 +9390,12 @@ _mm512_reduce_mul_epi32(__m512i __W) {
static __inline__ int __DEFAULT_FN_ATTRS512
_mm512_reduce_and_epi32(__m512i __W) {
- return __builtin_ia32_reduce_and_d512((__v16si)__W);
+ return __builtin_reduce_and((__v16si)__W);
}
static __inline__ int __DEFAULT_FN_ATTRS512
_mm512_reduce_or_epi32(__m512i __W) {
- return __builtin_ia32_reduce_or_d512((__v16si)__W);
+ return __builtin_reduce_or((__v16si)__W);
}
static __inline__ int __DEFAULT_FN_ATTRS512
@@ -9409,13 +9413,13 @@ _mm512_mask_reduce_mul_epi32( __mmask16 __M, __m512i __W) {
static __inline__ int __DEFAULT_FN_ATTRS512
_mm512_mask_reduce_and_epi32( __mmask16 __M, __m512i __W) {
__W = _mm512_mask_mov_epi32(_mm512_set1_epi32(~0U), __M, __W);
- return __builtin_ia32_reduce_and_d512((__v16si)__W);
+ return __builtin_reduce_and((__v16si)__W);
}
static __inline__ int __DEFAULT_FN_ATTRS512
_mm512_mask_reduce_or_epi32(__mmask16 __M, __m512i __W) {
__W = _mm512_maskz_mov_epi32(__M, __W);
- return __builtin_ia32_reduce_or_d512((__v16si)__W);
+ return __builtin_reduce_or((__v16si)__W);
}
static __inline__ float __DEFAULT_FN_ATTRS512
@@ -9442,89 +9446,89 @@ _mm512_mask_reduce_mul_ps(__mmask16 __M, __m512 __W) {
static __inline__ long long __DEFAULT_FN_ATTRS512
_mm512_reduce_max_epi64(__m512i __V) {
- return __builtin_ia32_reduce_smax_q512(__V);
+ return __builtin_reduce_max((__v8di)__V);
}
static __inline__ unsigned long long __DEFAULT_FN_ATTRS512
_mm512_reduce_max_epu64(__m512i __V) {
- return __builtin_ia32_reduce_umax_q512(__V);
+ return __builtin_reduce_max((__v8du)__V);
}
static __inline__ long long __DEFAULT_FN_ATTRS512
_mm512_reduce_min_epi64(__m512i __V) {
- return __builtin_ia32_reduce_smin_q512(__V);
+ return __builtin_reduce_min((__v8di)__V);
}
static __inline__ unsigned long long __DEFAULT_FN_ATTRS512
_mm512_reduce_min_epu64(__m512i __V) {
- return __builtin_ia32_reduce_umin_q512(__V);
+ return __builtin_reduce_min((__v8du)__V);
}
static __inline__ long long __DEFAULT_FN_ATTRS512
_mm512_mask_reduce_max_epi64(__mmask8 __M, __m512i __V) {
__V = _mm512_mask_mov_epi64(_mm512_set1_epi64(-__LONG_LONG_MAX__ - 1LL), __M, __V);
- return __builtin_ia32_reduce_smax_q512(__V);
+ return __builtin_reduce_max((__v8di)__V);
}
static __inline__ unsigned long long __DEFAULT_FN_ATTRS512
_mm512_mask_reduce_max_epu64(__mmask8 __M, __m512i __V) {
__V = _mm512_maskz_mov_epi64(__M, __V);
- return __builtin_ia32_reduce_umax_q512(__V);
+ return __builtin_reduce_max((__v8du)__V);
}
static __inline__ long long __DEFAULT_FN_ATTRS512
_mm512_mask_reduce_min_epi64(__mmask8 __M, __m512i __V) {
__V = _mm512_mask_mov_epi64(_mm512_set1_epi64(__LONG_LONG_MAX__), __M, __V);
- return __builtin_ia32_reduce_smin_q512(__V);
+ return __builtin_reduce_min((__v8di)__V);
}
static __inline__ unsigned long long __DEFAULT_FN_ATTRS512
_mm512_mask_reduce_min_epu64(__mmask8 __M, __m512i __V) {
__V = _mm512_mask_mov_epi64(_mm512_set1_epi64(~0ULL), __M, __V);
- return __builtin_ia32_reduce_umin_q512(__V);
+ return __builtin_reduce_min((__v8du)__V);
}
static __inline__ int __DEFAULT_FN_ATTRS512
_mm512_reduce_max_epi32(__m512i __V) {
- return __builtin_ia32_reduce_smax_d512((__v16si)__V);
+ return __builtin_reduce_max((__v16si)__V);
}
static __inline__ unsigned int __DEFAULT_FN_ATTRS512
_mm512_reduce_max_epu32(__m512i __V) {
- return __builtin_ia32_reduce_umax_d512((__v16si)__V);
+ return __builtin_reduce_max((__v16su)__V);
}
static __inline__ int __DEFAULT_FN_ATTRS512
_mm512_reduce_min_epi32(__m512i __V) {
- return __builtin_ia32_reduce_smin_d512((__v16si)__V);
+ return __builtin_reduce_min((__v16si)__V);
}
static __inline__ unsigned int __DEFAULT_FN_ATTRS512
_mm512_reduce_min_epu32(__m512i __V) {
- return __builtin_ia32_reduce_umin_d512((__v16si)__V);
+ return __builtin_reduce_min((__v16su)__V);
}
static __inline__ int __DEFAULT_FN_ATTRS512
_mm512_mask_reduce_max_epi32(__mmask16 __M, __m512i __V) {
__V = _mm512_mask_mov_epi32(_mm512_set1_epi32(-__INT_MAX__ - 1), __M, __V);
- return __builtin_ia32_reduce_smax_d512((__v16si)__V);
+ return __builtin_reduce_max((__v16si)__V);
}
static __inline__ unsigned int __DEFAULT_FN_ATTRS512
_mm512_mask_reduce_max_epu32(__mmask16 __M, __m512i __V) {
__V = _mm512_maskz_mov_epi32(__M, __V);
- return __builtin_ia32_reduce_umax_d512((__v16si)__V);
+ return __builtin_reduce_max((__v16su)__V);
}
static __inline__ int __DEFAULT_FN_ATTRS512
_mm512_mask_reduce_min_epi32(__mmask16 __M, __m512i __V) {
__V = _mm512_mask_mov_epi32(_mm512_set1_epi32(__INT_MAX__), __M, __V);
- return __builtin_ia32_reduce_smin_d512((__v16si)__V);
+ return __builtin_reduce_min((__v16si)__V);
}
static __inline__ unsigned int __DEFAULT_FN_ATTRS512
_mm512_mask_reduce_min_epu32(__mmask16 __M, __m512i __V) {
__V = _mm512_mask_mov_epi32(_mm512_set1_epi32(~0U), __M, __V);
- return __builtin_ia32_reduce_umin_d512((__v16si)__V);
+ return __builtin_reduce_min((__v16su)__V);
}
static __inline__ double __DEFAULT_FN_ATTRS512
diff --git a/clang/lib/Headers/avx512vlintrin.h b/clang/lib/Headers/avx512vlintrin.h
index 0519dba59081..178c9dbc0e6e 100644
--- a/clang/lib/Headers/avx512vlintrin.h
+++ b/clang/lib/Headers/avx512vlintrin.h
@@ -2988,7 +2988,7 @@ _mm256_maskz_abs_epi32(__mmask8 __U, __m256i __A) {
static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_abs_epi64 (__m128i __A) {
- return (__m128i)__builtin_ia32_pabsq128((__v2di)__A);
+ return (__m128i)__builtin_elementwise_abs((__v2di)__A);
}
static __inline__ __m128i __DEFAULT_FN_ATTRS128
@@ -3007,7 +3007,7 @@ _mm_maskz_abs_epi64 (__mmask8 __U, __m128i __A) {
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_abs_epi64 (__m256i __A) {
- return (__m256i)__builtin_ia32_pabsq256 ((__v4di)__A);
+ return (__m256i)__builtin_elementwise_abs((__v4di)__A);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
@@ -3054,7 +3054,7 @@ _mm256_mask_max_epi32(__m256i __W, __mmask8 __M, __m256i __A, __m256i __B) {
static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_max_epi64 (__m128i __A, __m128i __B) {
- return (__m128i)__builtin_ia32_pmaxsq128((__v2di)__A, (__v2di)__B);
+ return (__m128i)__builtin_elementwise_max((__v2di)__A, (__v2di)__B);
}
static __inline__ __m128i __DEFAULT_FN_ATTRS128
@@ -3073,7 +3073,7 @@ _mm_mask_max_epi64 (__m128i __W, __mmask8 __M, __m128i __A, __m128i __B) {
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_max_epi64 (__m256i __A, __m256i __B) {
- return (__m256i)__builtin_ia32_pmaxsq256((__v4di)__A, (__v4di)__B);
+ return (__m256i)__builtin_elementwise_max((__v4di)__A, (__v4di)__B);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
@@ -3120,7 +3120,7 @@ _mm256_mask_max_epu32(__m256i __W, __mmask8 __M, __m256i __A, __m256i __B) {
static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_max_epu64 (__m128i __A, __m128i __B) {
- return (__m128i)__builtin_ia32_pmaxuq128((__v2di)__A, (__v2di)__B);
+ return (__m128i)__builtin_elementwise_max((__v2du)__A, (__v2du)__B);
}
static __inline__ __m128i __DEFAULT_FN_ATTRS128
@@ -3139,7 +3139,7 @@ _mm_mask_max_epu64 (__m128i __W, __mmask8 __M, __m128i __A, __m128i __B) {
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_max_epu64 (__m256i __A, __m256i __B) {
- return (__m256i)__builtin_ia32_pmaxuq256((__v4di)__A, (__v4di)__B);
+ return (__m256i)__builtin_elementwise_max((__v4du)__A, (__v4du)__B);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
@@ -3186,7 +3186,7 @@ _mm256_mask_min_epi32(__m256i __W, __mmask8 __M, __m256i __A, __m256i __B) {
static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_min_epi64 (__m128i __A, __m128i __B) {
- return (__m128i)__builtin_ia32_pminsq128((__v2di)__A, (__v2di)__B);
+ return (__m128i)__builtin_elementwise_min((__v2di)__A, (__v2di)__B);
}
static __inline__ __m128i __DEFAULT_FN_ATTRS128
@@ -3205,7 +3205,7 @@ _mm_maskz_min_epi64 (__mmask8 __M, __m128i __A, __m128i __B) {
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_min_epi64 (__m256i __A, __m256i __B) {
- return (__m256i)__builtin_ia32_pminsq256((__v4di)__A, (__v4di)__B);
+ return (__m256i)__builtin_elementwise_min((__v4di)__A, (__v4di)__B);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
@@ -3252,7 +3252,7 @@ _mm256_mask_min_epu32(__m256i __W, __mmask8 __M, __m256i __A, __m256i __B) {
static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_min_epu64 (__m128i __A, __m128i __B) {
- return (__m128i)__builtin_ia32_pminuq128((__v2di)__A, (__v2di)__B);
+ return (__m128i)__builtin_elementwise_min((__v2du)__A, (__v2du)__B);
}
static __inline__ __m128i __DEFAULT_FN_ATTRS128
@@ -3271,7 +3271,7 @@ _mm_maskz_min_epu64 (__mmask8 __M, __m128i __A, __m128i __B) {
static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_min_epu64 (__m256i __A, __m256i __B) {
- return (__m256i)__builtin_ia32_pminuq256((__v4di)__A, (__v4di)__B);
+ return (__m256i)__builtin_elementwise_min((__v4du)__A, (__v4du)__B);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
diff --git a/clang/lib/Headers/cetintrin.h b/clang/lib/Headers/cetintrin.h
index 4290e9d7355b..019cab0261e7 100644
--- a/clang/lib/Headers/cetintrin.h
+++ b/clang/lib/Headers/cetintrin.h
@@ -42,10 +42,20 @@ static __inline__ unsigned int __DEFAULT_FN_ATTRS _rdsspd(unsigned int __a) {
return __builtin_ia32_rdsspd(__a);
}
+static __inline__ unsigned int __DEFAULT_FN_ATTRS _rdsspd_i32() {
+ unsigned int t;
+ return __builtin_ia32_rdsspd(t);
+}
+
#ifdef __x86_64__
static __inline__ unsigned long long __DEFAULT_FN_ATTRS _rdsspq(unsigned long long __a) {
return __builtin_ia32_rdsspq(__a);
}
+
+static __inline__ unsigned long long __DEFAULT_FN_ATTRS _rdsspq_i64() {
+ unsigned long long t;
+ return __builtin_ia32_rdsspq(t);
+}
#endif /* __x86_64__ */
#ifdef __x86_64__
diff --git a/clang/lib/Headers/cpuid.h b/clang/lib/Headers/cpuid.h
index 6df1b4a11172..5d262a60735f 100644
--- a/clang/lib/Headers/cpuid.h
+++ b/clang/lib/Headers/cpuid.h
@@ -200,7 +200,7 @@
#define bit_AMXINT8 0x02000000
/* Features in %eax for leaf 7 sub-leaf 1 */
-#define bit_AVXVNNI 0x00000008
+#define bit_AVXVNNI 0x00000010
#define bit_AVX512BF16 0x00000020
#define bit_HRESET 0x00400000
diff --git a/clang/lib/Headers/emmintrin.h b/clang/lib/Headers/emmintrin.h
index 6e9c3032c21f..4618b808efc4 100644
--- a/clang/lib/Headers/emmintrin.h
+++ b/clang/lib/Headers/emmintrin.h
@@ -2375,7 +2375,7 @@ _mm_madd_epi16(__m128i __a, __m128i __b)
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_max_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pmaxsw128((__v8hi)__a, (__v8hi)__b);
+ return (__m128i)__builtin_elementwise_max((__v8hi)__a, (__v8hi)__b);
}
/// Compares corresponding elements of two 128-bit unsigned [16 x i8]
@@ -2395,7 +2395,7 @@ _mm_max_epi16(__m128i __a, __m128i __b)
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_max_epu8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pmaxub128((__v16qi)__a, (__v16qi)__b);
+ return (__m128i)__builtin_elementwise_max((__v16qu)__a, (__v16qu)__b);
}
/// Compares corresponding elements of two 128-bit signed [8 x i16]
@@ -2415,7 +2415,7 @@ _mm_max_epu8(__m128i __a, __m128i __b)
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_min_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pminsw128((__v8hi)__a, (__v8hi)__b);
+ return (__m128i)__builtin_elementwise_min((__v8hi)__a, (__v8hi)__b);
}
/// Compares corresponding elements of two 128-bit unsigned [16 x i8]
@@ -2435,7 +2435,7 @@ _mm_min_epi16(__m128i __a, __m128i __b)
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_min_epu8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pminub128((__v16qi)__a, (__v16qi)__b);
+ return (__m128i)__builtin_elementwise_min((__v16qu)__a, (__v16qu)__b);
}
/// Multiplies the corresponding elements of two signed [8 x i16]
diff --git a/clang/lib/Headers/limits.h b/clang/lib/Headers/limits.h
index c653580bac4e..c2d3a7cf4353 100644
--- a/clang/lib/Headers/limits.h
+++ b/clang/lib/Headers/limits.h
@@ -62,6 +62,24 @@
#define CHAR_BIT __CHAR_BIT__
+/* C2x 5.2.4.2.1 */
+/* FIXME: This is using the placeholder dates Clang produces for these macros
+ in C2x mode; switch to the correct values once they've been published. */
+#if __STDC_VERSION__ >= 202000L
+#define BOOL_WIDTH __BOOL_WIDTH__
+#define CHAR_WIDTH CHAR_BIT
+#define SCHAR_WIDTH CHAR_BIT
+#define UCHAR_WIDTH CHAR_BIT
+#define USHRT_WIDTH __SHRT_WIDTH__
+#define SHRT_WIDTH __SHRT_WIDTH__
+#define UINT_WIDTH __INT_WIDTH__
+#define INT_WIDTH __INT_WIDTH__
+#define ULONG_WIDTH __LONG_WIDTH__
+#define LONG_WIDTH __LONG_WIDTH__
+#define ULLONG_WIDTH __LLONG_WIDTH__
+#define LLONG_WIDTH __LLONG_WIDTH__
+#endif
+
#ifdef __CHAR_UNSIGNED__ /* -funsigned-char */
#define CHAR_MIN 0
#define CHAR_MAX UCHAR_MAX
diff --git a/clang/lib/Headers/opencl-c-base.h b/clang/lib/Headers/opencl-c-base.h
index 9c81ddb5e2a7..06b78da63e69 100644
--- a/clang/lib/Headers/opencl-c-base.h
+++ b/clang/lib/Headers/opencl-c-base.h
@@ -68,6 +68,7 @@
// For the SPIR and SPIR-V target all features are supported.
#if defined(__SPIR__) || defined(__SPIRV__)
#define __opencl_c_atomic_scope_all_devices 1
+#define __opencl_c_read_write_images 1
#endif // defined(__SPIR__)
#endif // (__OPENCL_CPP_VERSION__ == 202100 || __OPENCL_C_VERSION__ == 300)
@@ -498,12 +499,14 @@ typedef int clk_profiling_info;
#define MAX_WORK_DIM 3
+#ifdef __opencl_c_device_enqueue
typedef struct {
unsigned int workDimension;
size_t globalWorkOffset[MAX_WORK_DIM];
size_t globalWorkSize[MAX_WORK_DIM];
size_t localWorkSize[MAX_WORK_DIM];
} ndrange_t;
+#endif // __opencl_c_device_enqueue
#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
@@ -600,9 +603,11 @@ typedef struct {
// C++ for OpenCL - __remove_address_space
#if defined(__OPENCL_CPP_VERSION__)
template <typename _Tp> struct __remove_address_space { using type = _Tp; };
+#if defined(__opencl_c_generic_address_space)
template <typename _Tp> struct __remove_address_space<__generic _Tp> {
using type = _Tp;
};
+#endif
template <typename _Tp> struct __remove_address_space<__global _Tp> {
using type = _Tp;
};
diff --git a/clang/lib/Headers/opencl-c.h b/clang/lib/Headers/opencl-c.h
index 77a7a8b9bb3a..8fde2fa29899 100644
--- a/clang/lib/Headers/opencl-c.h
+++ b/clang/lib/Headers/opencl-c.h
@@ -11,11 +11,11 @@
#include "opencl-c-base.h"
-#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#if defined(__opencl_c_images)
#ifndef cl_khr_depth_images
#define cl_khr_depth_images
#endif //cl_khr_depth_images
-#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#endif //defined(__opencl_c_images)
#if __OPENCL_C_VERSION__ < CL_VERSION_2_0
#ifdef cl_khr_3d_image_writes
@@ -15585,7 +15585,7 @@ half4 __purefn __ovld read_imageh(read_only image1d_buffer_t image, int coord);
#endif //cl_khr_fp16
// Image read functions for read_write images
-#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#if defined(__opencl_c_read_write_images)
float4 __purefn __ovld read_imagef(read_write image1d_t image, int coord);
int4 __purefn __ovld read_imagei(read_write image1d_t image, int coord);
uint4 __purefn __ovld read_imageui(read_write image1d_t image, int coord);
@@ -15628,7 +15628,6 @@ float __purefn __ovld read_imagef(read_write image2d_msaa_depth_t image, int2 co
float __purefn __ovld read_imagef(read_write image2d_array_msaa_depth_t image, int4 coord, int sample);
#endif //cl_khr_gl_msaa_sharing
-#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
#ifdef cl_khr_mipmap_image
float4 __purefn __ovld read_imagef(read_write image1d_t image, sampler_t sampler, float coord, float lod);
int4 __purefn __ovld read_imagei(read_write image1d_t image, sampler_t sampler, float coord, float lod);
@@ -15679,7 +15678,6 @@ int4 __purefn __ovld read_imagei(read_write image3d_t image, sampler_t sampler,
uint4 __purefn __ovld read_imageui(read_write image3d_t image, sampler_t sampler, float4 coord, float4 gradientX, float4 gradientY);
#endif //cl_khr_mipmap_image
-#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
// Image read functions returning half4 type
#ifdef cl_khr_fp16
@@ -15690,7 +15688,7 @@ half4 __purefn __ovld read_imageh(read_write image1d_array_t image, int2 coord);
half4 __purefn __ovld read_imageh(read_write image2d_array_t image, int4 coord);
half4 __purefn __ovld read_imageh(read_write image1d_buffer_t image, int coord);
#endif //cl_khr_fp16
-#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#endif //defined(__opencl_c_read_write_images)
/**
* Write color value to location specified by coordinate
@@ -15834,7 +15832,7 @@ void __ovld write_imageh(write_only image1d_buffer_t image, int coord, half4 col
#endif //cl_khr_fp16
// Image write functions for read_write images
-#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#if defined(__opencl_c_read_write_images)
void __ovld write_imagef(read_write image2d_t image, int2 coord, float4 color);
void __ovld write_imagei(read_write image2d_t image, int2 coord, int4 color);
void __ovld write_imageui(read_write image2d_t image, int2 coord, uint4 color);
@@ -15866,7 +15864,6 @@ void __ovld write_imagef(read_write image2d_depth_t image, int2 coord, float col
void __ovld write_imagef(read_write image2d_array_depth_t image, int4 coord, float color);
#endif //cl_khr_depth_images
-#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
#if defined(cl_khr_mipmap_image_writes)
void __ovld write_imagef(read_write image1d_t image, int coord, int lod, float4 color);
void __ovld write_imagei(read_write image1d_t image, int coord, int lod, int4 color);
@@ -15894,7 +15891,6 @@ void __ovld write_imageui(read_write image3d_t image, int4 coord, int lod, uint4
#endif //cl_khr_3d_image_writes
#endif //cl_khr_mipmap_image_writes
-#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
// Image write functions for half4 type
#ifdef cl_khr_fp16
@@ -15907,7 +15903,7 @@ void __ovld write_imageh(read_write image1d_array_t image, int2 coord, half4 col
void __ovld write_imageh(read_write image2d_array_t image, int4 coord, half4 color);
void __ovld write_imageh(read_write image1d_buffer_t image, int coord, half4 color);
#endif //cl_khr_fp16
-#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#endif //defined(__opencl_c_read_write_images)
// Note: In OpenCL v1.0/1.1/1.2, image argument of image query builtin functions does not have
// access qualifier, which by default assume read_only access qualifier. Image query builtin
@@ -15955,7 +15951,7 @@ int __ovld __cnfn get_image_width(write_only image2d_array_msaa_t image);
int __ovld __cnfn get_image_width(write_only image2d_array_msaa_depth_t image);
#endif //cl_khr_gl_msaa_sharing
-#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#if defined(__opencl_c_read_write_images)
int __ovld __cnfn get_image_width(read_write image1d_t image);
int __ovld __cnfn get_image_width(read_write image1d_buffer_t image);
int __ovld __cnfn get_image_width(read_write image2d_t image);
@@ -15972,7 +15968,7 @@ int __ovld __cnfn get_image_width(read_write image2d_msaa_depth_t image);
int __ovld __cnfn get_image_width(read_write image2d_array_msaa_t image);
int __ovld __cnfn get_image_width(read_write image2d_array_msaa_depth_t image);
#endif //cl_khr_gl_msaa_sharing
-#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#endif //defined(__opencl_c_read_write_images)
/**
* Return the image height in pixels.
@@ -16007,7 +16003,7 @@ int __ovld __cnfn get_image_height(write_only image2d_array_msaa_t image);
int __ovld __cnfn get_image_height(write_only image2d_array_msaa_depth_t image);
#endif //cl_khr_gl_msaa_sharing
-#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#if defined(__opencl_c_read_write_images)
int __ovld __cnfn get_image_height(read_write image2d_t image);
int __ovld __cnfn get_image_height(read_write image3d_t image);
int __ovld __cnfn get_image_height(read_write image2d_array_t image);
@@ -16021,7 +16017,7 @@ int __ovld __cnfn get_image_height(read_write image2d_msaa_depth_t image);
int __ovld __cnfn get_image_height(read_write image2d_array_msaa_t image);
int __ovld __cnfn get_image_height(read_write image2d_array_msaa_depth_t image);
#endif //cl_khr_gl_msaa_sharing
-#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#endif //defined(__opencl_c_read_write_images)
/**
* Return the image depth in pixels.
@@ -16032,9 +16028,9 @@ int __ovld __cnfn get_image_depth(read_only image3d_t image);
int __ovld __cnfn get_image_depth(write_only image3d_t image);
#endif
-#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#if defined(__opencl_c_read_write_images)
int __ovld __cnfn get_image_depth(read_write image3d_t image);
-#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#endif //defined(__opencl_c_read_write_images)
// OpenCL Extension v2.0 s9.18 - Mipmaps
#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
@@ -16053,9 +16049,11 @@ int __ovld get_image_num_mip_levels(write_only image2d_t image);
int __ovld get_image_num_mip_levels(write_only image3d_t image);
#endif
+#if defined(__opencl_c_read_write_images)
int __ovld get_image_num_mip_levels(read_write image1d_t image);
int __ovld get_image_num_mip_levels(read_write image2d_t image);
int __ovld get_image_num_mip_levels(read_write image3d_t image);
+#endif //defined(__opencl_c_read_write_images)
int __ovld get_image_num_mip_levels(read_only image1d_array_t image);
int __ovld get_image_num_mip_levels(read_only image2d_array_t image);
@@ -16067,10 +16065,12 @@ int __ovld get_image_num_mip_levels(write_only image2d_array_t image);
int __ovld get_image_num_mip_levels(write_only image2d_array_depth_t image);
int __ovld get_image_num_mip_levels(write_only image2d_depth_t image);
+#if defined(__opencl_c_read_write_images)
int __ovld get_image_num_mip_levels(read_write image1d_array_t image);
int __ovld get_image_num_mip_levels(read_write image2d_array_t image);
int __ovld get_image_num_mip_levels(read_write image2d_array_depth_t image);
int __ovld get_image_num_mip_levels(read_write image2d_depth_t image);
+#endif //defined(__opencl_c_read_write_images)
#endif //cl_khr_mipmap_image
#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
@@ -16130,7 +16130,7 @@ int __ovld __cnfn get_image_channel_data_type(write_only image2d_array_msaa_t im
int __ovld __cnfn get_image_channel_data_type(write_only image2d_array_msaa_depth_t image);
#endif //cl_khr_gl_msaa_sharing
-#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#if defined(__opencl_c_read_write_images)
int __ovld __cnfn get_image_channel_data_type(read_write image1d_t image);
int __ovld __cnfn get_image_channel_data_type(read_write image1d_buffer_t image);
int __ovld __cnfn get_image_channel_data_type(read_write image2d_t image);
@@ -16147,7 +16147,7 @@ int __ovld __cnfn get_image_channel_data_type(read_write image2d_msaa_depth_t im
int __ovld __cnfn get_image_channel_data_type(read_write image2d_array_msaa_t image);
int __ovld __cnfn get_image_channel_data_type(read_write image2d_array_msaa_depth_t image);
#endif //cl_khr_gl_msaa_sharing
-#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#endif //defined(__opencl_c_read_write_images)
/**
* Return the image channel order. Valid values are:
@@ -16202,7 +16202,7 @@ int __ovld __cnfn get_image_channel_order(write_only image2d_array_msaa_t image)
int __ovld __cnfn get_image_channel_order(write_only image2d_array_msaa_depth_t image);
#endif //cl_khr_gl_msaa_sharing
-#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#if defined(__opencl_c_read_write_images)
int __ovld __cnfn get_image_channel_order(read_write image1d_t image);
int __ovld __cnfn get_image_channel_order(read_write image1d_buffer_t image);
int __ovld __cnfn get_image_channel_order(read_write image2d_t image);
@@ -16219,7 +16219,7 @@ int __ovld __cnfn get_image_channel_order(read_write image2d_msaa_depth_t image)
int __ovld __cnfn get_image_channel_order(read_write image2d_array_msaa_t image);
int __ovld __cnfn get_image_channel_order(read_write image2d_array_msaa_depth_t image);
#endif //cl_khr_gl_msaa_sharing
-#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#endif //defined(__opencl_c_read_write_images)
/**
* Return the 2D image width and height as an int2
@@ -16252,7 +16252,7 @@ int2 __ovld __cnfn get_image_dim(write_only image2d_array_msaa_t image);
int2 __ovld __cnfn get_image_dim(write_only image2d_array_msaa_depth_t image);
#endif //cl_khr_gl_msaa_sharing
-#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#if defined(__opencl_c_read_write_images)
int2 __ovld __cnfn get_image_dim(read_write image2d_t image);
int2 __ovld __cnfn get_image_dim(read_write image2d_array_t image);
#ifdef cl_khr_depth_images
@@ -16265,7 +16265,7 @@ int2 __ovld __cnfn get_image_dim(read_write image2d_msaa_depth_t image);
int2 __ovld __cnfn get_image_dim(read_write image2d_array_msaa_t image);
int2 __ovld __cnfn get_image_dim(read_write image2d_array_msaa_depth_t image);
#endif //cl_khr_gl_msaa_sharing
-#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#endif //defined(__opencl_c_read_write_images)
/**
* Return the 3D image width, height, and depth as an
@@ -16277,9 +16277,9 @@ int4 __ovld __cnfn get_image_dim(read_only image3d_t image);
#ifdef cl_khr_3d_image_writes
int4 __ovld __cnfn get_image_dim(write_only image3d_t image);
#endif
-#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#if defined(__opencl_c_read_write_images)
int4 __ovld __cnfn get_image_dim(read_write image3d_t image);
-#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#endif //defined(__opencl_c_read_write_images)
/**
* Return the image array size.
@@ -16305,7 +16305,7 @@ size_t __ovld __cnfn get_image_array_size(write_only image2d_array_msaa_t image_
size_t __ovld __cnfn get_image_array_size(write_only image2d_array_msaa_depth_t image_array);
#endif //cl_khr_gl_msaa_sharing
-#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#if defined(__opencl_c_read_write_images)
size_t __ovld __cnfn get_image_array_size(read_write image1d_array_t image_array);
size_t __ovld __cnfn get_image_array_size(read_write image2d_array_t image_array);
#ifdef cl_khr_depth_images
@@ -16315,7 +16315,7 @@ size_t __ovld __cnfn get_image_array_size(read_write image2d_array_depth_t image
size_t __ovld __cnfn get_image_array_size(read_write image2d_array_msaa_t image_array);
size_t __ovld __cnfn get_image_array_size(read_write image2d_array_msaa_depth_t image_array);
#endif //cl_khr_gl_msaa_sharing
-#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#endif //defined(__opencl_c_read_write_images)
/**
* Return the number of samples associated with image
@@ -16331,12 +16331,12 @@ int __ovld get_image_num_samples(write_only image2d_msaa_depth_t image);
int __ovld get_image_num_samples(write_only image2d_array_msaa_t image);
int __ovld get_image_num_samples(write_only image2d_array_msaa_depth_t image);
-#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#if defined(__opencl_c_read_write_images)
int __ovld get_image_num_samples(read_write image2d_msaa_t image);
int __ovld get_image_num_samples(read_write image2d_msaa_depth_t image);
int __ovld get_image_num_samples(read_write image2d_array_msaa_t image);
int __ovld get_image_num_samples(read_write image2d_array_msaa_depth_t image);
-#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#endif //defined(__opencl_c_read_write_images)
#endif
// OpenCL v2.0 s6.13.15 - Work-group Functions
@@ -16450,6 +16450,7 @@ bool __ovld is_valid_reserve_id(reserve_id_t reserve_id);
// OpenCL v2.0 s6.13.17 - Enqueue Kernels
#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#ifdef __opencl_c_device_enqueue
ndrange_t __ovld ndrange_1D(size_t);
ndrange_t __ovld ndrange_1D(size_t, size_t);
ndrange_t __ovld ndrange_1D(size_t, size_t, size_t);
@@ -16477,6 +16478,7 @@ bool __ovld is_valid_event (clk_event_t event);
void __ovld capture_event_profiling_info(clk_event_t, clk_profiling_info, __global void* value);
queue_t __ovld get_default_queue(void);
+#endif //__opencl_c_device_enqueue
#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
// OpenCL Extension v2.0 s9.17 - Sub-groups
@@ -17572,34 +17574,38 @@ uint16 __ovld __conv intel_sub_group_shuffle_xor( uint16 x, uint c );
long __ovld __conv intel_sub_group_shuffle_xor( long x, uint c );
ulong __ovld __conv intel_sub_group_shuffle_xor( ulong x, uint c );
+#if defined(__opencl_c_images)
uint __ovld __conv intel_sub_group_block_read( read_only image2d_t image, int2 coord );
uint2 __ovld __conv intel_sub_group_block_read2( read_only image2d_t image, int2 coord );
uint4 __ovld __conv intel_sub_group_block_read4( read_only image2d_t image, int2 coord );
uint8 __ovld __conv intel_sub_group_block_read8( read_only image2d_t image, int2 coord );
+#endif
-#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#if defined(__opencl_c_read_write_images)
uint __ovld __conv intel_sub_group_block_read(read_write image2d_t image, int2 coord);
uint2 __ovld __conv intel_sub_group_block_read2(read_write image2d_t image, int2 coord);
uint4 __ovld __conv intel_sub_group_block_read4(read_write image2d_t image, int2 coord);
uint8 __ovld __conv intel_sub_group_block_read8(read_write image2d_t image, int2 coord);
-#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#endif // defined(__opencl_c_read_write_images)
uint __ovld __conv intel_sub_group_block_read( const __global uint* p );
uint2 __ovld __conv intel_sub_group_block_read2( const __global uint* p );
uint4 __ovld __conv intel_sub_group_block_read4( const __global uint* p );
uint8 __ovld __conv intel_sub_group_block_read8( const __global uint* p );
+#if defined(__opencl_c_images)
void __ovld __conv intel_sub_group_block_write(write_only image2d_t image, int2 coord, uint data);
void __ovld __conv intel_sub_group_block_write2(write_only image2d_t image, int2 coord, uint2 data);
void __ovld __conv intel_sub_group_block_write4(write_only image2d_t image, int2 coord, uint4 data);
void __ovld __conv intel_sub_group_block_write8(write_only image2d_t image, int2 coord, uint8 data);
+#endif // defined(__opencl_c_images)
-#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#if defined(__opencl_c_read_write_images)
void __ovld __conv intel_sub_group_block_write(read_write image2d_t image, int2 coord, uint data);
void __ovld __conv intel_sub_group_block_write2(read_write image2d_t image, int2 coord, uint2 data);
void __ovld __conv intel_sub_group_block_write4(read_write image2d_t image, int2 coord, uint4 data);
void __ovld __conv intel_sub_group_block_write8(read_write image2d_t image, int2 coord, uint8 data);
-#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#endif // defined(__opencl_c_read_write_images)
void __ovld __conv intel_sub_group_block_write( __global uint* p, uint data );
void __ovld __conv intel_sub_group_block_write2( __global uint* p, uint2 data );
@@ -17712,68 +17718,76 @@ ushort __ovld __conv intel_sub_group_scan_inclusive_min( ushort x );
short __ovld __conv intel_sub_group_scan_inclusive_max( short x );
ushort __ovld __conv intel_sub_group_scan_inclusive_max( ushort x );
+#if defined(__opencl_c_images)
uint __ovld __conv intel_sub_group_block_read_ui( read_only image2d_t image, int2 byte_coord );
uint2 __ovld __conv intel_sub_group_block_read_ui2( read_only image2d_t image, int2 byte_coord );
uint4 __ovld __conv intel_sub_group_block_read_ui4( read_only image2d_t image, int2 byte_coord );
uint8 __ovld __conv intel_sub_group_block_read_ui8( read_only image2d_t image, int2 byte_coord );
+#endif // defined(__opencl_c_images)
-#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#if defined(__opencl_c_read_write_images)
uint __ovld __conv intel_sub_group_block_read_ui( read_write image2d_t image, int2 byte_coord );
uint2 __ovld __conv intel_sub_group_block_read_ui2( read_write image2d_t image, int2 byte_coord );
uint4 __ovld __conv intel_sub_group_block_read_ui4( read_write image2d_t image, int2 byte_coord );
uint8 __ovld __conv intel_sub_group_block_read_ui8( read_write image2d_t image, int2 byte_coord );
-#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#endif // defined(__opencl_c_read_write_images)
uint __ovld __conv intel_sub_group_block_read_ui( const __global uint* p );
uint2 __ovld __conv intel_sub_group_block_read_ui2( const __global uint* p );
uint4 __ovld __conv intel_sub_group_block_read_ui4( const __global uint* p );
uint8 __ovld __conv intel_sub_group_block_read_ui8( const __global uint* p );
+#if defined(__opencl_c_images)
void __ovld __conv intel_sub_group_block_write_ui( read_only image2d_t image, int2 byte_coord, uint data );
void __ovld __conv intel_sub_group_block_write_ui2( read_only image2d_t image, int2 byte_coord, uint2 data );
void __ovld __conv intel_sub_group_block_write_ui4( read_only image2d_t image, int2 byte_coord, uint4 data );
void __ovld __conv intel_sub_group_block_write_ui8( read_only image2d_t image, int2 byte_coord, uint8 data );
+#endif //defined(__opencl_c_images)
-#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#if defined(__opencl_c_read_write_images)
void __ovld __conv intel_sub_group_block_write_ui( read_write image2d_t image, int2 byte_coord, uint data );
void __ovld __conv intel_sub_group_block_write_ui2( read_write image2d_t image, int2 byte_coord, uint2 data );
void __ovld __conv intel_sub_group_block_write_ui4( read_write image2d_t image, int2 byte_coord, uint4 data );
void __ovld __conv intel_sub_group_block_write_ui8( read_write image2d_t image, int2 byte_coord, uint8 data );
-#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#endif // defined(__opencl_c_read_write_images)
void __ovld __conv intel_sub_group_block_write_ui( __global uint* p, uint data );
void __ovld __conv intel_sub_group_block_write_ui2( __global uint* p, uint2 data );
void __ovld __conv intel_sub_group_block_write_ui4( __global uint* p, uint4 data );
void __ovld __conv intel_sub_group_block_write_ui8( __global uint* p, uint8 data );
+#if defined(__opencl_c_images)
ushort __ovld __conv intel_sub_group_block_read_us( read_only image2d_t image, int2 coord );
ushort2 __ovld __conv intel_sub_group_block_read_us2( read_only image2d_t image, int2 coord );
ushort4 __ovld __conv intel_sub_group_block_read_us4( read_only image2d_t image, int2 coord );
ushort8 __ovld __conv intel_sub_group_block_read_us8( read_only image2d_t image, int2 coord );
+#endif // defined(__opencl_c_images)
-#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#if defined(__opencl_c_read_write_images)
ushort __ovld __conv intel_sub_group_block_read_us(read_write image2d_t image, int2 coord);
ushort2 __ovld __conv intel_sub_group_block_read_us2(read_write image2d_t image, int2 coord);
ushort4 __ovld __conv intel_sub_group_block_read_us4(read_write image2d_t image, int2 coord);
ushort8 __ovld __conv intel_sub_group_block_read_us8(read_write image2d_t image, int2 coord);
-#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#endif // defined(__opencl_c_read_write_images)
ushort __ovld __conv intel_sub_group_block_read_us( const __global ushort* p );
ushort2 __ovld __conv intel_sub_group_block_read_us2( const __global ushort* p );
ushort4 __ovld __conv intel_sub_group_block_read_us4( const __global ushort* p );
ushort8 __ovld __conv intel_sub_group_block_read_us8( const __global ushort* p );
+#if defined(__opencl_c_images)
void __ovld __conv intel_sub_group_block_write_us(write_only image2d_t image, int2 coord, ushort data);
void __ovld __conv intel_sub_group_block_write_us2(write_only image2d_t image, int2 coord, ushort2 data);
void __ovld __conv intel_sub_group_block_write_us4(write_only image2d_t image, int2 coord, ushort4 data);
void __ovld __conv intel_sub_group_block_write_us8(write_only image2d_t image, int2 coord, ushort8 data);
+#endif // defined(__opencl_c_images)
-#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#if defined(__opencl_c_read_write_images)
void __ovld __conv intel_sub_group_block_write_us(read_write image2d_t image, int2 coord, ushort data);
void __ovld __conv intel_sub_group_block_write_us2(read_write image2d_t image, int2 coord, ushort2 data);
void __ovld __conv intel_sub_group_block_write_us4(read_write image2d_t image, int2 coord, ushort4 data);
void __ovld __conv intel_sub_group_block_write_us8(read_write image2d_t image, int2 coord, ushort8 data);
-#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#endif // defined(__opencl_c_read_write_images)
void __ovld __conv intel_sub_group_block_write_us( __global ushort* p, ushort data );
void __ovld __conv intel_sub_group_block_write_us2( __global ushort* p, ushort2 data );
@@ -17891,6 +17905,7 @@ short2 __ovld intel_sub_group_avc_ime_adjust_ref_offset(
short2 ref_offset, ushort2 src_coord, ushort2 ref_window_size,
ushort2 image_size);
+#if defined(__opencl_c_images)
intel_sub_group_avc_ime_result_t __ovld
intel_sub_group_avc_ime_evaluate_with_single_reference(
read_only image2d_t src_image, read_only image2d_t ref_image,
@@ -17931,6 +17946,7 @@ intel_sub_group_avc_ime_evaluate_with_dual_reference_streaminout(
read_only image2d_t bwd_ref_image, sampler_t vme_media_sampler,
intel_sub_group_avc_ime_payload_t payload,
intel_sub_group_avc_ime_dual_reference_streamin_t streamin_components);
+#endif
intel_sub_group_avc_ime_single_reference_streamin_t __ovld
intel_sub_group_avc_ime_get_single_reference_streamin(
@@ -17995,6 +18011,7 @@ intel_sub_group_avc_ref_payload_t __ovld
intel_sub_group_avc_ref_set_bilinear_filter_enable(
intel_sub_group_avc_ref_payload_t payload);
+#if defined(__opencl_c_images)
intel_sub_group_avc_ref_result_t __ovld
intel_sub_group_avc_ref_evaluate_with_single_reference(
read_only image2d_t src_image, read_only image2d_t ref_image,
@@ -18013,6 +18030,7 @@ intel_sub_group_avc_ref_evaluate_with_multi_reference(
read_only image2d_t src_image, uint packed_reference_ids,
uchar packed_reference_field_polarities, sampler_t vme_media_sampler,
intel_sub_group_avc_ref_payload_t payload);
+#endif //defined(__opencl_c_images)
// SIC built-in functions
intel_sub_group_avc_sic_payload_t __ovld
@@ -18063,6 +18081,7 @@ intel_sub_group_avc_sic_set_block_based_raw_skip_sad(
uchar block_based_skip_type,
intel_sub_group_avc_sic_payload_t payload);
+#if defined(__opencl_c_images)
intel_sub_group_avc_sic_result_t __ovld
intel_sub_group_avc_sic_evaluate_ipe(
read_only image2d_t src_image, sampler_t vme_media_sampler,
@@ -18085,6 +18104,7 @@ intel_sub_group_avc_sic_evaluate_with_multi_reference(
read_only image2d_t src_image, uint packed_reference_ids,
uchar packed_reference_field_polarities, sampler_t vme_media_sampler,
intel_sub_group_avc_sic_payload_t payload);
+#endif //defined(__opencl_c_images)
uchar __ovld intel_sub_group_avc_sic_get_ipe_luma_shape(
intel_sub_group_avc_sic_result_t result);
diff --git a/clang/lib/Headers/smmintrin.h b/clang/lib/Headers/smmintrin.h
index 710e55aaa120..0df59c5fcc59 100644
--- a/clang/lib/Headers/smmintrin.h
+++ b/clang/lib/Headers/smmintrin.h
@@ -668,7 +668,7 @@ _mm_stream_load_si128 (__m128i const *__V)
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_min_epi8 (__m128i __V1, __m128i __V2)
{
- return (__m128i) __builtin_ia32_pminsb128 ((__v16qi) __V1, (__v16qi) __V2);
+ return (__m128i) __builtin_elementwise_min((__v16qs) __V1, (__v16qs) __V2);
}
/// Compares the corresponding elements of two 128-bit vectors of
@@ -687,7 +687,7 @@ _mm_min_epi8 (__m128i __V1, __m128i __V2)
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_max_epi8 (__m128i __V1, __m128i __V2)
{
- return (__m128i) __builtin_ia32_pmaxsb128 ((__v16qi) __V1, (__v16qi) __V2);
+ return (__m128i) __builtin_elementwise_max((__v16qs) __V1, (__v16qs) __V2);
}
/// Compares the corresponding elements of two 128-bit vectors of
@@ -706,7 +706,7 @@ _mm_max_epi8 (__m128i __V1, __m128i __V2)
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_min_epu16 (__m128i __V1, __m128i __V2)
{
- return (__m128i) __builtin_ia32_pminuw128 ((__v8hi) __V1, (__v8hi) __V2);
+ return (__m128i) __builtin_elementwise_min((__v8hu) __V1, (__v8hu) __V2);
}
/// Compares the corresponding elements of two 128-bit vectors of
@@ -725,7 +725,7 @@ _mm_min_epu16 (__m128i __V1, __m128i __V2)
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_max_epu16 (__m128i __V1, __m128i __V2)
{
- return (__m128i) __builtin_ia32_pmaxuw128 ((__v8hi) __V1, (__v8hi) __V2);
+ return (__m128i) __builtin_elementwise_max((__v8hu) __V1, (__v8hu) __V2);
}
/// Compares the corresponding elements of two 128-bit vectors of
@@ -744,7 +744,7 @@ _mm_max_epu16 (__m128i __V1, __m128i __V2)
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_min_epi32 (__m128i __V1, __m128i __V2)
{
- return (__m128i) __builtin_ia32_pminsd128 ((__v4si) __V1, (__v4si) __V2);
+ return (__m128i) __builtin_elementwise_min((__v4si) __V1, (__v4si) __V2);
}
/// Compares the corresponding elements of two 128-bit vectors of
@@ -763,7 +763,7 @@ _mm_min_epi32 (__m128i __V1, __m128i __V2)
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_max_epi32 (__m128i __V1, __m128i __V2)
{
- return (__m128i) __builtin_ia32_pmaxsd128 ((__v4si) __V1, (__v4si) __V2);
+ return (__m128i) __builtin_elementwise_max((__v4si) __V1, (__v4si) __V2);
}
/// Compares the corresponding elements of two 128-bit vectors of
@@ -782,7 +782,7 @@ _mm_max_epi32 (__m128i __V1, __m128i __V2)
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_min_epu32 (__m128i __V1, __m128i __V2)
{
- return (__m128i) __builtin_ia32_pminud128((__v4si) __V1, (__v4si) __V2);
+ return (__m128i) __builtin_elementwise_min((__v4su) __V1, (__v4su) __V2);
}
/// Compares the corresponding elements of two 128-bit vectors of
@@ -801,7 +801,7 @@ _mm_min_epu32 (__m128i __V1, __m128i __V2)
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_max_epu32 (__m128i __V1, __m128i __V2)
{
- return (__m128i) __builtin_ia32_pmaxud128((__v4si) __V1, (__v4si) __V2);
+ return (__m128i) __builtin_elementwise_max((__v4su) __V1, (__v4su) __V2);
}
/* SSE4 Insertion and Extraction from XMM Register Instructions. */
diff --git a/clang/lib/Headers/stdatomic.h b/clang/lib/Headers/stdatomic.h
index 1e47bcb2bacf..780bcc2dfea1 100644
--- a/clang/lib/Headers/stdatomic.h
+++ b/clang/lib/Headers/stdatomic.h
@@ -44,6 +44,11 @@ extern "C" {
/* 7.17.2 Initialization */
#define ATOMIC_VAR_INIT(value) (value)
+#if (__STDC_VERSION__ >= 201710L || __cplusplus >= 202002L) && \
+ !defined(_CLANG_DISABLE_CRT_DEPRECATION_WARNINGS)
+/* ATOMIC_VAR_INIT was deprecated in C17 and C++20. */
+#pragma clang deprecated(ATOMIC_VAR_INIT)
+#endif
#define atomic_init __c11_atomic_init
/* 7.17.3 Order and consistency */
@@ -153,6 +158,10 @@ typedef _Atomic(uintmax_t) atomic_uintmax_t;
typedef struct atomic_flag { atomic_bool _Value; } atomic_flag;
#define ATOMIC_FLAG_INIT { 0 }
+#if __cplusplus >= 202002L && !defined(_CLANG_DISABLE_CRT_DEPRECATION_WARNINGS)
+/* ATOMIC_FLAG_INIT was deprecated in C++20 but is not deprecated in C. */
+#pragma clang deprecated(ATOMIC_FLAG_INIT)
+#endif
/* These should be provided by the libc implementation. */
#ifdef __cplusplus
diff --git a/clang/lib/Headers/stdint.h b/clang/lib/Headers/stdint.h
index 192f653e95a1..4790c25a2774 100644
--- a/clang/lib/Headers/stdint.h
+++ b/clang/lib/Headers/stdint.h
@@ -461,6 +461,18 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# define INT64_MAX INT64_C( 9223372036854775807)
# define INT64_MIN (-INT64_C( 9223372036854775807)-1)
# define UINT64_MAX UINT64_C(18446744073709551615)
+/* FIXME: This is using the placeholder dates Clang produces for these macros
+ in C2x mode; switch to the correct values once they've been published. */
+#if __STDC_VERSION__ >= 202000L
+# define UINT64_WIDTH 64
+# define INT64_WIDTH UINT64_WIDTH
+
+# define __UINT_LEAST64_WIDTH UINT64_WIDTH
+# define __UINT_LEAST32_WIDTH UINT64_WIDTH
+# define __UINT_LEAST16_WIDTH UINT64_WIDTH
+# define __UINT_LEAST8_MAX UINT64_MAX
+#endif /* __STDC_VERSION__ */
+
# define __INT_LEAST64_MIN INT64_MIN
# define __INT_LEAST64_MAX INT64_MAX
# define __UINT_LEAST64_MAX UINT64_MAX
@@ -482,6 +494,15 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# define INT_FAST64_MIN __INT_LEAST64_MIN
# define INT_FAST64_MAX __INT_LEAST64_MAX
# define UINT_FAST64_MAX __UINT_LEAST64_MAX
+
+/* FIXME: This is using the placeholder dates Clang produces for these macros
+ in C2x mode; switch to the correct values once they've been published. */
+#if __STDC_VERSION__ >= 202000L
+# define UINT_LEAST64_WIDTH __UINT_LEAST64_WIDTH
+# define INT_LEAST64_WIDTH UINT_LEAST64_WIDTH
+# define UINT_FAST64_WIDTH __UINT_LEAST64_WIDTH
+# define INT_FAST64_WIDTH UINT_FAST64_WIDTH
+#endif /* __STDC_VERSION__ */
#endif /* __INT_LEAST64_MIN */
@@ -495,6 +516,7 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# define INT_FAST56_MIN INT56_MIN
# define INT_FAST56_MAX INT56_MAX
# define UINT_FAST56_MAX UINT56_MAX
+
# define __INT_LEAST32_MIN INT56_MIN
# define __INT_LEAST32_MAX INT56_MAX
# define __UINT_LEAST32_MAX UINT56_MAX
@@ -504,6 +526,20 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# define __INT_LEAST8_MIN INT56_MIN
# define __INT_LEAST8_MAX INT56_MAX
# define __UINT_LEAST8_MAX UINT56_MAX
+
+/* FIXME: This is using the placeholder dates Clang produces for these macros
+ in C2x mode; switch to the correct values once they've been published. */
+#if __STDC_VERSION__ >= 202000L
+# define UINT56_WIDTH 56
+# define INT56_WIDTH UINT56_WIDTH
+# define UINT_LEAST56_WIDTH UINT56_WIDTH
+# define INT_LEAST56_WIDTH UINT_LEAST56_WIDTH
+# define UINT_FAST56_WIDTH UINT56_WIDTH
+# define INT_FAST56_WIDTH UINT_FAST56_WIDTH
+# define __UINT_LEAST32_WIDTH UINT56_WIDTH
+# define __UINT_LEAST16_WIDTH UINT56_WIDTH
+# define __UINT_LEAST8_WIDTH UINT56_WIDTH
+#endif /* __STDC_VERSION__ */
#endif /* __INT56_TYPE__ */
@@ -517,6 +553,7 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# define INT_FAST48_MIN INT48_MIN
# define INT_FAST48_MAX INT48_MAX
# define UINT_FAST48_MAX UINT48_MAX
+
# define __INT_LEAST32_MIN INT48_MIN
# define __INT_LEAST32_MAX INT48_MAX
# define __UINT_LEAST32_MAX UINT48_MAX
@@ -526,6 +563,20 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# define __INT_LEAST8_MIN INT48_MIN
# define __INT_LEAST8_MAX INT48_MAX
# define __UINT_LEAST8_MAX UINT48_MAX
+
+/* FIXME: This is using the placeholder dates Clang produces for these macros
+ in C2x mode; switch to the correct values once they've been published. */
+#if __STDC_VERSION__ >= 202000L
+#define UINT48_WIDTH 48
+#define INT48_WIDTH UINT48_WIDTH
+#define UINT_LEAST48_WIDTH UINT48_WIDTH
+#define INT_LEAST48_WIDTH UINT_LEAST48_WIDTH
+#define UINT_FAST48_WIDTH UINT48_WIDTH
+#define INT_FAST48_WIDTH UINT_FAST48_WIDTH
+#define __UINT_LEAST32_WIDTH UINT48_WIDTH
+#define __UINT_LEAST16_WIDTH UINT48_WIDTH
+#define __UINT_LEAST8_WIDTH UINT48_WIDTH
+#endif /* __STDC_VERSION__ */
#endif /* __INT48_TYPE__ */
@@ -539,6 +590,7 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# define INT_FAST40_MIN INT40_MIN
# define INT_FAST40_MAX INT40_MAX
# define UINT_FAST40_MAX UINT40_MAX
+
# define __INT_LEAST32_MIN INT40_MIN
# define __INT_LEAST32_MAX INT40_MAX
# define __UINT_LEAST32_MAX UINT40_MAX
@@ -548,6 +600,20 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# define __INT_LEAST8_MIN INT40_MIN
# define __INT_LEAST8_MAX INT40_MAX
# define __UINT_LEAST8_MAX UINT40_MAX
+
+/* FIXME: This is using the placeholder dates Clang produces for these macros
+ in C2x mode; switch to the correct values once they've been published. */
+#if __STDC_VERSION__ >= 202000L
+# define UINT40_WIDTH 40
+# define INT40_WIDTH UINT40_WIDTH
+# define UINT_LEAST40_WIDTH UINT40_WIDTH
+# define INT_LEAST40_WIDTH UINT_LEAST40_WIDTH
+# define UINT_FAST40_WIDTH UINT40_WIDTH
+# define INT_FAST40_WIDTH UINT_FAST40_WIDTH
+# define __UINT_LEAST32_WIDTH UINT40_WIDTH
+# define __UINT_LEAST16_WIDTH UINT40_WIDTH
+# define __UINT_LEAST8_WIDTH UINT40_WIDTH
+#endif /* __STDC_VERSION__ */
#endif /* __INT40_TYPE__ */
@@ -555,6 +621,7 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# define INT32_MAX INT32_C(2147483647)
# define INT32_MIN (-INT32_C(2147483647)-1)
# define UINT32_MAX UINT32_C(4294967295)
+
# define __INT_LEAST32_MIN INT32_MIN
# define __INT_LEAST32_MAX INT32_MAX
# define __UINT_LEAST32_MAX UINT32_MAX
@@ -564,6 +631,16 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# define __INT_LEAST8_MIN INT32_MIN
# define __INT_LEAST8_MAX INT32_MAX
# define __UINT_LEAST8_MAX UINT32_MAX
+
+/* FIXME: This is using the placeholder dates Clang produces for these macros
+ in C2x mode; switch to the correct values once they've been published. */
+#if __STDC_VERSION__ >= 202000L
+# define UINT32_WIDTH 32
+# define INT32_WIDTH UINT32_WIDTH
+# define __UINT_LEAST32_WIDTH UINT32_WIDTH
+# define __UINT_LEAST16_WIDTH UINT32_WIDTH
+# define __UINT_LEAST8_WIDTH UINT32_WIDTH
+#endif /* __STDC_VERSION__ */
#endif /* __INT32_TYPE__ */
#ifdef __INT_LEAST32_MIN
@@ -573,6 +650,15 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# define INT_FAST32_MIN __INT_LEAST32_MIN
# define INT_FAST32_MAX __INT_LEAST32_MAX
# define UINT_FAST32_MAX __UINT_LEAST32_MAX
+
+/* FIXME: This is using the placeholder dates Clang produces for these macros
+ in C2x mode; switch to the correct values once they've been published. */
+#if __STDC_VERSION__ >= 202000L
+# define UINT_LEAST32_WIDTH __UINT_LEAST32_WIDTH
+# define INT_LEAST32_WIDTH UINT_LEAST32_WIDTH
+# define UINT_FAST32_WIDTH __UINT_LEAST32_WIDTH
+# define INT_FAST32_WIDTH UINT_FAST32_WIDTH
+#endif /* __STDC_VERSION__ */
#endif /* __INT_LEAST32_MIN */
@@ -586,12 +672,26 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# define INT_FAST24_MIN INT24_MIN
# define INT_FAST24_MAX INT24_MAX
# define UINT_FAST24_MAX UINT24_MAX
+
# define __INT_LEAST16_MIN INT24_MIN
# define __INT_LEAST16_MAX INT24_MAX
# define __UINT_LEAST16_MAX UINT24_MAX
# define __INT_LEAST8_MIN INT24_MIN
# define __INT_LEAST8_MAX INT24_MAX
# define __UINT_LEAST8_MAX UINT24_MAX
+
+/* FIXME: This is using the placeholder dates Clang produces for these macros
+ in C2x mode; switch to the correct values once they've been published. */
+#if __STDC_VERSION__ >= 202000L
+# define UINT24_WIDTH 24
+# define INT24_WIDTH UINT24_WIDTH
+# define UINT_LEAST24_WIDTH UINT24_WIDTH
+# define INT_LEAST24_WIDTH UINT_LEAST24_WIDTH
+# define UINT_FAST24_WIDTH UINT24_WIDTH
+# define INT_FAST24_WIDTH UINT_FAST24_WIDTH
+# define __UINT_LEAST16_WIDTH UINT24_WIDTH
+# define __UINT_LEAST8_WIDTH UINT24_WIDTH
+#endif /* __STDC_VERSION__ */
#endif /* __INT24_TYPE__ */
@@ -599,12 +699,22 @@ typedef __UINTMAX_TYPE__ uintmax_t;
#define INT16_MAX INT16_C(32767)
#define INT16_MIN (-INT16_C(32767)-1)
#define UINT16_MAX UINT16_C(65535)
+
# define __INT_LEAST16_MIN INT16_MIN
# define __INT_LEAST16_MAX INT16_MAX
# define __UINT_LEAST16_MAX UINT16_MAX
# define __INT_LEAST8_MIN INT16_MIN
# define __INT_LEAST8_MAX INT16_MAX
# define __UINT_LEAST8_MAX UINT16_MAX
+
+/* FIXME: This is using the placeholder dates Clang produces for these macros
+ in C2x mode; switch to the correct values once they've been published. */
+#if __STDC_VERSION__ >= 202000L
+# define UINT16_WIDTH 16
+# define INT16_WIDTH UINT16_WIDTH
+# define __UINT_LEAST16_WIDTH UINT16_WIDTH
+# define __UINT_LEAST8_WIDTH UINT16_WIDTH
+#endif /* __STDC_VERSION__ */
#endif /* __INT16_TYPE__ */
#ifdef __INT_LEAST16_MIN
@@ -614,6 +724,15 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# define INT_FAST16_MIN __INT_LEAST16_MIN
# define INT_FAST16_MAX __INT_LEAST16_MAX
# define UINT_FAST16_MAX __UINT_LEAST16_MAX
+
+/* FIXME: This is using the placeholder dates Clang produces for these macros
+ in C2x mode; switch to the correct values once they've been published. */
+#if __STDC_VERSION__ >= 202000L
+# define UINT_LEAST16_WIDTH __UINT_LEAST16_WIDTH
+# define INT_LEAST16_WIDTH UINT_LEAST16_WIDTH
+# define UINT_FAST16_WIDTH __UINT_LEAST16_WIDTH
+# define INT_FAST16_WIDTH UINT_FAST16_WIDTH
+#endif /* __STDC_VERSION__ */
#endif /* __INT_LEAST16_MIN */
@@ -621,9 +740,18 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# define INT8_MAX INT8_C(127)
# define INT8_MIN (-INT8_C(127)-1)
# define UINT8_MAX UINT8_C(255)
+
# define __INT_LEAST8_MIN INT8_MIN
# define __INT_LEAST8_MAX INT8_MAX
# define __UINT_LEAST8_MAX UINT8_MAX
+
+/* FIXME: This is using the placeholder dates Clang produces for these macros
+ in C2x mode; switch to the correct values once they've been published. */
+#if __STDC_VERSION__ >= 202000L
+# define UINT8_WIDTH 8
+# define INT8_WIDTH UINT8_WIDTH
+# define __UINT_LEAST8_WIDTH UINT8_WIDTH
+#endif /* __STDC_VERSION__ */
#endif /* __INT8_TYPE__ */
#ifdef __INT_LEAST8_MIN
@@ -633,6 +761,15 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# define INT_FAST8_MIN __INT_LEAST8_MIN
# define INT_FAST8_MAX __INT_LEAST8_MAX
# define UINT_FAST8_MAX __UINT_LEAST8_MAX
+
+/* FIXME: This is using the placeholder dates Clang produces for these macros
+ in C2x mode; switch to the correct values once they've been published. */
+#if __STDC_VERSION__ >= 202000L
+# define UINT_LEAST8_WIDTH __UINT_LEAST8_WIDTH
+# define INT_LEAST8_WIDTH UINT_LEAST8_WIDTH
+# define UINT_FAST8_WIDTH __UINT_LEAST8_WIDTH
+# define INT_FAST8_WIDTH UINT_FAST8_WIDTH
+#endif /* __STDC_VERSION__ */
#endif /* __INT_LEAST8_MIN */
/* Some utility macros */
@@ -652,6 +789,16 @@ typedef __UINTMAX_TYPE__ uintmax_t;
#define PTRDIFF_MAX __PTRDIFF_MAX__
#define SIZE_MAX __SIZE_MAX__
+/* C2x 7.20.2.4 Width of integer types capable of holding object pointers. */
+/* FIXME: This is using the placeholder dates Clang produces for these macros
+ in C2x mode; switch to the correct values once they've been published. */
+#if __STDC_VERSION__ >= 202000L
+/* NB: The C standard requires that these be the same value, but the compiler
+ exposes separate internal width macros. */
+#define INTPTR_WIDTH __INTPTR_WIDTH__
+#define UINTPTR_WIDTH __UINTPTR_WIDTH__
+#endif
+
/* ISO9899:2011 7.20 (C11 Annex K): Define RSIZE_MAX if __STDC_WANT_LIB_EXT1__
* is enabled. */
#if defined(__STDC_WANT_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__ >= 1
@@ -663,6 +810,16 @@ typedef __UINTMAX_TYPE__ uintmax_t;
#define INTMAX_MAX __INTMAX_MAX__
#define UINTMAX_MAX __UINTMAX_MAX__
+/* C2x 7.20.2.5 Width of greatest-width integer types. */
+/* FIXME: This is using the placeholder dates Clang produces for these macros
+ in C2x mode; switch to the correct values once they've been published. */
+#if __STDC_VERSION__ >= 202000L
+/* NB: The C standard requires that these be the same value, but the compiler
+ exposes separate internal width macros. */
+#define INTMAX_WIDTH __INTMAX_WIDTH__
+#define UINTMAX_WIDTH __UINTMAX_WIDTH__
+#endif
+
/* C99 7.18.3 Limits of other integer types. */
#define SIG_ATOMIC_MIN __INTN_MIN(__SIG_ATOMIC_WIDTH__)
#define SIG_ATOMIC_MAX __INTN_MAX(__SIG_ATOMIC_WIDTH__)
@@ -689,5 +846,16 @@ typedef __UINTMAX_TYPE__ uintmax_t;
#define INTMAX_C(v) __int_c(v, __INTMAX_C_SUFFIX__)
#define UINTMAX_C(v) __int_c(v, __UINTMAX_C_SUFFIX__)
+/* C2x 7.20.3.x Width of other integer types. */
+/* FIXME: This is using the placeholder dates Clang produces for these macros
+ in C2x mode; switch to the correct values once they've been published. */
+#if __STDC_VERSION__ >= 202000L
+#define PTRDIFF_WIDTH __PTRDIFF_WIDTH__
+#define SIG_ATOMIC_WIDTH __SIG_ATOMIC_WIDTH__
+#define SIZE_WIDTH __SIZE_WIDTH__
+#define WCHAR_WIDTH __WCHAR_WIDTH__
+#define WINT_WIDTH __WINT_WIDTH__
+#endif
+
#endif /* __STDC_HOSTED__ */
#endif /* __CLANG_STDINT_H */
diff --git a/clang/lib/Headers/tmmintrin.h b/clang/lib/Headers/tmmintrin.h
index bcffa8187801..cb9be2349de5 100644
--- a/clang/lib/Headers/tmmintrin.h
+++ b/clang/lib/Headers/tmmintrin.h
@@ -53,7 +53,7 @@ _mm_abs_pi8(__m64 __a)
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_abs_epi8(__m128i __a)
{
- return (__m128i)__builtin_ia32_pabsb128((__v16qi)__a);
+ return (__m128i)__builtin_elementwise_abs((__v16qs)__a);
}
/// Computes the absolute value of each of the packed 16-bit signed
@@ -89,7 +89,7 @@ _mm_abs_pi16(__m64 __a)
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_abs_epi16(__m128i __a)
{
- return (__m128i)__builtin_ia32_pabsw128((__v8hi)__a);
+ return (__m128i)__builtin_elementwise_abs((__v8hi)__a);
}
/// Computes the absolute value of each of the packed 32-bit signed
@@ -125,7 +125,7 @@ _mm_abs_pi32(__m64 __a)
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_abs_epi32(__m128i __a)
{
- return (__m128i)__builtin_ia32_pabsd128((__v4si)__a);
+ return (__m128i)__builtin_elementwise_abs((__v4si)__a);
}
/// Concatenates the two 128-bit integer vector operands, and
diff --git a/clang/lib/Headers/vaesintrin.h b/clang/lib/Headers/vaesintrin.h
index f3c0807bb94a..294dcff2addd 100644
--- a/clang/lib/Headers/vaesintrin.h
+++ b/clang/lib/Headers/vaesintrin.h
@@ -82,4 +82,4 @@ static __inline__ __m512i __DEFAULT_FN_ATTRS_F
#undef __DEFAULT_FN_ATTRS
#undef __DEFAULT_FN_ATTRS_F
-#endif
+#endif // __VAESINTRIN_H
diff --git a/clang/lib/Interpreter/IncrementalParser.cpp b/clang/lib/Interpreter/IncrementalParser.cpp
index 84eabc3a210f..4ade8b8bb074 100644
--- a/clang/lib/Interpreter/IncrementalParser.cpp
+++ b/clang/lib/Interpreter/IncrementalParser.cpp
@@ -256,7 +256,7 @@ IncrementalParser::Parse(llvm::StringRef input) {
/*LoadedOffset=*/0, NewLoc);
// NewLoc only used for diags.
- if (PP.EnterSourceFile(FID, /*DirLookup=*/0, NewLoc))
+ if (PP.EnterSourceFile(FID, /*DirLookup=*/nullptr, NewLoc))
return llvm::make_error<llvm::StringError>("Parsing failed. "
"Cannot enter source file.",
std::error_code());
diff --git a/clang/lib/Interpreter/IncrementalParser.h b/clang/lib/Interpreter/IncrementalParser.h
index e5ce798025d9..d1f454f21239 100644
--- a/clang/lib/Interpreter/IncrementalParser.h
+++ b/clang/lib/Interpreter/IncrementalParser.h
@@ -30,9 +30,6 @@ class LLVMContext;
namespace clang {
class ASTConsumer;
class CompilerInstance;
-class CodeGenerator;
-class DeclGroupRef;
-class FrontendAction;
class IncrementalAction;
class Parser;
diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp
index a0b60118a1a8..39c125c395ef 100644
--- a/clang/lib/Lex/HeaderSearch.cpp
+++ b/clang/lib/Lex/HeaderSearch.cpp
@@ -29,6 +29,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Capacity.h"
#include "llvm/Support/Errc.h"
@@ -89,16 +90,10 @@ HeaderSearch::HeaderSearch(std::shared_ptr<HeaderSearchOptions> HSOpts,
void HeaderSearch::PrintStats() {
llvm::errs() << "\n*** HeaderSearch Stats:\n"
<< FileInfo.size() << " files tracked.\n";
- unsigned NumOnceOnlyFiles = 0, MaxNumIncludes = 0, NumSingleIncludedFiles = 0;
- for (unsigned i = 0, e = FileInfo.size(); i != e; ++i) {
+ unsigned NumOnceOnlyFiles = 0;
+ for (unsigned i = 0, e = FileInfo.size(); i != e; ++i)
NumOnceOnlyFiles += (FileInfo[i].isPragmaOnce || FileInfo[i].isImport);
- if (MaxNumIncludes < FileInfo[i].NumIncludes)
- MaxNumIncludes = FileInfo[i].NumIncludes;
- NumSingleIncludedFiles += FileInfo[i].NumIncludes == 1;
- }
- llvm::errs() << " " << NumOnceOnlyFiles << " #import/#pragma once files.\n"
- << " " << NumSingleIncludedFiles << " included exactly once.\n"
- << " " << MaxNumIncludes << " max times a file is included.\n";
+ llvm::errs() << " " << NumOnceOnlyFiles << " #import/#pragma once files.\n";
llvm::errs() << " " << NumIncluded << " #include/#include_next/#import.\n"
<< " " << NumMultiIncludeFileOptzn
@@ -108,6 +103,30 @@ void HeaderSearch::PrintStats() {
<< NumSubFrameworkLookups << " subframework lookups.\n";
}
+void HeaderSearch::SetSearchPaths(
+ std::vector<DirectoryLookup> dirs, unsigned int angledDirIdx,
+ unsigned int systemDirIdx, bool noCurDirSearch,
+ llvm::DenseMap<unsigned int, unsigned int> searchDirToHSEntry) {
+ assert(angledDirIdx <= systemDirIdx && systemDirIdx <= dirs.size() &&
+ "Directory indices are unordered");
+ SearchDirs = std::move(dirs);
+ SearchDirsUsage.assign(SearchDirs.size(), false);
+ AngledDirIdx = angledDirIdx;
+ SystemDirIdx = systemDirIdx;
+ NoCurDirSearch = noCurDirSearch;
+ SearchDirToHSEntry = std::move(searchDirToHSEntry);
+ //LookupFileCache.clear();
+}
+
+void HeaderSearch::AddSearchPath(const DirectoryLookup &dir, bool isAngled) {
+ unsigned idx = isAngled ? SystemDirIdx : AngledDirIdx;
+ SearchDirs.insert(SearchDirs.begin() + idx, dir);
+ SearchDirsUsage.insert(SearchDirsUsage.begin() + idx, false);
+ if (!isAngled)
+ AngledDirIdx++;
+ SystemDirIdx++;
+}
+
std::vector<bool> HeaderSearch::computeUserEntryUsage() const {
std::vector<bool> UserEntryUsage(HSOpts->UserEntries.size());
for (unsigned I = 0, E = SearchDirsUsage.size(); I < E; ++I) {
@@ -720,7 +739,8 @@ static const char *copyString(StringRef Str, llvm::BumpPtrAllocator &Alloc) {
}
static bool isFrameworkStylePath(StringRef Path, bool &IsPrivateHeader,
- SmallVectorImpl<char> &FrameworkName) {
+ SmallVectorImpl<char> &FrameworkName,
+ SmallVectorImpl<char> &IncludeSpelling) {
using namespace llvm::sys;
path::const_iterator I = path::begin(Path);
path::const_iterator E = path::end(Path);
@@ -736,15 +756,22 @@ static bool isFrameworkStylePath(StringRef Path, bool &IsPrivateHeader,
// and some other variations among these lines.
int FoundComp = 0;
while (I != E) {
- if (*I == "Headers")
+ if (*I == "Headers") {
++FoundComp;
- if (I->endswith(".framework")) {
- FrameworkName.append(I->begin(), I->end());
- ++FoundComp;
- }
- if (*I == "PrivateHeaders") {
+ } else if (*I == "PrivateHeaders") {
++FoundComp;
IsPrivateHeader = true;
+ } else if (I->endswith(".framework")) {
+ StringRef Name = I->drop_back(10); // Drop .framework
+ // Need to reset the strings and counter to support nested frameworks.
+ FrameworkName.clear();
+ FrameworkName.append(Name.begin(), Name.end());
+ IncludeSpelling.clear();
+ IncludeSpelling.append(Name.begin(), Name.end());
+ FoundComp = 1;
+ } else if (FoundComp >= 2) {
+ IncludeSpelling.push_back('/');
+ IncludeSpelling.append(I->begin(), I->end());
}
++I;
}
@@ -759,20 +786,24 @@ diagnoseFrameworkInclude(DiagnosticsEngine &Diags, SourceLocation IncludeLoc,
bool FoundByHeaderMap = false) {
bool IsIncluderPrivateHeader = false;
SmallString<128> FromFramework, ToFramework;
- if (!isFrameworkStylePath(Includer, IsIncluderPrivateHeader, FromFramework))
+ SmallString<128> FromIncludeSpelling, ToIncludeSpelling;
+ if (!isFrameworkStylePath(Includer, IsIncluderPrivateHeader, FromFramework,
+ FromIncludeSpelling))
return;
bool IsIncludeePrivateHeader = false;
- bool IsIncludeeInFramework = isFrameworkStylePath(
- IncludeFE->getName(), IsIncludeePrivateHeader, ToFramework);
+ bool IsIncludeeInFramework =
+ isFrameworkStylePath(IncludeFE->getName(), IsIncludeePrivateHeader,
+ ToFramework, ToIncludeSpelling);
if (!isAngled && !FoundByHeaderMap) {
SmallString<128> NewInclude("<");
if (IsIncludeeInFramework) {
- NewInclude += ToFramework.str().drop_back(10); // drop .framework
- NewInclude += "/";
+ NewInclude += ToIncludeSpelling;
+ NewInclude += ">";
+ } else {
+ NewInclude += IncludeFilename;
+ NewInclude += ">";
}
- NewInclude += IncludeFilename;
- NewInclude += ">";
Diags.Report(IncludeLoc, diag::warn_quoted_include_in_framework_header)
<< IncludeFilename
<< FixItHint::CreateReplacement(IncludeLoc, NewInclude);
@@ -794,12 +825,15 @@ diagnoseFrameworkInclude(DiagnosticsEngine &Diags, SourceLocation IncludeLoc,
/// search is needed. Microsoft mode will pass all \#including files.
Optional<FileEntryRef> HeaderSearch::LookupFile(
StringRef Filename, SourceLocation IncludeLoc, bool isAngled,
- const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir,
+ const DirectoryLookup *FromDir, const DirectoryLookup **CurDirArg,
ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers,
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule,
bool *IsMapped, bool *IsFrameworkFound, bool SkipCache,
bool BuildSystemModule) {
+ const DirectoryLookup *CurDirLocal = nullptr;
+ const DirectoryLookup *&CurDir = CurDirArg ? *CurDirArg : CurDirLocal;
+
if (IsMapped)
*IsMapped = false;
@@ -1046,7 +1080,7 @@ Optional<FileEntryRef> HeaderSearch::LookupFile(
ScratchFilename += Filename;
Optional<FileEntryRef> File = LookupFile(
- ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir, CurDir,
+ ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir, &CurDir,
Includers.front(), SearchPath, RelativePath, RequestingModule,
SuggestedModule, IsMapped, /*IsFrameworkFound=*/nullptr);
@@ -1203,7 +1237,6 @@ static void mergeHeaderFileInfo(HeaderFileInfo &HFI,
HFI.isImport |= OtherHFI.isImport;
HFI.isPragmaOnce |= OtherHFI.isPragmaOnce;
HFI.isModuleHeader |= OtherHFI.isModuleHeader;
- HFI.NumIncludes += OtherHFI.NumIncludes;
if (!HFI.ControllingMacro && !HFI.ControllingMacroID) {
HFI.ControllingMacro = OtherHFI.ControllingMacro;
@@ -1364,7 +1397,7 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP,
FileInfo.isImport = true;
// Has this already been #import'ed or #include'd?
- if (FileInfo.NumIncludes && !TryEnterImported())
+ if (PP.alreadyIncluded(File) && !TryEnterImported())
return false;
} else {
// Otherwise, if this is a #include of a file that was previously #import'd
@@ -1387,10 +1420,7 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP,
}
}
- // Increment the number of times this file has been included.
- ++FileInfo.NumIncludes;
-
- IsFirstIncludeOfFile = FileInfo.NumIncludes == 1;
+ IsFirstIncludeOfFile = PP.markIncluded(File);
return true;
}
@@ -1779,11 +1809,8 @@ void HeaderSearch::collectAllModules(SmallVectorImpl<Module *> &Modules) {
}
// Populate the list of modules.
- for (ModuleMap::module_iterator M = ModMap.module_begin(),
- MEnd = ModMap.module_end();
- M != MEnd; ++M) {
- Modules.push_back(M->getValue());
- }
+ llvm::transform(ModMap.modules(), std::back_inserter(Modules),
+ [](const auto &NameAndMod) { return NameAndMod.second; });
}
void HeaderSearch::loadTopLevelSystemModules() {
@@ -1843,9 +1870,9 @@ std::string HeaderSearch::suggestPathToFileForDiagnostics(
using namespace llvm::sys;
unsigned BestPrefixLength = 0;
- // Checks whether Dir and File shares a common prefix, if they do and that's
- // the longest prefix we've seen so for it returns true and updates the
- // BestPrefixLength accordingly.
+ // Checks whether `Dir` is a strict path prefix of `File`. If so and that's
+ // the longest prefix we've seen so for it, returns true and updates the
+ // `BestPrefixLength` accordingly.
auto CheckDir = [&](llvm::StringRef Dir) -> bool {
llvm::SmallString<32> DirPath(Dir.begin(), Dir.end());
if (!WorkingDir.empty() && !path::is_absolute(Dir))
@@ -1880,26 +1907,48 @@ std::string HeaderSearch::suggestPathToFileForDiagnostics(
path::is_separator(NI->front()) && path::is_separator(DI->front()))
continue;
+ // Special case Apple .sdk folders since the search path is typically a
+ // symlink like `iPhoneSimulator14.5.sdk` while the file is instead
+ // located in `iPhoneSimulator.sdk` (the real folder).
+ if (NI->endswith(".sdk") && DI->endswith(".sdk")) {
+ StringRef NBasename = path::stem(*NI);
+ StringRef DBasename = path::stem(*DI);
+ if (DBasename.startswith(NBasename))
+ continue;
+ }
+
if (*NI != *DI)
break;
}
return false;
};
+ bool BestPrefixIsFramework = false;
for (unsigned I = 0; I != SearchDirs.size(); ++I) {
- // FIXME: Support this search within frameworks.
- if (!SearchDirs[I].isNormalDir())
- continue;
-
- StringRef Dir = SearchDirs[I].getDir()->getName();
- if (CheckDir(Dir) && IsSystem)
- *IsSystem = BestPrefixLength ? I >= SystemDirIdx : false;
+ if (SearchDirs[I].isNormalDir()) {
+ StringRef Dir = SearchDirs[I].getDir()->getName();
+ if (CheckDir(Dir)) {
+ if (IsSystem)
+ *IsSystem = BestPrefixLength ? I >= SystemDirIdx : false;
+ BestPrefixIsFramework = false;
+ }
+ } else if (SearchDirs[I].isFramework()) {
+ StringRef Dir = SearchDirs[I].getFrameworkDir()->getName();
+ if (CheckDir(Dir)) {
+ if (IsSystem)
+ *IsSystem = BestPrefixLength ? I >= SystemDirIdx : false;
+ BestPrefixIsFramework = true;
+ }
+ }
}
// Try to shorten include path using TUs directory, if we couldn't find any
// suitable prefix in include search paths.
- if (!BestPrefixLength && CheckDir(path::parent_path(MainFile)) && IsSystem)
- *IsSystem = false;
+ if (!BestPrefixLength && CheckDir(path::parent_path(MainFile))) {
+ if (IsSystem)
+ *IsSystem = false;
+ BestPrefixIsFramework = false;
+ }
// Try resolving resulting filename via reverse search in header maps,
// key from header name is user prefered name for the include file.
@@ -1912,8 +1961,19 @@ std::string HeaderSearch::suggestPathToFileForDiagnostics(
SearchDirs[I].getHeaderMap()->reverseLookupFilename(Filename);
if (!SpelledFilename.empty()) {
Filename = SpelledFilename;
+ BestPrefixIsFramework = false;
break;
}
}
+
+ // If the best prefix is a framework path, we need to compute the proper
+ // include spelling for the framework header.
+ bool IsPrivateHeader;
+ SmallString<128> FrameworkName, IncludeSpelling;
+ if (BestPrefixIsFramework &&
+ isFrameworkStylePath(Filename, IsPrivateHeader, FrameworkName,
+ IncludeSpelling)) {
+ Filename = IncludeSpelling;
+ }
return path::convert_to_slash(Filename);
}
diff --git a/clang/lib/Frontend/InitHeaderSearch.cpp b/clang/lib/Lex/InitHeaderSearch.cpp
index ed1314f3b03d..ec7b1505c7bf 100644
--- a/clang/lib/Frontend/InitHeaderSearch.cpp
+++ b/clang/lib/Lex/InitHeaderSearch.cpp
@@ -10,11 +10,10 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/DiagnosticFrontend.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Config/config.h" // C_INCLUDE_DIRS
-#include "clang/Frontend/FrontendDiagnostic.h"
-#include "clang/Frontend/Utils.h"
#include "clang/Lex/HeaderMap.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/HeaderSearchOptions.h"
@@ -354,7 +353,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
break;
case llvm::Triple::PS4: {
// <isysroot> gets prepended later in AddPath().
- std::string BaseSDKPath = "";
+ std::string BaseSDKPath;
if (!HasSysroot) {
const char *envValue = getenv("SCE_ORBIS_SDK_DIR");
if (envValue)
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 38467a1835d0..89e89c7c1f17 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -2548,9 +2548,9 @@ static bool isEndOfBlockCommentWithEscapedNewLine(const char *CurPtr,
assert(CurPtr[0] == '\n' || CurPtr[0] == '\r');
// Position of the first trigraph in the ending sequence.
- const char *TrigraphPos = 0;
+ const char *TrigraphPos = nullptr;
// Position of the first whitespace after a '\' in the ending sequence.
- const char *SpacePos = 0;
+ const char *SpacePos = nullptr;
while (true) {
// Back up off the newline.
diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index ef7a5351953e..f3aefdd22b51 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -818,10 +818,13 @@ Preprocessor::getHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
Optional<FileEntryRef> Preprocessor::LookupFile(
SourceLocation FilenameLoc, StringRef Filename, bool isAngled,
const DirectoryLookup *FromDir, const FileEntry *FromFile,
- const DirectoryLookup *&CurDir, SmallVectorImpl<char> *SearchPath,
+ const DirectoryLookup **CurDirArg, SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
ModuleMap::KnownHeader *SuggestedModule, bool *IsMapped,
bool *IsFrameworkFound, bool SkipCache) {
+ const DirectoryLookup *CurDirLocal = nullptr;
+ const DirectoryLookup *&CurDir = CurDirArg ? *CurDirArg : CurDirLocal;
+
Module *RequestingModule = getModuleForLocation(FilenameLoc);
bool RequestingModuleIsModuleInterface = !SourceMgr.isInMainFile(FilenameLoc);
@@ -877,7 +880,7 @@ Optional<FileEntryRef> Preprocessor::LookupFile(
const DirectoryLookup *TmpCurDir = CurDir;
const DirectoryLookup *TmpFromDir = nullptr;
while (Optional<FileEntryRef> FE = HeaderInfo.LookupFile(
- Filename, FilenameLoc, isAngled, TmpFromDir, TmpCurDir,
+ Filename, FilenameLoc, isAngled, TmpFromDir, &TmpCurDir,
Includers, SearchPath, RelativePath, RequestingModule,
SuggestedModule, /*IsMapped=*/nullptr,
/*IsFrameworkFound=*/nullptr, SkipCache)) {
@@ -895,7 +898,7 @@ Optional<FileEntryRef> Preprocessor::LookupFile(
// Do a standard file entry lookup.
Optional<FileEntryRef> FE = HeaderInfo.LookupFile(
- Filename, FilenameLoc, isAngled, FromDir, CurDir, Includers, SearchPath,
+ Filename, FilenameLoc, isAngled, FromDir, &CurDir, Includers, SearchPath,
RelativePath, RequestingModule, SuggestedModule, IsMapped,
IsFrameworkFound, SkipCache, BuildSystemModule);
if (FE) {
@@ -1827,7 +1830,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
}
Optional<FileEntryRef> Preprocessor::LookupHeaderIncludeOrImport(
- const DirectoryLookup *&CurDir, StringRef& Filename,
+ const DirectoryLookup **CurDir, StringRef& Filename,
SourceLocation FilenameLoc, CharSourceRange FilenameRange,
const Token &FilenameTok, bool &IsFrameworkFound, bool IsImportDecl,
bool &IsMapped, const DirectoryLookup *LookupFrom,
@@ -2028,7 +2031,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
}
Optional<FileEntryRef> File = LookupHeaderIncludeOrImport(
- CurDir, Filename, FilenameLoc, FilenameRange, FilenameTok,
+ &CurDir, Filename, FilenameLoc, FilenameRange, FilenameTok,
IsFrameworkFound, IsImportDecl, IsMapped, LookupFrom, LookupFromFile,
LookupFilename, RelativePath, SearchPath, SuggestedModule, isAngled);
@@ -2055,7 +2058,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
// include cycle. Don't enter already processed files again as it can lead to
// reaching the max allowed include depth again.
if (Action == Enter && HasReachedMaxIncludeDepth && File &&
- HeaderInfo.getFileInfo(&File->getFileEntry()).NumIncludes)
+ alreadyIncluded(*File))
Action = IncludeLimitReached;
// Determine whether we should try to import the module for this #include, if
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp
index cfee7a3c2513..f6c95a8b67c6 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -1228,10 +1228,9 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
return false;
// Search include directories.
- const DirectoryLookup *CurDir;
Optional<FileEntryRef> File =
PP.LookupFile(FilenameLoc, Filename, isAngled, LookupFrom, LookupFromFile,
- CurDir, nullptr, nullptr, nullptr, nullptr, nullptr);
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
if (PPCallbacks *Callbacks = PP.getPPCallbacks()) {
SrcMgr::CharacteristicKind FileType = SrcMgr::C_User;
diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp
index 67daa5841983..eb7e7cbc4714 100644
--- a/clang/lib/Lex/Pragma.cpp
+++ b/clang/lib/Lex/Pragma.cpp
@@ -526,9 +526,8 @@ static llvm::Optional<Token> LexHeader(Preprocessor &PP,
return llvm::None;
// Search include directories for this file.
- const DirectoryLookup *CurDir;
File = PP.LookupFile(FilenameTok.getLocation(), Filename, isAngled, nullptr,
- nullptr, CurDir, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr);
if (!File) {
if (!SuppressIncludeNotFoundError)
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index b026ae36fc0f..3c338a2b8123 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -549,7 +549,7 @@ void Preprocessor::EnterMainSourceFile() {
// Tell the header info that the main file was entered. If the file is later
// #imported, it won't be re-entered.
if (const FileEntry *FE = SourceMgr.getFileEntryForID(MainFileID))
- HeaderInfo.IncrementIncludeCount(FE);
+ markIncluded(FE);
}
// Preprocess Predefines to populate the initial preprocessor state.
@@ -566,11 +566,10 @@ void Preprocessor::EnterMainSourceFile() {
if (!PPOpts->PCHThroughHeader.empty()) {
// Lookup and save the FileID for the through header. If it isn't found
// in the search path, it's a fatal error.
- const DirectoryLookup *CurDir;
Optional<FileEntryRef> File = LookupFile(
SourceLocation(), PPOpts->PCHThroughHeader,
- /*isAngled=*/false, /*FromDir=*/nullptr, /*FromFile=*/nullptr, CurDir,
- /*SearchPath=*/nullptr, /*RelativePath=*/nullptr,
+ /*isAngled=*/false, /*FromDir=*/nullptr, /*FromFile=*/nullptr,
+ /*CurDir=*/nullptr, /*SearchPath=*/nullptr, /*RelativePath=*/nullptr,
/*SuggestedModule=*/nullptr, /*IsMapped=*/nullptr,
/*IsFrameworkFound=*/nullptr);
if (!File) {
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index 19cddc69ebfc..7330c2b7593d 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -140,8 +140,22 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(
// function body.
if (ConsumeAndStoreFunctionPrologue(Toks)) {
// We didn't find the left-brace we expected after the
- // constructor initializer; we already printed an error, and it's likely
- // impossible to recover, so don't try to parse this method later.
+ // constructor initializer.
+
+ // If we're code-completing and the completion point was in the broken
+ // initializer, we want to parse it even though that will fail.
+ if (PP.isCodeCompletionEnabled() &&
+ llvm::any_of(Toks, [](const Token &Tok) {
+ return Tok.is(tok::code_completion);
+ })) {
+ // If we gave up at the completion point, the initializer list was
+ // likely truncated, so don't eat more tokens. We'll hit some extra
+ // errors, but they should be ignored in code completion.
+ return FnD;
+ }
+
+ // We already printed an error, and it's likely impossible to recover,
+ // so don't try to parse this method later.
// Skip over the rest of the decl and back to somewhere that looks
// reasonable.
SkipMalformedDecl();
@@ -803,7 +817,7 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
// We always want this function to consume at least one token if the first
// token isn't T and if not at EOF.
bool isFirstTokenConsumed = true;
- while (1) {
+ while (true) {
// If we found one of the tokens, stop and return true.
if (Tok.is(T1) || Tok.is(T2)) {
if (ConsumeFinalToken) {
@@ -1159,7 +1173,7 @@ bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks,
unsigned AngleCount = 0;
unsigned KnownTemplateCount = 0;
- while (1) {
+ while (true) {
switch (Tok.getKind()) {
case tok::comma:
// If we might be in a template, perform a tentative parse to check.
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 0c1f88bc51d1..f21938c81689 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2419,8 +2419,9 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
auto ThisVarDecl = dyn_cast_or_null<VarDecl>(ThisDecl);
auto RunSignatureHelp = [&]() {
QualType PreferredType = Actions.ProduceConstructorSignatureHelp(
- getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(),
- ThisDecl->getLocation(), Exprs, T.getOpenLocation());
+ ThisVarDecl->getType()->getCanonicalTypeInternal(),
+ ThisDecl->getLocation(), Exprs, T.getOpenLocation(),
+ /*Braced=*/false);
CalledSignatureHelp = true;
return PreferredType;
};
@@ -2439,8 +2440,9 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
if (ParseExpressionList(Exprs, CommaLocs, ExpressionStarts)) {
if (ThisVarDecl && PP.isCodeCompletionReached() && !CalledSignatureHelp) {
Actions.ProduceConstructorSignatureHelp(
- getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(),
- ThisDecl->getLocation(), Exprs, T.getOpenLocation());
+ ThisVarDecl->getType()->getCanonicalTypeInternal(),
+ ThisDecl->getLocation(), Exprs, T.getOpenLocation(),
+ /*Braced=*/false);
CalledSignatureHelp = true;
}
Actions.ActOnInitializerError(ThisDecl);
@@ -3078,7 +3080,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
ParsedAttributesWithRange attrs(AttrFactory);
// We use Sema's policy to get bool macros right.
PrintingPolicy Policy = Actions.getPrintingPolicy();
- while (1) {
+ while (true) {
bool isInvalid = false;
bool isStorageClass = false;
const char *PrevSpec = nullptr;
@@ -3574,12 +3576,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
}
}
ConsumedEnd = Tok.getLocation();
+ DS.setTypeofParensRange(Tracker.getRange());
// Even if something went wrong above, continue as if we've seen
// `decltype(auto)`.
isInvalid = DS.SetTypeSpecType(TST_decltype_auto, Loc, PrevSpec,
DiagID, TemplateId, Policy);
} else {
- isInvalid = DS.SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID,
+ isInvalid = DS.SetTypeSpecType(TST_auto, AutoLoc, PrevSpec, DiagID,
TemplateId, Policy);
}
break;
@@ -4269,7 +4272,7 @@ void Parser::ParseStructDeclaration(
// Read struct-declarators until we find the semicolon.
bool FirstDeclarator = true;
SourceLocation CommaLoc;
- while (1) {
+ while (true) {
ParsingFieldDeclarator DeclaratorInfo(*this, DS);
DeclaratorInfo.D.setCommaLoc(CommaLoc);
@@ -4536,7 +4539,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
CXXScopeSpec Spec;
if (ParseOptionalCXXScopeSpecifier(Spec, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
/*EnteringContext=*/true))
return;
@@ -5420,7 +5423,7 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide) {
// Parse the C++ scope specifier.
CXXScopeSpec SS;
if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
/*EnteringContext=*/true)) {
TPA.Revert();
return false;
@@ -5578,7 +5581,7 @@ void Parser::ParseTypeQualifierListOpt(
SourceLocation EndLoc;
- while (1) {
+ while (true) {
bool isInvalid = false;
const char *PrevSpec = nullptr;
unsigned DiagID = 0;
@@ -5802,7 +5805,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
D.getContext() == DeclaratorContext::Member;
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false, EnteringContext);
+ /*ObjectHasErrors=*/false, EnteringContext);
if (SS.isNotEmpty()) {
if (Tok.isNot(tok::star)) {
@@ -6031,7 +6034,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
D.getContext() == DeclaratorContext::Member;
ParseOptionalCXXScopeSpecifier(
D.getCXXScopeSpec(), /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false, EnteringContext);
+ /*ObjectHasErrors=*/false, EnteringContext);
}
if (D.getCXXScopeSpec().isValid()) {
@@ -6270,7 +6273,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
if (D.hasName() && !D.getNumTypeObjects())
MaybeParseCXX11Attributes(D);
- while (1) {
+ while (true) {
if (Tok.is(tok::l_paren)) {
bool IsFunctionDeclaration = D.isFunctionDeclaratorAFunctionDeclaration();
// Enter function-declaration scope, limiting any declarators to the
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index f5a6ffcff9e9..c08a586604b1 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -291,7 +291,7 @@ Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
CXXScopeSpec SS;
// Parse (optional) nested-name-specifier.
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
/*EnteringContext=*/false,
/*MayBePseudoDestructor=*/nullptr,
/*IsTypename=*/false,
@@ -529,7 +529,7 @@ Decl *Parser::ParseUsingDirective(DeclaratorContext Context,
CXXScopeSpec SS;
// Parse (optional) nested-name-specifier.
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
/*EnteringContext=*/false,
/*MayBePseudoDestructor=*/nullptr,
/*IsTypename=*/false,
@@ -598,7 +598,7 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context,
// Parse nested-name-specifier.
IdentifierInfo *LastII = nullptr;
if (ParseOptionalCXXScopeSpecifier(D.SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
/*EnteringContext=*/false,
/*MayBePseudoDtor=*/nullptr,
/*IsTypename=*/false,
@@ -1007,6 +1007,9 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
if (Tok.is(tok::annot_decltype)) {
Result = getExprAnnotation(Tok);
EndLoc = Tok.getAnnotationEndLoc();
+ // Unfortunately, we don't know the LParen source location as the annotated
+ // token doesn't have it.
+ DS.setTypeofParensRange(SourceRange(SourceLocation(), EndLoc));
ConsumeAnnotationToken();
if (Result.isInvalid()) {
DS.SetTypeSpecError();
@@ -1071,6 +1074,7 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
// Match the ')'
T.consumeClose();
+ DS.setTypeofParensRange(T.getRange());
if (T.getCloseLocation().isInvalid()) {
DS.SetTypeSpecError();
// FIXME: this should return the location of the last token
@@ -1190,7 +1194,7 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
// Parse optional nested-name-specifier
CXXScopeSpec SS;
if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
/*EnteringContext=*/false))
return true;
@@ -1609,7 +1613,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
CXXScopeSpec Spec;
bool HasValidSpec = true;
if (ParseOptionalCXXScopeSpecifier(Spec, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
EnteringContext)) {
DS.SetTypeSpecError();
HasValidSpec = false;
@@ -2605,7 +2609,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// Collect the scope specifier token we annotated earlier.
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
/*EnteringContext=*/false);
if (SS.isInvalid()) {
@@ -2905,7 +2909,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// member-declarator
// member-declarator-list ',' member-declarator
- while (1) {
+ while (true) {
InClassInitStyle HasInClassInit = ICIS_NoInit;
bool HasStaticInitializer = false;
if (Tok.isOneOf(tok::equal, tok::l_brace) && PureSpecLoc.isInvalid()) {
@@ -3674,7 +3678,7 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
// parse '::'[opt] nested-name-specifier[opt]
CXXScopeSpec SS;
if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
/*EnteringContext=*/false))
return true;
@@ -3740,8 +3744,8 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
if (TemplateTypeTy.isInvalid())
return QualType();
QualType PreferredType = Actions.ProduceCtorInitMemberSignatureHelp(
- getCurScope(), ConstructorDecl, SS, TemplateTypeTy.get(), ArgExprs, II,
- T.getOpenLocation());
+ ConstructorDecl, SS, TemplateTypeTy.get(), ArgExprs, II,
+ T.getOpenLocation(), /*Braced=*/false);
CalledSignatureHelp = true;
return PreferredType;
};
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 09a3842f5809..fbf79a0a8746 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -400,7 +400,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
SourceLocation ColonLoc;
auto SavedType = PreferredType;
- while (1) {
+ while (true) {
// Every iteration may rely on a preferred type for the whole expression.
PreferredType = SavedType;
// If this token has a lower precedence than we are allowed to parse (e.g.
@@ -1588,7 +1588,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
// cast expression.
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
/*EnteringContext=*/false);
AnnotateTemplateIdTokenAsType(SS);
return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr,
@@ -1853,7 +1853,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
// parsed, see if there are any postfix-expression pieces here.
SourceLocation Loc;
auto SavedType = PreferredType;
- while (1) {
+ while (true) {
// Each iteration relies on preferred type for the whole expression.
PreferredType = SavedType;
switch (Tok.getKind()) {
@@ -2019,7 +2019,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
CommaLocsTy CommaLocs;
auto RunSignatureHelp = [&]() -> QualType {
QualType PreferredType = Actions.ProduceCallSignatureHelp(
- getCurScope(), LHS.get(), ArgExprs, PT.getOpenLocation());
+ LHS.get(), ArgExprs, PT.getOpenLocation());
CalledSignatureHelp = true;
return PreferredType;
};
@@ -2558,7 +2558,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
Comps.back().LocStart = Comps.back().LocEnd = ConsumeToken();
// FIXME: This loop leaks the index expressions on error.
- while (1) {
+ while (true) {
if (Tok.is(tok::period)) {
// offsetof-member-designator: offsetof-member-designator '.' identifier
Comps.push_back(Sema::OffsetOfComponent());
@@ -3358,7 +3358,7 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
SmallVectorImpl<SourceLocation> &CommaLocs,
llvm::function_ref<void()> ExpressionStarts) {
bool SawError = false;
- while (1) {
+ while (true) {
if (ExpressionStarts)
ExpressionStarts();
@@ -3418,7 +3418,7 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
bool
Parser::ParseSimpleExpressionList(SmallVectorImpl<Expr*> &Exprs,
SmallVectorImpl<SourceLocation> &CommaLocs) {
- while (1) {
+ while (true) {
ExprResult Expr = ParseAssignmentExpression();
if (Expr.isInvalid())
return true;
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 76c510ddd36c..2d38891c723f 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -668,7 +668,7 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
//
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
/*EnteringContext=*/false);
Token Replacement;
@@ -1877,8 +1877,8 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
QualType PreferredType;
if (TypeRep)
PreferredType = Actions.ProduceConstructorSignatureHelp(
- getCurScope(), TypeRep.get()->getCanonicalTypeInternal(),
- DS.getEndLoc(), Exprs, T.getOpenLocation());
+ TypeRep.get()->getCanonicalTypeInternal(), DS.getEndLoc(), Exprs,
+ T.getOpenLocation(), /*Braced=*/false);
CalledSignatureHelp = true;
return PreferredType;
};
@@ -1953,6 +1953,9 @@ Parser::ParseAliasDeclarationInInitStatement(DeclaratorContext Context,
/// \param Loc The location of the start of the statement that requires this
/// condition, e.g., the "for" in a for loop.
///
+/// \param MissingOK Whether an empty condition is acceptable here. Otherwise
+/// it is considered an error to be recovered from.
+///
/// \param FRI If non-null, a for range declaration is permitted, and if
/// present will be parsed and stored here, and a null result will be returned.
///
@@ -1960,11 +1963,10 @@ Parser::ParseAliasDeclarationInInitStatement(DeclaratorContext Context,
/// appropriate moment for a 'for' loop.
///
/// \returns The parsed condition.
-Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt,
- SourceLocation Loc,
- Sema::ConditionKind CK,
- ForRangeInfo *FRI,
- bool EnterForConditionScope) {
+Sema::ConditionResult
+Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
+ Sema::ConditionKind CK, bool MissingOK,
+ ForRangeInfo *FRI, bool EnterForConditionScope) {
// Helper to ensure we always enter a continue/break scope if requested.
struct ForConditionScopeRAII {
Scope *S;
@@ -2019,7 +2021,7 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt,
}
ConsumeToken();
*InitStmt = Actions.ActOnNullStmt(SemiLoc);
- return ParseCXXCondition(nullptr, Loc, CK);
+ return ParseCXXCondition(nullptr, Loc, CK, MissingOK);
}
// Parse the expression.
@@ -2031,10 +2033,11 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt,
WarnOnInit();
*InitStmt = Actions.ActOnExprStmt(Expr.get());
ConsumeToken();
- return ParseCXXCondition(nullptr, Loc, CK);
+ return ParseCXXCondition(nullptr, Loc, CK, MissingOK);
}
- return Actions.ActOnCondition(getCurScope(), Loc, Expr.get(), CK);
+ return Actions.ActOnCondition(getCurScope(), Loc, Expr.get(), CK,
+ MissingOK);
}
case ConditionOrInitStatement::InitStmtDecl: {
@@ -2048,7 +2051,7 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt,
DG = ParseSimpleDeclaration(DeclaratorContext::SelectionInit, DeclEnd,
attrs, /*RequireSemi=*/true);
*InitStmt = Actions.ActOnDeclStmt(DG, DeclStart, DeclEnd);
- return ParseCXXCondition(nullptr, Loc, CK);
+ return ParseCXXCondition(nullptr, Loc, CK, MissingOK);
}
case ConditionOrInitStatement::ForRangeDecl: {
@@ -2454,8 +2457,8 @@ bool Parser::ParseUnqualifiedIdTemplateId(
// Parse the enclosed template argument list.
SourceLocation LAngleLoc, RAngleLoc;
TemplateArgList TemplateArgs;
- if (ParseTemplateIdAfterTemplateName(true, LAngleLoc, TemplateArgs,
- RAngleLoc))
+ if (ParseTemplateIdAfterTemplateName(true, LAngleLoc, TemplateArgs, RAngleLoc,
+ Template))
return true;
// If this is a non-template, we already issued a diagnostic.
@@ -3167,8 +3170,9 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
// `new decltype(invalid) (^)`.
if (TypeRep)
PreferredType = Actions.ProduceConstructorSignatureHelp(
- getCurScope(), TypeRep.get()->getCanonicalTypeInternal(),
- DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen);
+ TypeRep.get()->getCanonicalTypeInternal(),
+ DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen,
+ /*Braced=*/false);
CalledSignatureHelp = true;
return PreferredType;
};
@@ -3585,7 +3589,7 @@ ExprResult Parser::ParseRequiresExpression() {
// We need to consume the typename to allow 'requires { typename a; }'
SourceLocation TypenameKWLoc = ConsumeToken();
- if (TryAnnotateCXXScopeToken()) {
+ if (TryAnnotateOptionalCXXScopeToken()) {
TPA.Commit();
SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
break;
diff --git a/clang/lib/Parse/ParseInit.cpp b/clang/lib/Parse/ParseInit.cpp
index 9d9c03d28a97..fd0faba9c1c1 100644
--- a/clang/lib/Parse/ParseInit.cpp
+++ b/clang/lib/Parse/ParseInit.cpp
@@ -459,12 +459,22 @@ ExprResult Parser::ParseBraceInitializer() {
Actions, EnterExpressionEvaluationContext::InitList);
bool InitExprsOk = true;
- DesignatorCompletionInfo DesignatorCompletion{
- InitExprs,
- PreferredType.get(T.getOpenLocation()),
+ QualType LikelyType = PreferredType.get(T.getOpenLocation());
+ DesignatorCompletionInfo DesignatorCompletion{InitExprs, LikelyType};
+ bool CalledSignatureHelp = false;
+ auto RunSignatureHelp = [&] {
+ QualType PreferredType;
+ if (!LikelyType.isNull())
+ PreferredType = Actions.ProduceConstructorSignatureHelp(
+ LikelyType->getCanonicalTypeInternal(), T.getOpenLocation(),
+ InitExprs, T.getOpenLocation(), /*Braced=*/true);
+ CalledSignatureHelp = true;
+ return PreferredType;
};
- while (1) {
+ while (true) {
+ PreferredType.enterFunctionArgument(Tok.getLocation(), RunSignatureHelp);
+
// Handle Microsoft __if_exists/if_not_exists if necessary.
if (getLangOpts().MicrosoftExt && (Tok.is(tok::kw___if_exists) ||
Tok.is(tok::kw___if_not_exists))) {
diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp
index 9e145f57d61f..f493ac9b92ca 100644
--- a/clang/lib/Parse/ParseObjc.cpp
+++ b/clang/lib/Parse/ParseObjc.cpp
@@ -134,7 +134,7 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
SmallVector<SourceLocation, 8> ClassLocs;
SmallVector<ObjCTypeParamList *, 8> ClassTypeParams;
- while (1) {
+ while (true) {
MaybeSkipAttributes(tok::objc_class);
if (expectIdentifier()) {
SkipUntil(tok::semi);
@@ -598,7 +598,7 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
SourceRange AtEnd;
- while (1) {
+ while (true) {
// If this is a method prototype, parse it.
if (Tok.isOneOf(tok::minus, tok::plus)) {
if (Decl *methodPrototype =
@@ -848,7 +848,7 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
- while (1) {
+ while (true) {
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteObjCPropertyFlags(getCurScope(), DS);
@@ -1149,7 +1149,7 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
assert(Context == DeclaratorContext::ObjCParameter ||
Context == DeclaratorContext::ObjCResult);
- while (1) {
+ while (true) {
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteObjCPassingType(
@@ -1401,7 +1401,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
Scope::FunctionDeclarationScope | Scope::DeclScope);
AttributePool allParamAttrs(AttrFactory);
- while (1) {
+ while (true) {
ParsedAttributes paramAttrs(AttrFactory);
Sema::ObjCArgInfo ArgInfo;
@@ -1531,7 +1531,7 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
SmallVector<IdentifierLocPair, 8> ProtocolIdents;
- while (1) {
+ while (true) {
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents);
@@ -2050,7 +2050,7 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
ProtocolRefs.push_back(std::make_pair(protocolName, nameLoc));
// Parse the list of forward declarations.
- while (1) {
+ while (true) {
ConsumeToken(); // the ','
if (expectIdentifier()) {
SkipUntil(tok::semi);
@@ -3179,7 +3179,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
ExprVector KeyExprs;
if (Tok.is(tok::colon)) {
- while (1) {
+ while (true) {
// Each iteration parses a single keyword argument.
KeyIdents.push_back(selIdent);
KeyLocs.push_back(Loc);
@@ -3599,7 +3599,7 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
unsigned nColons = 0;
if (Tok.isNot(tok::r_paren)) {
- while (1) {
+ while (true) {
if (TryConsumeToken(tok::coloncolon)) { // Handle :: in C++.
++nColons;
KeyIdents.push_back(nullptr);
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 300b022d83b9..8ad5edb1bcd6 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -23,6 +23,7 @@
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/UniqueVector.h"
+#include "llvm/Frontend/OpenMP/OMPAssume.h"
#include "llvm/Frontend/OpenMP/OMPContext.h"
using namespace clang;
@@ -469,8 +470,8 @@ void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) {
SourceLocation LParLoc = T.getOpenLocation();
auto RunSignatureHelp = [this, OmpPrivParm, LParLoc, &Exprs]() {
QualType PreferredType = Actions.ProduceConstructorSignatureHelp(
- getCurScope(), OmpPrivParm->getType()->getCanonicalTypeInternal(),
- OmpPrivParm->getLocation(), Exprs, LParLoc);
+ OmpPrivParm->getType()->getCanonicalTypeInternal(),
+ OmpPrivParm->getLocation(), Exprs, LParLoc, /*Braced=*/false);
CalledSignatureHelp = true;
return PreferredType;
};
@@ -1813,38 +1814,55 @@ parseOpenMPSimpleClause(Parser &P, OpenMPClauseKind Kind) {
void Parser::ParseOMPDeclareTargetClauses(
Sema::DeclareTargetContextInfo &DTCI) {
SourceLocation DeviceTypeLoc;
- bool RequiresToOrLinkClause = false;
- bool HasToOrLinkClause = false;
+ bool RequiresToOrLinkOrIndirectClause = false;
+ bool HasToOrLinkOrIndirectClause = false;
while (Tok.isNot(tok::annot_pragma_openmp_end)) {
OMPDeclareTargetDeclAttr::MapTypeTy MT = OMPDeclareTargetDeclAttr::MT_To;
bool HasIdentifier = Tok.is(tok::identifier);
if (HasIdentifier) {
// If we see any clause we need a to or link clause.
- RequiresToOrLinkClause = true;
+ RequiresToOrLinkOrIndirectClause = true;
IdentifierInfo *II = Tok.getIdentifierInfo();
StringRef ClauseName = II->getName();
bool IsDeviceTypeClause =
getLangOpts().OpenMP >= 50 &&
getOpenMPClauseKind(ClauseName) == OMPC_device_type;
+ bool IsIndirectClause = getLangOpts().OpenMP >= 51 &&
+ getOpenMPClauseKind(ClauseName) == OMPC_indirect;
+ if (DTCI.Indirect.hasValue() && IsIndirectClause) {
+ Diag(Tok, diag::err_omp_more_one_clause)
+ << getOpenMPDirectiveName(OMPD_declare_target)
+ << getOpenMPClauseName(OMPC_indirect) << 0;
+ break;
+ }
bool IsToOrLinkClause =
OMPDeclareTargetDeclAttr::ConvertStrToMapTypeTy(ClauseName, MT);
assert((!IsDeviceTypeClause || !IsToOrLinkClause) && "Cannot be both!");
- if (!IsDeviceTypeClause && DTCI.Kind == OMPD_begin_declare_target) {
+ if (!IsDeviceTypeClause && !IsIndirectClause &&
+ DTCI.Kind == OMPD_begin_declare_target) {
Diag(Tok, diag::err_omp_declare_target_unexpected_clause)
- << ClauseName << 0;
+ << ClauseName << (getLangOpts().OpenMP >= 51 ? 3 : 0);
break;
}
- if (!IsDeviceTypeClause && !IsToOrLinkClause) {
+ if (!IsDeviceTypeClause && !IsToOrLinkClause && !IsIndirectClause) {
Diag(Tok, diag::err_omp_declare_target_unexpected_clause)
- << ClauseName << (getLangOpts().OpenMP >= 50 ? 2 : 1);
+ << ClauseName
+ << (getLangOpts().OpenMP >= 51 ? 4
+ : getLangOpts().OpenMP >= 50 ? 2
+ : 1);
break;
}
- if (IsToOrLinkClause)
- HasToOrLinkClause = true;
+ if (IsToOrLinkClause || IsIndirectClause)
+ HasToOrLinkOrIndirectClause = true;
+ if (IsIndirectClause) {
+ if (!ParseOpenMPIndirectClause(DTCI, /*ParseOnly*/ false))
+ break;
+ continue;
+ }
// Parse 'device_type' clause and go to next clause if any.
if (IsDeviceTypeClause) {
Optional<SimpleClauseData> DevTypeData =
@@ -1910,10 +1928,14 @@ void Parser::ParseOMPDeclareTargetClauses(
ConsumeToken();
}
+ if (DTCI.Indirect.hasValue() && DTCI.DT != OMPDeclareTargetDeclAttr::DT_Any)
+ Diag(DeviceTypeLoc, diag::err_omp_declare_target_indirect_device_type);
+
// For declare target require at least 'to' or 'link' to be present.
- if (DTCI.Kind == OMPD_declare_target && RequiresToOrLinkClause &&
- !HasToOrLinkClause)
- Diag(DTCI.Loc, diag::err_omp_declare_target_missing_to_or_link_clause);
+ if (DTCI.Kind == OMPD_declare_target && RequiresToOrLinkOrIndirectClause &&
+ !HasToOrLinkOrIndirectClause)
+ Diag(DTCI.Loc, diag::err_omp_declare_target_missing_to_or_link_clause)
+ << (getLangOpts().OpenMP >= 51 ? 1 : 0);
SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
}
@@ -2188,12 +2210,12 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
VariantMatchInfo VMI;
TI.getAsVariantMatchInfo(ASTCtx, VMI);
- std::function<void(StringRef)> DiagUnknownTrait = [this, Loc](
- StringRef ISATrait) {
- // TODO Track the selector locations in a way that is accessible here to
- // improve the diagnostic location.
- Diag(Loc, diag::warn_unknown_begin_declare_variant_isa_trait) << ISATrait;
- };
+ std::function<void(StringRef)> DiagUnknownTrait =
+ [this, Loc](StringRef ISATrait) {
+ // TODO Track the selector locations in a way that is accessible here
+ // to improve the diagnostic location.
+ Diag(Loc, diag::warn_unknown_declare_variant_isa_trait) << ISATrait;
+ };
TargetOMPContext OMPCtx(
ASTCtx, std::move(DiagUnknownTrait),
/* CurrentFunctionDecl */ nullptr,
@@ -2282,11 +2304,12 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
case OMPD_declare_target: {
SourceLocation DTLoc = ConsumeAnyToken();
bool HasClauses = Tok.isNot(tok::annot_pragma_openmp_end);
- bool HasImplicitMappings =
- DKind == OMPD_begin_declare_target || !HasClauses;
Sema::DeclareTargetContextInfo DTCI(DKind, DTLoc);
if (HasClauses)
ParseOMPDeclareTargetClauses(DTCI);
+ bool HasImplicitMappings =
+ DKind == OMPD_begin_declare_target || !HasClauses ||
+ (DTCI.ExplicitlyMapped.empty() && DTCI.Indirect.hasValue());
// Skip the last annot_pragma_openmp_end.
ConsumeAnyToken();
@@ -2528,7 +2551,13 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) {
TPA.Revert();
// End of the first iteration. Parser is reset to the start of metadirective
- TargetOMPContext OMPCtx(ASTContext, /* DiagUnknownTrait */ nullptr,
+ std::function<void(StringRef)> DiagUnknownTrait =
+ [this, Loc](StringRef ISATrait) {
+ // TODO Track the selector locations in a way that is accessible here
+ // to improve the diagnostic location.
+ Diag(Loc, diag::warn_unknown_declare_variant_isa_trait) << ISATrait;
+ };
+ TargetOMPContext OMPCtx(ASTContext, std::move(DiagUnknownTrait),
/* CurrentFunctionDecl */ nullptr,
ArrayRef<llvm::omp::TraitProperty>());
@@ -2936,7 +2965,7 @@ bool Parser::ParseOpenMPSimpleVarList(
if (AllowScopeSpecifier && getLangOpts().CPlusPlus &&
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false, false)) {
+ /*ObjectHasErrors=*/false, false)) {
IsCorrect = false;
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
StopBeforeMatch);
@@ -3383,6 +3412,47 @@ OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind,
return Actions.ActOnOpenMPSingleExprClause(Kind, Val.get(), Loc, LLoc, RLoc);
}
+/// Parse indirect clause for '#pragma omp declare target' directive.
+/// 'indirect' '[' '(' invoked-by-fptr ')' ']'
+/// where invoked-by-fptr is a constant boolean expression that evaluates to
+/// true or false at compile time.
+bool Parser::ParseOpenMPIndirectClause(Sema::DeclareTargetContextInfo &DTCI,
+ bool ParseOnly) {
+ SourceLocation Loc = ConsumeToken();
+ SourceLocation RLoc;
+
+ if (Tok.isNot(tok::l_paren)) {
+ if (ParseOnly)
+ return false;
+ DTCI.Indirect = nullptr;
+ return true;
+ }
+
+ ExprResult Val =
+ ParseOpenMPParensExpr(getOpenMPClauseName(OMPC_indirect), RLoc);
+ if (Val.isInvalid())
+ return false;
+
+ if (ParseOnly)
+ return false;
+
+ if (!Val.get()->isValueDependent() && !Val.get()->isTypeDependent() &&
+ !Val.get()->isInstantiationDependent() &&
+ !Val.get()->containsUnexpandedParameterPack()) {
+ ExprResult Ret = Actions.CheckBooleanCondition(Loc, Val.get());
+ if (Ret.isInvalid())
+ return false;
+ llvm::APSInt Result;
+ Ret = Actions.VerifyIntegerConstantExpression(Val.get(), &Result,
+ Sema::AllowFold);
+ if (Ret.isInvalid())
+ return false;
+ DTCI.Indirect = Val.get();
+ return true;
+ }
+ return false;
+}
+
/// Parsing of OpenMP clauses that use an interop-var.
///
/// init-clause:
@@ -3817,7 +3887,7 @@ bool Parser::parseMapperModifier(OpenMPVarListDataTy &Data) {
if (getLangOpts().CPlusPlus)
ParseOptionalCXXScopeSpecifier(Data.ReductionOrMapperIdScopeSpec,
/*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
/*EnteringContext=*/false);
if (Tok.isNot(tok::identifier) && Tok.isNot(tok::kw_default)) {
Diag(Tok.getLocation(), diag::err_omp_mapper_illegal_identifier);
@@ -4050,7 +4120,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
if (getLangOpts().CPlusPlus)
ParseOptionalCXXScopeSpecifier(Data.ReductionOrMapperIdScopeSpec,
/*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
/*EnteringContext=*/false);
InvalidReductionId = ParseReductionId(
*this, Data.ReductionOrMapperIdScopeSpec, UnqualifiedReductionId);
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 292ab03e8614..ee07775b6346 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -1068,7 +1068,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
SourceLocation LabelLoc = ConsumeToken();
SmallVector<Decl *, 8> DeclsInGroup;
- while (1) {
+ while (true) {
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected) << tok::identifier;
break;
@@ -1191,22 +1191,24 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt,
Sema::ConditionResult &Cond,
SourceLocation Loc,
- Sema::ConditionKind CK,
+ Sema::ConditionKind CK, bool MissingOK,
SourceLocation *LParenLoc,
SourceLocation *RParenLoc) {
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
+ SourceLocation Start = Tok.getLocation();
- if (getLangOpts().CPlusPlus)
- Cond = ParseCXXCondition(InitStmt, Loc, CK);
- else {
+ if (getLangOpts().CPlusPlus) {
+ Cond = ParseCXXCondition(InitStmt, Loc, CK, MissingOK);
+ } else {
ExprResult CondExpr = ParseExpression();
// If required, convert to a boolean value.
if (CondExpr.isInvalid())
Cond = Sema::ConditionError();
else
- Cond = Actions.ActOnCondition(getCurScope(), Loc, CondExpr.get(), CK);
+ Cond = Actions.ActOnCondition(getCurScope(), Loc, CondExpr.get(), CK,
+ MissingOK);
}
// If the parser was confused by the condition and we don't have a ')', try to
@@ -1220,7 +1222,16 @@ bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt,
return true;
}
- // Otherwise the condition is valid or the rparen is present.
+ if (Cond.isInvalid()) {
+ ExprResult CondExpr = Actions.CreateRecoveryExpr(
+ Start, Tok.getLocation() == Start ? Start : PrevTokLocation, {},
+ Actions.PreferredConditionType(CK));
+ if (!CondExpr.isInvalid())
+ Cond = Actions.ActOnCondition(getCurScope(), Loc, CondExpr.get(), CK,
+ MissingOK);
+ }
+
+ // Either the condition is valid or the rparen is present.
T.consumeClose();
if (LParenLoc != nullptr) {
@@ -1404,7 +1415,7 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
if (ParseParenExprOrCondition(&InitStmt, Cond, IfLoc,
IsConstexpr ? Sema::ConditionKind::ConstexprIf
: Sema::ConditionKind::Boolean,
- &LParen, &RParen))
+ /*MissingOK=*/false, &LParen, &RParen))
return StmtError();
if (IsConstexpr)
@@ -1599,7 +1610,8 @@ StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) {
SourceLocation LParen;
SourceLocation RParen;
if (ParseParenExprOrCondition(&InitStmt, Cond, SwitchLoc,
- Sema::ConditionKind::Switch, &LParen, &RParen))
+ Sema::ConditionKind::Switch,
+ /*MissingOK=*/false, &LParen, &RParen))
return StmtError();
StmtResult Switch = Actions.ActOnStartOfSwitchStmt(
@@ -1689,7 +1701,8 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) {
SourceLocation LParen;
SourceLocation RParen;
if (ParseParenExprOrCondition(nullptr, Cond, WhileLoc,
- Sema::ConditionKind::Boolean, &LParen, &RParen))
+ Sema::ConditionKind::Boolean,
+ /*MissingOK=*/false, &LParen, &RParen))
return StmtError();
// C99 6.8.5p5 - In C99, the body of the while statement is a scope, even if
@@ -1780,10 +1793,18 @@ StmtResult Parser::ParseDoStatement() {
// A do-while expression is not a condition, so can't have attributes.
DiagnoseAndSkipCXX11Attributes();
+ SourceLocation Start = Tok.getLocation();
ExprResult Cond = ParseExpression();
// Correct the typos in condition before closing the scope.
if (Cond.isUsable())
Cond = Actions.CorrectDelayedTyposInExpr(Cond);
+ else {
+ if (!Tok.isOneOf(tok::r_paren, tok::r_square, tok::r_brace))
+ SkipUntil(tok::semi);
+ Cond = Actions.CreateRecoveryExpr(
+ Start, Start == Tok.getLocation() ? Start : PrevTokLocation, {},
+ Actions.getASTContext().BoolTy);
+ }
T.consumeClose();
DoScope.Exit();
@@ -2038,10 +2059,11 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
// for-range-declaration next.
bool MightBeForRangeStmt = !ForRangeInfo.ParsedForRangeDecl();
ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt);
- SecondPart =
- ParseCXXCondition(nullptr, ForLoc, Sema::ConditionKind::Boolean,
- MightBeForRangeStmt ? &ForRangeInfo : nullptr,
- /*EnterForConditionScope*/ true);
+ SecondPart = ParseCXXCondition(
+ nullptr, ForLoc, Sema::ConditionKind::Boolean,
+ // FIXME: recovery if we don't see another semi!
+ /*MissingOK=*/true, MightBeForRangeStmt ? &ForRangeInfo : nullptr,
+ /*EnterForConditionScope*/ true);
if (ForRangeInfo.ParsedForRangeDecl()) {
Diag(FirstPart.get() ? FirstPart.get()->getBeginLoc()
@@ -2065,9 +2087,9 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
if (SecondExpr.isInvalid())
SecondPart = Sema::ConditionError();
else
- SecondPart =
- Actions.ActOnCondition(getCurScope(), ForLoc, SecondExpr.get(),
- Sema::ConditionKind::Boolean);
+ SecondPart = Actions.ActOnCondition(
+ getCurScope(), ForLoc, SecondExpr.get(),
+ Sema::ConditionKind::Boolean, /*MissingOK=*/true);
}
}
}
diff --git a/clang/lib/Parse/ParseStmtAsm.cpp b/clang/lib/Parse/ParseStmtAsm.cpp
index 3e9ce8fd668f..04c3a8700c10 100644
--- a/clang/lib/Parse/ParseStmtAsm.cpp
+++ b/clang/lib/Parse/ParseStmtAsm.cpp
@@ -222,7 +222,7 @@ ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
CXXScopeSpec SS;
if (getLangOpts().CPlusPlus)
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
/*EnteringContext=*/false);
// Require an identifier here.
@@ -508,7 +508,7 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
TokLoc = Tok.getLocation();
++NumTokensRead;
SkippedStartOfLine = false;
- } while (1);
+ } while (true);
if (BraceNesting && BraceCount != savedBraceCount) {
// __asm without closing brace (this can happen at EOF).
@@ -681,7 +681,7 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
/// asm-qualifier
/// asm-qualifier-list asm-qualifier
bool Parser::parseGNUAsmQualifierListOpt(GNUAsmQualifiers &AQ) {
- while (1) {
+ while (true) {
const GNUAsmQualifiers::AQ A = getGNUAsmQualifier(Tok);
if (A == GNUAsmQualifiers::AQ_unspecified) {
if (Tok.isNot(tok::l_paren)) {
@@ -810,7 +810,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
}
// Parse the asm-string list for clobbers if present.
if (!AteExtraColon && isTokenStringLiteral()) {
- while (1) {
+ while (true) {
ExprResult Clobber(ParseAsmStringLiteral(/*ForAsmLabel*/ false));
if (Clobber.isInvalid())
@@ -888,7 +888,7 @@ bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,
if (!isTokenStringLiteral() && Tok.isNot(tok::l_square))
return false;
- while (1) {
+ while (true) {
// Read the [id] if present.
if (Tok.is(tok::l_square)) {
BalancedDelimiterTracker T(*this, tok::l_square);
diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index 45af61a3926a..f875e3bf43e8 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -391,7 +391,7 @@ Parser::ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo,
CXXScopeSpec SS;
if (ParseOptionalCXXScopeSpecifier(
SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false, /*EnteringContext=*/false,
+ /*ObjectHasErrors=*/false, /*EnteringContext=*/false,
/*MayBePseudoDestructor=*/nullptr,
/*IsTypename=*/false, /*LastII=*/nullptr, /*OnlyNamespace=*/true) ||
SS.isInvalid()) {
@@ -500,7 +500,7 @@ bool Parser::ParseTemplateParameters(
bool
Parser::ParseTemplateParameterList(const unsigned Depth,
SmallVectorImpl<NamedDecl*> &TemplateParams) {
- while (1) {
+ while (true) {
if (NamedDecl *TmpParam
= ParseTemplateParameter(Depth, TemplateParams.size())) {
@@ -715,7 +715,7 @@ bool Parser::TryAnnotateTypeConstraint() {
CXXScopeSpec SS;
bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope);
if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
/*EnteringContext=*/false,
/*MayBePseudoDestructor=*/nullptr,
// If this is not a type-constraint, then
@@ -787,7 +787,7 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
bool TypenameKeyword = false;
SourceLocation KeyLoc;
ParseOptionalCXXScopeSpecifier(TypeConstraintSS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
/*EnteringContext*/ false);
if (Tok.is(tok::annot_template_id)) {
// Consume the 'type-constraint'.
@@ -1222,7 +1222,6 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation LAngleLoc,
return false;
}
-
/// Parses a template-id that after the template name has
/// already been parsed.
///
@@ -1234,11 +1233,13 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation LAngleLoc,
/// token that forms the template-id. Otherwise, we will leave the
/// last token in the stream (e.g., so that it can be replaced with an
/// annotation token).
-bool
-Parser::ParseTemplateIdAfterTemplateName(bool ConsumeLastToken,
- SourceLocation &LAngleLoc,
- TemplateArgList &TemplateArgs,
- SourceLocation &RAngleLoc) {
+///
+/// \param NameHint is not required, and merely affects code completion.
+bool Parser::ParseTemplateIdAfterTemplateName(bool ConsumeLastToken,
+ SourceLocation &LAngleLoc,
+ TemplateArgList &TemplateArgs,
+ SourceLocation &RAngleLoc,
+ TemplateTy Template) {
assert(Tok.is(tok::less) && "Must have already parsed the template-name");
// Consume the '<'.
@@ -1251,7 +1252,7 @@ Parser::ParseTemplateIdAfterTemplateName(bool ConsumeLastToken,
if (!Tok.isOneOf(tok::greater, tok::greatergreater,
tok::greatergreatergreater, tok::greaterequal,
tok::greatergreaterequal))
- Invalid = ParseTemplateArgumentList(TemplateArgs);
+ Invalid = ParseTemplateArgumentList(TemplateArgs, Template, LAngleLoc);
if (Invalid) {
// Try to find the closing '>'.
@@ -1332,8 +1333,8 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
TemplateArgList TemplateArgs;
bool ArgsInvalid = false;
if (!TypeConstraint || Tok.is(tok::less)) {
- ArgsInvalid = ParseTemplateIdAfterTemplateName(false, LAngleLoc,
- TemplateArgs, RAngleLoc);
+ ArgsInvalid = ParseTemplateIdAfterTemplateName(
+ false, LAngleLoc, TemplateArgs, RAngleLoc, Template);
// If we couldn't recover from invalid arguments, don't form an annotation
// token -- we don't know how much to annotate.
// FIXME: This can lead to duplicate diagnostics if we retry parsing this
@@ -1467,7 +1468,7 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
// '>', or (in some cases) '>>'.
CXXScopeSpec SS; // nested-name-specifier, if present
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
/*EnteringContext=*/false);
ParsedTemplateArgument Result;
@@ -1585,19 +1586,34 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() {
/// template-argument-list: [C++ 14.2]
/// template-argument
/// template-argument-list ',' template-argument
-bool
-Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) {
+///
+/// \param Template is only used for code completion, and may be null.
+bool Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs,
+ TemplateTy Template,
+ SourceLocation OpenLoc) {
ColonProtectionRAIIObject ColonProtection(*this, false);
+ auto RunSignatureHelp = [&] {
+ if (!Template)
+ return QualType();
+ CalledSignatureHelp = true;
+ return Actions.ProduceTemplateArgumentSignatureHelp(Template, TemplateArgs,
+ OpenLoc);
+ };
+
do {
+ PreferredType.enterFunctionArgument(Tok.getLocation(), RunSignatureHelp);
ParsedTemplateArgument Arg = ParseTemplateArgument();
SourceLocation EllipsisLoc;
if (TryConsumeToken(tok::ellipsis, EllipsisLoc))
Arg = Actions.ActOnPackExpansion(Arg, EllipsisLoc);
- if (Arg.isInvalid())
+ if (Arg.isInvalid()) {
+ if (PP.isCodeCompletionReached() && !CalledSignatureHelp)
+ RunSignatureHelp();
return true;
+ }
// Save this template argument.
TemplateArgs.push_back(Arg);
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index 35c9036fb27e..512993a5278e 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -277,7 +277,7 @@ Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) {
/// '{' '}'
///
Parser::TPResult Parser::TryParseInitDeclaratorList() {
- while (1) {
+ while (true) {
// declarator
TPResult TPR = TryParseDeclarator(false/*mayBeAbstract*/);
if (TPR != TPResult::Ambiguous)
@@ -1068,7 +1068,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
if (mayHaveDirectInit)
return TPResult::Ambiguous;
- while (1) {
+ while (true) {
TPResult TPR(TPResult::Ambiguous);
if (Tok.is(tok::l_paren)) {
@@ -1898,7 +1898,7 @@ Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration,
// parameter-declaration
// parameter-declaration-list ',' parameter-declaration
//
- while (1) {
+ while (true) {
// '...'[opt]
if (Tok.is(tok::ellipsis)) {
ConsumeToken();
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 11113fa1a060..ffa1e0f027f1 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -279,7 +279,7 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) {
// We always want this function to skip at least one token if the first token
// isn't T and if not at EOF.
bool isFirstTokenSkipped = true;
- while (1) {
+ while (true) {
// If we found one of the tokens, stop and return true.
for (unsigned i = 0, NumToks = Toks.size(); i != NumToks; ++i) {
if (Tok.is(Toks[i])) {
@@ -1448,7 +1448,7 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
ParseDeclarator(ParmDeclarator);
// Handle the full declarator list.
- while (1) {
+ while (true) {
// If attributes are present, parse them.
MaybeParseGNUAttributes(ParmDeclarator);
@@ -1634,7 +1634,7 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) {
CXXScopeSpec SS;
if (getLangOpts().CPlusPlus &&
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
EnteringContext))
return ANK_Error;
@@ -1882,7 +1882,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
SourceLocation TypenameLoc = ConsumeToken();
CXXScopeSpec SS;
if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
/*EnteringContext=*/false, nullptr,
/*IsTypename*/ true))
return true;
@@ -1953,7 +1953,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
CXXScopeSpec SS;
if (getLangOpts().CPlusPlus)
if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
/*EnteringContext*/ false))
return true;
@@ -2084,7 +2084,7 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) {
CXXScopeSpec SS;
if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
EnteringContext))
return true;
if (SS.isEmpty())
@@ -2195,7 +2195,7 @@ bool Parser::ParseMicrosoftIfExistsCondition(IfExistsCondition& Result) {
// Parse nested-name-specifier.
if (getLangOpts().CPlusPlus)
ParseOptionalCXXScopeSpecifier(Result.SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
/*EnteringContext=*/false);
// Check nested-name specifier.
diff --git a/clang/lib/Rewrite/HTMLRewrite.cpp b/clang/lib/Rewrite/HTMLRewrite.cpp
index e9b678b69594..70ea2fcd3d04 100644
--- a/clang/lib/Rewrite/HTMLRewrite.cpp
+++ b/clang/lib/Rewrite/HTMLRewrite.cpp
@@ -542,7 +542,7 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) {
// Lex all the tokens in raw mode, to avoid entering #includes or expanding
// macros.
- while (1) {
+ while (true) {
Token Tok;
L.LexFromRawLexer(Tok);
diff --git a/clang/lib/Rewrite/Rewriter.cpp b/clang/lib/Rewrite/Rewriter.cpp
index 3b06afc76e16..8950bfb7c4dc 100644
--- a/clang/lib/Rewrite/Rewriter.cpp
+++ b/clang/lib/Rewrite/Rewriter.cpp
@@ -223,6 +223,7 @@ std::string Rewriter::getRewrittenText(CharSourceRange Range) const {
RewriteBuffer::iterator Start = RB.begin();
std::advance(Start, StartOff);
RewriteBuffer::iterator End = Start;
+ assert(EndOff >= StartOff && "Invalid iteration distance");
std::advance(End, EndOff-StartOff);
return std::string(Start, End);
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index b4dcc9759b99..ac5ad52c0b1d 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -128,7 +128,7 @@ class LogicalErrorHandler : public CFGCallback {
Sema &S;
public:
- LogicalErrorHandler(Sema &S) : CFGCallback(), S(S) {}
+ LogicalErrorHandler(Sema &S) : S(S) {}
static bool HasMacroID(const Expr *E) {
if (E->getExprLoc().isMacroID())
diff --git a/clang/lib/Sema/CodeCompleteConsumer.cpp b/clang/lib/Sema/CodeCompleteConsumer.cpp
index 0a2ca54e244a..fefe20941f17 100644
--- a/clang/lib/Sema/CodeCompleteConsumer.cpp
+++ b/clang/lib/Sema/CodeCompleteConsumer.cpp
@@ -506,11 +506,92 @@ CodeCompleteConsumer::OverloadCandidate::getFunctionType() const {
case CK_FunctionType:
return Type;
+
+ case CK_Template:
+ case CK_Aggregate:
+ return nullptr;
}
llvm_unreachable("Invalid CandidateKind!");
}
+unsigned CodeCompleteConsumer::OverloadCandidate::getNumParams() const {
+ if (Kind == CK_Template)
+ return Template->getTemplateParameters()->size();
+
+ if (Kind == CK_Aggregate) {
+ unsigned Count =
+ std::distance(AggregateType->field_begin(), AggregateType->field_end());
+ if (const auto *CRD = dyn_cast<CXXRecordDecl>(AggregateType))
+ Count += CRD->getNumBases();
+ return Count;
+ }
+
+ if (const auto *FT = getFunctionType())
+ if (const auto *FPT = dyn_cast<FunctionProtoType>(FT))
+ return FPT->getNumParams();
+
+ return 0;
+}
+
+QualType
+CodeCompleteConsumer::OverloadCandidate::getParamType(unsigned N) const {
+ if (Kind == CK_Aggregate) {
+ if (const auto *CRD = dyn_cast<CXXRecordDecl>(AggregateType)) {
+ if (N < CRD->getNumBases())
+ return std::next(CRD->bases_begin(), N)->getType();
+ N -= CRD->getNumBases();
+ }
+ for (const auto *Field : AggregateType->fields())
+ if (N-- == 0)
+ return Field->getType();
+ return QualType();
+ }
+
+ if (Kind == CK_Template) {
+ TemplateParameterList *TPL = getTemplate()->getTemplateParameters();
+ if (N < TPL->size())
+ if (const auto *D = dyn_cast<NonTypeTemplateParmDecl>(TPL->getParam(N)))
+ return D->getType();
+ return QualType();
+ }
+
+ if (const auto *FT = getFunctionType())
+ if (const auto *FPT = dyn_cast<FunctionProtoType>(FT))
+ if (N < FPT->getNumParams())
+ return FPT->getParamType(N);
+ return QualType();
+}
+
+const NamedDecl *
+CodeCompleteConsumer::OverloadCandidate::getParamDecl(unsigned N) const {
+ if (Kind == CK_Aggregate) {
+ if (const auto *CRD = dyn_cast<CXXRecordDecl>(AggregateType)) {
+ if (N < CRD->getNumBases())
+ return std::next(CRD->bases_begin(), N)->getType()->getAsTagDecl();
+ N -= CRD->getNumBases();
+ }
+ for (const auto *Field : AggregateType->fields())
+ if (N-- == 0)
+ return Field;
+ return nullptr;
+ }
+
+ if (Kind == CK_Template) {
+ TemplateParameterList *TPL = getTemplate()->getTemplateParameters();
+ if (N < TPL->size())
+ return TPL->getParam(N);
+ return nullptr;
+ }
+
+ // Note that if we only have a FunctionProtoType, we don't have param decls.
+ if (const auto *FD = getFunction()) {
+ if (N < FD->param_size())
+ return FD->getParamDecl(N);
+ }
+ return nullptr;
+}
+
//===----------------------------------------------------------------------===//
// Code completion consumer implementation
//===----------------------------------------------------------------------===//
@@ -645,7 +726,7 @@ static std::string getOverloadAsString(const CodeCompletionString &CCS) {
void PrintingCodeCompleteConsumer::ProcessOverloadCandidates(
Sema &SemaRef, unsigned CurrentArg, OverloadCandidate *Candidates,
- unsigned NumCandidates, SourceLocation OpenParLoc) {
+ unsigned NumCandidates, SourceLocation OpenParLoc, bool Braced) {
OS << "OPENING_PAREN_LOC: ";
OpenParLoc.print(OS, SemaRef.getSourceManager());
OS << "\n";
@@ -653,7 +734,7 @@ void PrintingCodeCompleteConsumer::ProcessOverloadCandidates(
for (unsigned I = 0; I != NumCandidates; ++I) {
if (CodeCompletionString *CCS = Candidates[I].CreateSignatureString(
CurrentArg, SemaRef, getAllocator(), CCTUInfo,
- includeBriefComments())) {
+ includeBriefComments(), Braced)) {
OS << "OVERLOAD: " << getOverloadAsString(*CCS) << "\n";
}
}
diff --git a/clang/lib/Sema/OpenCLBuiltins.td b/clang/lib/Sema/OpenCLBuiltins.td
index 38debc5aa9fc..df2f206041c1 100644
--- a/clang/lib/Sema/OpenCLBuiltins.td
+++ b/clang/lib/Sema/OpenCLBuiltins.td
@@ -80,11 +80,14 @@ def FuncExtKhrLocalInt32ExtendedAtomics : FunctionExtension<"cl_khr_local_int32
def FuncExtKhrInt64BaseAtomics : FunctionExtension<"cl_khr_int64_base_atomics">;
def FuncExtKhrInt64ExtendedAtomics : FunctionExtension<"cl_khr_int64_extended_atomics">;
def FuncExtKhrMipmapImage : FunctionExtension<"cl_khr_mipmap_image">;
+def FuncExtKhrMipmapImageReadWrite : FunctionExtension<"cl_khr_mipmap_image __opencl_c_read_write_images">;
def FuncExtKhrMipmapImageWrites : FunctionExtension<"cl_khr_mipmap_image_writes">;
def FuncExtKhrGlMsaaSharing : FunctionExtension<"cl_khr_gl_msaa_sharing">;
+def FuncExtKhrGlMsaaSharingReadWrite : FunctionExtension<"cl_khr_gl_msaa_sharing __opencl_c_read_write_images">;
def FuncExtOpenCLCPipes : FunctionExtension<"__opencl_c_pipes">;
def FuncExtOpenCLCWGCollectiveFunctions : FunctionExtension<"__opencl_c_work_group_collective_functions">;
+def FuncExtOpenCLCReadWriteImages : FunctionExtension<"__opencl_c_read_write_images">;
def FuncExtFloatAtomicsFp16GlobalLoadStore : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_global_atomic_load_store">;
def FuncExtFloatAtomicsFp16LocalLoadStore : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_local_atomic_load_store">;
def FuncExtFloatAtomicsFp16GenericLoadStore : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_global_atomic_load_store __opencl_c_ext_fp16_local_atomic_load_store">;
@@ -1390,30 +1393,35 @@ foreach coordTy = [Int, Float] in {
}
// --- Table 23: Sampler-less Read Functions ---
+multiclass ImageReadSamplerless<string aQual> {
+ foreach imgTy = [Image2d, Image1dArray] in {
+ 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>], 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], 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>], Attr.Pure>;
+ def : Builtin<"read_imagef", [Float, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>], Attr.Pure>;
+}
+
let MinVersion = CL12 in {
- foreach aQual = ["RO", "RW"] in {
- foreach imgTy = [Image2d, Image1dArray] in {
- 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>], 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], 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>], Attr.Pure>;
- def : Builtin<"read_imagef", [Float, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>], Attr.Pure>;
+ defm : ImageReadSamplerless<"RO">;
+ let Extension = FuncExtOpenCLCReadWriteImages in {
+ defm : ImageReadSamplerless<"RW">;
}
}
// --- Table 24: Image Write Functions ---
-foreach aQual = ["WO", "RW"] in {
+multiclass ImageWrite<string aQual> {
foreach imgTy = [Image2d] in {
def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<Float, 4>]>;
def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<Int, 4>]>;
@@ -1443,8 +1451,13 @@ foreach aQual = ["WO", "RW"] in {
def : Builtin<"write_imagef", [Void, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>, Float]>;
}
+defm : ImageWrite<"WO">;
+let Extension = FuncExtOpenCLCReadWriteImages in {
+ defm : ImageWrite<"RW">;
+}
+
// --- Table 25: Image Query Functions ---
-foreach aQual = ["RO", "WO", "RW"] in {
+multiclass ImageQuery<string aQual> {
foreach imgTy = [Image1d, Image1dBuffer, Image2d, Image3d,
Image1dArray, Image2dArray, Image2dDepth,
Image2dArrayDepth] in {
@@ -1468,6 +1481,12 @@ foreach aQual = ["RO", "WO", "RW"] in {
}
}
+defm : ImageQuery<"RO">;
+defm : ImageQuery<"WO">;
+let Extension = FuncExtOpenCLCReadWriteImages in {
+ defm : ImageQuery<"RW">;
+}
+
// OpenCL extension v2.0 s5.1.9: Built-in Image Read Functions
// --- Table 8 ---
foreach aQual = ["RO"] in {
@@ -1488,7 +1507,7 @@ foreach aQual = ["RO"] in {
// OpenCL extension v2.0 s5.1.10: Built-in Image Sampler-less Read Functions
// --- Table 9 ---
let MinVersion = CL12 in {
- foreach aQual = ["RO", "RW"] in {
+ multiclass ImageReadHalf<string aQual> {
foreach name = ["read_imageh"] in {
foreach imgTy = [Image2d, Image1dArray] in {
def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>], Attr.Pure>;
@@ -1501,10 +1520,14 @@ let MinVersion = CL12 in {
}
}
}
+ defm : ImageReadHalf<"RO">;
+ let Extension = FuncExtOpenCLCReadWriteImages in {
+ defm : ImageReadHalf<"RW">;
+ }
}
// OpenCL extension v2.0 s5.1.11: Built-in Image Write Functions
// --- Table 10 ---
-foreach aQual = ["WO", "RW"] in {
+multiclass ImageWriteHalf<string aQual> {
foreach name = ["write_imageh"] in {
def : Builtin<name, [Void, ImageType<Image2d, aQual>, VectorType<Int, 2>, VectorType<Half, 4>]>;
def : Builtin<name, [Void, ImageType<Image2dArray, aQual>, VectorType<Int, 4>, VectorType<Half, 4>]>;
@@ -1515,6 +1538,12 @@ foreach aQual = ["WO", "RW"] in {
}
}
+defm : ImageWriteHalf<"WO">;
+let Extension = FuncExtOpenCLCReadWriteImages in {
+ defm : ImageWriteHalf<"RW">;
+}
+
+
//--------------------------------------------------------------------
// OpenCL v2.0 s6.13.15 - Work-group Functions
@@ -1688,14 +1717,24 @@ let Extension = FuncExtKhrMipmapImage in {
}
}
}
- // 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>]>;
- }
+}
+
+// Added to section 6.13.14.5
+multiclass ImageQueryNumMipLevels<string aQual> {
+ foreach imgTy = [Image1d, Image2d, Image3d, Image1dArray, Image2dArray, Image2dDepth, Image2dArrayDepth] in {
+ def : Builtin<"get_image_num_mip_levels", [Int, ImageType<imgTy, aQual>]>;
}
}
+let Extension = FuncExtKhrMipmapImage in {
+ defm : ImageQueryNumMipLevels<"RO">;
+ defm : ImageQueryNumMipLevels<"WO">;
+}
+
+let Extension = FuncExtKhrMipmapImageReadWrite in {
+ defm : ImageQueryNumMipLevels<"RW">;
+}
+
// Write functions are enabled using a separate extension.
let Extension = FuncExtKhrMipmapImageWrites in {
// Added to section 6.13.14.4.
@@ -1734,41 +1773,50 @@ let Extension = FuncExtKhrMipmapImageWrites in {
//--------------------------------------------------------------------
// 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.3 ---
+multiclass ImageReadMsaa<string aQual> {
+ 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>;
- }
- foreach imgTy = [Image2dArrayMsaa, Image2dArrayMsaaDepth] in {
- def : Builtin<"get_image_array_size", [Size, ImageType<imgTy, aQual>], Attr.Const>;
+// --- Table 6.13.14.5 ---
+multiclass ImageQueryMsaa<string aQual> {
+ 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>;
+ }
+ foreach imgTy = [Image2dArrayMsaa, Image2dArrayMsaaDepth] in {
+ def : Builtin<"get_image_array_size", [Size, ImageType<imgTy, aQual>], Attr.Const>;
}
}
+let Extension = FuncExtKhrGlMsaaSharing in {
+ defm : ImageReadMsaa<"RO">;
+ defm : ImageQueryMsaa<"RO">;
+ defm : ImageQueryMsaa<"WO">;
+}
+
+let Extension = FuncExtKhrGlMsaaSharingReadWrite in {
+ defm : ImageReadMsaa<"RW">;
+ defm : ImageQueryMsaa<"RW">;
+}
+
//--------------------------------------------------------------------
// OpenCL Extension v2.0 s28 - Subgroups
// --- Table 28.2.1 ---
diff --git a/clang/lib/Sema/Scope.cpp b/clang/lib/Sema/Scope.cpp
index 51b0b24e57b7..499279a2659d 100644
--- a/clang/lib/Sema/Scope.cpp
+++ b/clang/lib/Sema/Scope.cpp
@@ -91,7 +91,7 @@ void Scope::Init(Scope *parent, unsigned flags) {
UsingDirectives.clear();
Entity = nullptr;
ErrorTrap.reset();
- NRVO.setPointerAndInt(nullptr, 0);
+ NRVO.setPointerAndInt(nullptr, false);
}
bool Scope::containedInPrototypeScope() const {
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 734ed0f62ec6..20b4a9a5d4e6 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -60,6 +60,16 @@ ModuleLoader &Sema::getModuleLoader() const { return PP.getModuleLoader(); }
DarwinSDKInfo *
Sema::getDarwinSDKInfoForAvailabilityChecking(SourceLocation Loc,
StringRef Platform) {
+ auto *SDKInfo = getDarwinSDKInfoForAvailabilityChecking();
+ if (!SDKInfo && !WarnedDarwinSDKInfoMissing) {
+ Diag(Loc, diag::warn_missing_sdksettings_for_availability_checking)
+ << Platform;
+ WarnedDarwinSDKInfoMissing = true;
+ }
+ return SDKInfo;
+}
+
+DarwinSDKInfo *Sema::getDarwinSDKInfoForAvailabilityChecking() {
if (CachedDarwinSDKInfo)
return CachedDarwinSDKInfo->get();
auto SDKInfo = parseDarwinSDKInfo(
@@ -71,8 +81,6 @@ Sema::getDarwinSDKInfoForAvailabilityChecking(SourceLocation Loc,
}
if (!SDKInfo)
llvm::consumeError(SDKInfo.takeError());
- Diag(Loc, diag::warn_missing_sdksettings_for_availability_checking)
- << Platform;
CachedDarwinSDKInfo = std::unique_ptr<DarwinSDKInfo>();
return nullptr;
}
@@ -187,7 +195,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
CodeSegStack(nullptr), FpPragmaStack(FPOptionsOverride()),
CurInitSeg(nullptr), VisContext(nullptr),
PragmaAttributeCurrentTargetDecl(nullptr),
- IsBuildingRecoveryCallExpr(false), Cleanup{}, LateTemplateParser(nullptr),
+ IsBuildingRecoveryCallExpr(false), LateTemplateParser(nullptr),
LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp),
StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr),
StdCoroutineTraitsCache(nullptr), CXXTypeInfoDecl(nullptr),
@@ -324,9 +332,12 @@ void Sema::Initialize() {
Context.getTargetInfo().getSupportedOpenCLOpts(), getLangOpts());
addImplicitTypedef("sampler_t", Context.OCLSamplerTy);
addImplicitTypedef("event_t", Context.OCLEventTy);
- if (getLangOpts().getOpenCLCompatibleVersion() >= 200) {
- addImplicitTypedef("clk_event_t", Context.OCLClkEventTy);
- addImplicitTypedef("queue_t", Context.OCLQueueTy);
+ auto OCLCompatibleVersion = getLangOpts().getOpenCLCompatibleVersion();
+ if (OCLCompatibleVersion >= 200) {
+ if (getLangOpts().OpenCLCPlusPlus || getLangOpts().Blocks) {
+ addImplicitTypedef("clk_event_t", Context.OCLClkEventTy);
+ addImplicitTypedef("queue_t", Context.OCLQueueTy);
+ }
if (getLangOpts().OpenCLPipes)
addImplicitTypedef("reserve_id_t", Context.OCLReserveIDTy);
addImplicitTypedef("atomic_int", Context.getAtomicType(Context.IntTy));
@@ -394,7 +405,6 @@ void Sema::Initialize() {
}
}
-
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
if (getOpenCLOptions().isSupported(#Ext, getLangOpts())) { \
addImplicitTypedef(#ExtType, Context.Id##Ty); \
@@ -1858,6 +1868,15 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) {
if (isUnevaluatedContext() || Ty.isNull())
return;
+ // The original idea behind checkTypeSupport function is that unused
+ // declarations can be replaced with an array of bytes of the same size during
+ // codegen, such replacement doesn't seem to be possible for types without
+ // constant byte size like zero length arrays. So, do a deep check for SYCL.
+ if (D && LangOpts.SYCLIsDevice) {
+ llvm::DenseSet<QualType> Visited;
+ deepTypeCheckForSYCLDevice(Loc, Visited, D);
+ }
+
Decl *C = cast<Decl>(getCurLexicalContext());
// Memcpy operations for structs containing a member with unsupported type
@@ -1932,7 +1951,8 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) {
};
auto CheckType = [&](QualType Ty, bool IsRetTy = false) {
- if (LangOpts.SYCLIsDevice || (LangOpts.OpenMP && LangOpts.OpenMPIsDevice))
+ if (LangOpts.SYCLIsDevice || (LangOpts.OpenMP && LangOpts.OpenMPIsDevice) ||
+ LangOpts.CUDAIsDevice)
CheckDeviceType(Ty);
QualType UnqualTy = Ty.getCanonicalType().getUnqualifiedType();
@@ -2534,6 +2554,11 @@ static bool IsCPUDispatchCPUSpecificMultiVersion(const Expr *E) {
bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD,
bool ForceComplain,
bool (*IsPlausibleResult)(QualType)) {
+ if (isSFINAEContext()) {
+ // If this is a SFINAE context, don't try anything that might trigger ADL
+ // prematurely.
+ return false;
+ }
SourceLocation Loc = E.get()->getExprLoc();
SourceRange Range = E.get()->getSourceRange();
diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index 8cecf6c6ab4f..4781d71080c9 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -881,7 +881,8 @@ bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS,
TypeLocBuilder TLB;
DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T);
- DecltypeTL.setNameLoc(DS.getTypeSpecTypeLoc());
+ DecltypeTL.setDecltypeLoc(DS.getTypeSpecTypeLoc());
+ DecltypeTL.setRParenLoc(DS.getTypeofParensRange().getEnd());
SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T),
ColonColonLoc);
return false;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 4e83fa1fffca..c8fb36b8311a 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -499,7 +499,8 @@ public:
1 /* null byte always written by sprintf */) {}
bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
- const char *, unsigned SpecifierLen) override {
+ const char *, unsigned SpecifierLen,
+ const TargetInfo &) override {
const size_t FieldWidth = computeFieldWidth(FS);
const size_t Precision = computePrecision(FS);
@@ -1578,11 +1579,26 @@ static ExprResult SemaBuiltinLaunder(Sema &S, CallExpr *TheCall) {
return TheCall;
}
+// Emit an error and return true if the current object format type is in the
+// list of unsupported types.
+static bool CheckBuiltinTargetNotInUnsupported(
+ Sema &S, unsigned BuiltinID, CallExpr *TheCall,
+ ArrayRef<llvm::Triple::ObjectFormatType> UnsupportedObjectFormatTypes) {
+ llvm::Triple::ObjectFormatType CurObjFormat =
+ S.getASTContext().getTargetInfo().getTriple().getObjectFormat();
+ if (llvm::is_contained(UnsupportedObjectFormatTypes, CurObjFormat)) {
+ S.Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
+ << TheCall->getSourceRange();
+ return true;
+ }
+ return false;
+}
+
// Emit an error and return true if the current architecture is not in the list
// of supported architectures.
static bool
-CheckBuiltinTargetSupport(Sema &S, unsigned BuiltinID, CallExpr *TheCall,
- ArrayRef<llvm::Triple::ArchType> SupportedArchs) {
+CheckBuiltinTargetInSupported(Sema &S, unsigned BuiltinID, CallExpr *TheCall,
+ ArrayRef<llvm::Triple::ArchType> SupportedArchs) {
llvm::Triple::ArchType CurArch =
S.getASTContext().getTargetInfo().getTriple().getArch();
if (llvm::is_contained(SupportedArchs, CurArch))
@@ -1664,6 +1680,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
switch (BuiltinID) {
case Builtin::BI__builtin___CFStringMakeConstantString:
+ // CFStringMakeConstantString is currently not implemented for GOFF (i.e.,
+ // on z/OS) and for XCOFF (i.e., on AIX). Emit unsupported
+ if (CheckBuiltinTargetNotInUnsupported(
+ *this, BuiltinID, TheCall,
+ {llvm::Triple::GOFF, llvm::Triple::XCOFF}))
+ return ExprError();
assert(TheCall->getNumArgs() == 1 &&
"Wrong # arguments to builtin CFStringMakeConstantString");
if (CheckObjCString(TheCall->getArg(0)))
@@ -1698,7 +1720,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
case Builtin::BI_interlockedbittestandreset_acq:
case Builtin::BI_interlockedbittestandreset_rel:
case Builtin::BI_interlockedbittestandreset_nf:
- if (CheckBuiltinTargetSupport(
+ if (CheckBuiltinTargetInSupported(
*this, BuiltinID, TheCall,
{llvm::Triple::arm, llvm::Triple::thumb, llvm::Triple::aarch64}))
return ExprError();
@@ -1711,9 +1733,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
case Builtin::BI_bittestandset64:
case Builtin::BI_interlockedbittestandreset64:
case Builtin::BI_interlockedbittestandset64:
- if (CheckBuiltinTargetSupport(*this, BuiltinID, TheCall,
- {llvm::Triple::x86_64, llvm::Triple::arm,
- llvm::Triple::thumb, llvm::Triple::aarch64}))
+ if (CheckBuiltinTargetInSupported(*this, BuiltinID, TheCall,
+ {llvm::Triple::x86_64, llvm::Triple::arm,
+ llvm::Triple::thumb,
+ llvm::Triple::aarch64}))
return ExprError();
break;
@@ -1750,10 +1773,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
return ExprError();
break;
case Builtin::BI__builtin_alloca_with_align:
+ case Builtin::BI__builtin_alloca_with_align_uninitialized:
if (SemaBuiltinAllocaWithAlign(TheCall))
return ExprError();
LLVM_FALLTHROUGH;
case Builtin::BI__builtin_alloca:
+ case Builtin::BI__builtin_alloca_uninitialized:
Diag(TheCall->getBeginLoc(), diag::warn_alloca)
<< TheCall->getDirectCallee();
break;
@@ -2189,9 +2214,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
break;
}
- // __builtin_elementwise_ceil restricts the element type to floating point
+ // These builtins restrict the element type to floating point
// types only.
- case Builtin::BI__builtin_elementwise_ceil: {
+ case Builtin::BI__builtin_elementwise_ceil:
+ case Builtin::BI__builtin_elementwise_floor:
+ case Builtin::BI__builtin_elementwise_roundeven:
+ case Builtin::BI__builtin_elementwise_trunc: {
if (PrepareBuiltinElementwiseMathOneArgCall(TheCall))
return ExprError();
@@ -2232,8 +2260,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
break;
}
- // __builtin_reduce_xor supports vector of integers only.
- case Builtin::BI__builtin_reduce_xor: {
+ // These builtins support vectors of integers only.
+ case Builtin::BI__builtin_reduce_xor:
+ case Builtin::BI__builtin_reduce_or:
+ case Builtin::BI__builtin_reduce_and: {
if (PrepareBuiltinReduceMathOneArgCall(TheCall))
return ExprError();
@@ -3946,23 +3976,39 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI,
// Check if each required feature is included
for (StringRef F : ReqFeatures) {
- if (TI.hasFeature(F))
- continue;
-
- // If the feature is 64bit, alter the string so it will print better in
- // the diagnostic.
- if (F == "64bit")
- F = "RV64";
+ SmallVector<StringRef> ReqOpFeatures;
+ F.split(ReqOpFeatures, '|');
+ bool HasFeature = false;
+ for (StringRef OF : ReqOpFeatures) {
+ if (TI.hasFeature(OF)) {
+ HasFeature = true;
+ continue;
+ }
+ }
- // Convert features like "zbr" and "experimental-zbr" to "Zbr".
- F.consume_front("experimental-");
- std::string FeatureStr = F.str();
- FeatureStr[0] = std::toupper(FeatureStr[0]);
+ if (!HasFeature) {
+ std::string FeatureStrs = "";
+ for (StringRef OF : ReqOpFeatures) {
+ // If the feature is 64bit, alter the string so it will print better in
+ // the diagnostic.
+ if (OF == "64bit")
+ OF = "RV64";
- // Error message
- FeatureMissing = true;
- Diag(TheCall->getBeginLoc(), diag::err_riscv_builtin_requires_extension)
- << TheCall->getSourceRange() << StringRef(FeatureStr);
+ // Convert features like "zbr" and "experimental-zbr" to "Zbr".
+ OF.consume_front("experimental-");
+ std::string FeatureStr = OF.str();
+ FeatureStr[0] = std::toupper(FeatureStr[0]);
+ // Combine strings.
+ FeatureStrs += FeatureStrs == "" ? "" : ", ";
+ FeatureStrs += "'";
+ FeatureStrs += FeatureStr;
+ FeatureStrs += "'";
+ }
+ // Error message
+ FeatureMissing = true;
+ Diag(TheCall->getBeginLoc(), diag::err_riscv_builtin_requires_extension)
+ << TheCall->getSourceRange() << StringRef(FeatureStrs);
+ }
}
if (FeatureMissing)
@@ -8880,8 +8926,8 @@ public:
void handleInvalidMaskType(StringRef MaskType) override;
bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
- const char *startSpecifier,
- unsigned specifierLen) override;
+ const char *startSpecifier, unsigned specifierLen,
+ const TargetInfo &Target) override;
bool checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
const char *StartSpecifier,
unsigned SpecifierLen,
@@ -9140,11 +9186,9 @@ bool CheckPrintfHandler::checkForCStrMembers(
return false;
}
-bool
-CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
- &FS,
- const char *startSpecifier,
- unsigned specifierLen) {
+bool CheckPrintfHandler::HandlePrintfSpecifier(
+ const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier,
+ unsigned specifierLen, const TargetInfo &Target) {
using namespace analyze_format_string;
using namespace analyze_printf;
@@ -9276,6 +9320,15 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
}
}
+ const llvm::Triple &Triple = Target.getTriple();
+ if (CS.getKind() == ConversionSpecifier::nArg &&
+ (Triple.isAndroid() || Triple.isOSFuchsia())) {
+ EmitFormatDiagnostic(S.PDiag(diag::warn_printf_narg_not_supported),
+ getLocationOfByte(CS.getStart()),
+ /*IsStringLocation*/ false,
+ getSpecifierRange(startSpecifier, specifierLen));
+ }
+
// Check for invalid use of field width
if (!FS.hasValidFieldWidth()) {
HandleInvalidAmount(FS, FS.getFieldWidth(), /* field width */ 0,
@@ -14021,7 +14074,7 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
const Expr *UsageExpr;
SequenceTree::Seq Seq;
- Usage() : UsageExpr(nullptr), Seq() {}
+ Usage() : UsageExpr(nullptr) {}
};
struct UsageInfo {
@@ -14030,7 +14083,7 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
/// Have we issued a diagnostic for this object already?
bool Diagnosed;
- UsageInfo() : Uses(), Diagnosed(false) {}
+ UsageInfo() : Diagnosed(false) {}
};
using UsageInfoMap = llvm::SmallDenseMap<Object, UsageInfo, 16>;
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 93c07ccc891f..01fdf51c60c3 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -36,6 +36,7 @@
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Overload.h"
#include "clang/Sema/ParsedAttr.h"
+#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/Sema.h"
@@ -98,7 +99,7 @@ private:
unsigned SingleDeclIndex;
public:
- ShadowMapEntry() : DeclOrVector(), SingleDeclIndex(0) {}
+ ShadowMapEntry() : SingleDeclIndex(0) {}
ShadowMapEntry(const ShadowMapEntry &) = delete;
ShadowMapEntry(ShadowMapEntry &&Move) { *this = std::move(Move); }
ShadowMapEntry &operator=(const ShadowMapEntry &) = delete;
@@ -1437,7 +1438,7 @@ bool ResultBuilder::IsOrdinaryNonTypeName(const NamedDecl *ND) const {
bool ResultBuilder::IsIntegralConstantValue(const NamedDecl *ND) const {
if (!IsOrdinaryNonTypeName(ND))
- return 0;
+ return false;
if (const auto *VD = dyn_cast<ValueDecl>(ND->getUnderlyingDecl()))
if (VD->getType()->isIntegralOrEnumerationType())
@@ -1895,6 +1896,7 @@ static PrintingPolicy getCompletionPrintingPolicy(const ASTContext &Context,
Policy.SuppressStrongLifetime = true;
Policy.SuppressUnwrittenScope = true;
Policy.SuppressScope = true;
+ Policy.CleanUglifiedParameters = true;
return Policy;
}
@@ -2816,14 +2818,18 @@ formatBlockPlaceholder(const PrintingPolicy &Policy, const NamedDecl *BlockDecl,
Optional<ArrayRef<QualType>> ObjCSubsts = None);
static std::string
-FormatFunctionParameter(const PrintingPolicy &Policy, const ParmVarDecl *Param,
- bool SuppressName = false, bool SuppressBlock = false,
+FormatFunctionParameter(const PrintingPolicy &Policy,
+ const DeclaratorDecl *Param, bool SuppressName = false,
+ bool SuppressBlock = false,
Optional<ArrayRef<QualType>> ObjCSubsts = None) {
// Params are unavailable in FunctionTypeLoc if the FunctionType is invalid.
// It would be better to pass in the param Type, which is usually available.
// But this case is rare, so just pretend we fell back to int as elsewhere.
if (!Param)
return "int";
+ Decl::ObjCDeclQualifier ObjCQual = Decl::OBJC_TQ_None;
+ if (const auto *PVD = dyn_cast<ParmVarDecl>(Param))
+ ObjCQual = PVD->getObjCDeclQualifier();
bool ObjCMethodParam = isa<ObjCMethodDecl>(Param->getDeclContext());
if (Param->getType()->isDependentType() ||
!Param->getType()->isBlockPointerType()) {
@@ -2832,18 +2838,17 @@ FormatFunctionParameter(const PrintingPolicy &Policy, const ParmVarDecl *Param,
std::string Result;
if (Param->getIdentifier() && !ObjCMethodParam && !SuppressName)
- Result = std::string(Param->getIdentifier()->getName());
+ Result = std::string(Param->getIdentifier()->deuglifiedName());
QualType Type = Param->getType();
if (ObjCSubsts)
Type = Type.substObjCTypeArgs(Param->getASTContext(), *ObjCSubsts,
ObjCSubstitutionContext::Parameter);
if (ObjCMethodParam) {
- Result =
- "(" + formatObjCParamQualifiers(Param->getObjCDeclQualifier(), Type);
+ Result = "(" + formatObjCParamQualifiers(ObjCQual, Type);
Result += Type.getAsString(Policy) + ")";
if (Param->getIdentifier() && !SuppressName)
- Result += Param->getIdentifier()->getName();
+ Result += Param->getIdentifier()->deuglifiedName();
} else {
Type.getAsStringInternal(Result, Policy);
}
@@ -2871,20 +2876,19 @@ FormatFunctionParameter(const PrintingPolicy &Policy, const ParmVarDecl *Param,
// for the block; just use the parameter type as a placeholder.
std::string Result;
if (!ObjCMethodParam && Param->getIdentifier())
- Result = std::string(Param->getIdentifier()->getName());
+ Result = std::string(Param->getIdentifier()->deuglifiedName());
QualType Type = Param->getType().getUnqualifiedType();
if (ObjCMethodParam) {
Result = Type.getAsString(Policy);
- std::string Quals =
- formatObjCParamQualifiers(Param->getObjCDeclQualifier(), Type);
+ std::string Quals = formatObjCParamQualifiers(ObjCQual, Type);
if (!Quals.empty())
Result = "(" + Quals + " " + Result + ")";
if (Result.back() != ')')
Result += " ";
if (Param->getIdentifier())
- Result += Param->getIdentifier()->getName();
+ Result += Param->getIdentifier()->deuglifiedName();
} else {
Type.getAsStringInternal(Result, Policy);
}
@@ -3079,14 +3083,14 @@ static void AddTemplateParameterChunks(
if (TTP->getIdentifier()) {
PlaceholderStr += ' ';
- PlaceholderStr += TTP->getIdentifier()->getName();
+ PlaceholderStr += TTP->getIdentifier()->deuglifiedName();
}
HasDefaultArg = TTP->hasDefaultArgument();
} else if (NonTypeTemplateParmDecl *NTTP =
dyn_cast<NonTypeTemplateParmDecl>(*P)) {
if (NTTP->getIdentifier())
- PlaceholderStr = std::string(NTTP->getIdentifier()->getName());
+ PlaceholderStr = std::string(NTTP->getIdentifier()->deuglifiedName());
NTTP->getType().getAsStringInternal(PlaceholderStr, Policy);
HasDefaultArg = NTTP->hasDefaultArgument();
} else {
@@ -3098,7 +3102,7 @@ static void AddTemplateParameterChunks(
PlaceholderStr = "template<...> class";
if (TTP->getIdentifier()) {
PlaceholderStr += ' ';
- PlaceholderStr += TTP->getIdentifier()->getName();
+ PlaceholderStr += TTP->getIdentifier()->deuglifiedName();
}
HasDefaultArg = TTP->hasDefaultArgument();
@@ -3688,6 +3692,31 @@ const RawComment *clang::getParameterComment(
return nullptr;
}
+static void AddOverloadAggregateChunks(const RecordDecl *RD,
+ const PrintingPolicy &Policy,
+ CodeCompletionBuilder &Result,
+ unsigned CurrentArg) {
+ unsigned ChunkIndex = 0;
+ auto AddChunk = [&](llvm::StringRef Placeholder) {
+ if (ChunkIndex > 0)
+ Result.AddChunk(CodeCompletionString::CK_Comma);
+ const char *Copy = Result.getAllocator().CopyString(Placeholder);
+ if (ChunkIndex == CurrentArg)
+ Result.AddCurrentParameterChunk(Copy);
+ else
+ Result.AddPlaceholderChunk(Copy);
+ ++ChunkIndex;
+ };
+ // Aggregate initialization has all bases followed by all fields.
+ // (Bases are not legal in C++11 but in that case we never get here).
+ if (auto *CRD = llvm::dyn_cast<CXXRecordDecl>(RD)) {
+ for (const auto &Base : CRD->bases())
+ AddChunk(Base.getType().getAsString(Policy));
+ }
+ for (const auto &Field : RD->fields())
+ AddChunk(FormatFunctionParameter(Policy, Field));
+}
+
/// Add function overload parameter chunks to the given code completion
/// string.
static void AddOverloadParameterChunks(ASTContext &Context,
@@ -3697,6 +3726,11 @@ static void AddOverloadParameterChunks(ASTContext &Context,
CodeCompletionBuilder &Result,
unsigned CurrentArg, unsigned Start = 0,
bool InOptional = false) {
+ if (!Function && !Prototype) {
+ Result.AddChunk(CodeCompletionString::CK_CurrentParameter, "...");
+ return;
+ }
+
bool FirstParameter = true;
unsigned NumParams =
Function ? Function->getNumParams() : Prototype->getNumParams();
@@ -3757,10 +3791,83 @@ static void AddOverloadParameterChunks(ASTContext &Context,
}
}
+static std::string
+formatTemplateParameterPlaceholder(const NamedDecl *Param, bool &Optional,
+ const PrintingPolicy &Policy) {
+ if (const auto *Type = dyn_cast<TemplateTypeParmDecl>(Param)) {
+ Optional = Type->hasDefaultArgument();
+ } else if (const auto *NonType = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ Optional = NonType->hasDefaultArgument();
+ } else if (const auto *Template = dyn_cast<TemplateTemplateParmDecl>(Param)) {
+ Optional = Template->hasDefaultArgument();
+ }
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ Param->print(OS, Policy);
+ return Result;
+}
+
+static std::string templateResultType(const TemplateDecl *TD,
+ const PrintingPolicy &Policy) {
+ if (const auto *CTD = dyn_cast<ClassTemplateDecl>(TD))
+ return CTD->getTemplatedDecl()->getKindName().str();
+ if (const auto *VTD = dyn_cast<VarTemplateDecl>(TD))
+ return VTD->getTemplatedDecl()->getType().getAsString(Policy);
+ if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(TD))
+ return FTD->getTemplatedDecl()->getReturnType().getAsString(Policy);
+ if (isa<TypeAliasTemplateDecl>(TD))
+ return "type";
+ if (isa<TemplateTemplateParmDecl>(TD))
+ return "class";
+ if (isa<ConceptDecl>(TD))
+ return "concept";
+ return "";
+}
+
+static CodeCompletionString *createTemplateSignatureString(
+ const TemplateDecl *TD, CodeCompletionBuilder &Builder, unsigned CurrentArg,
+ const PrintingPolicy &Policy) {
+ llvm::ArrayRef<NamedDecl *> Params = TD->getTemplateParameters()->asArray();
+ CodeCompletionBuilder OptionalBuilder(Builder.getAllocator(),
+ Builder.getCodeCompletionTUInfo());
+ std::string ResultType = templateResultType(TD, Policy);
+ if (!ResultType.empty())
+ Builder.AddResultTypeChunk(Builder.getAllocator().CopyString(ResultType));
+ Builder.AddTextChunk(
+ Builder.getAllocator().CopyString(TD->getNameAsString()));
+ Builder.AddChunk(CodeCompletionString::CK_LeftAngle);
+ // Initially we're writing into the main string. Once we see an optional arg
+ // (with default), we're writing into the nested optional chunk.
+ CodeCompletionBuilder *Current = &Builder;
+ for (unsigned I = 0; I < Params.size(); ++I) {
+ bool Optional = false;
+ std::string Placeholder =
+ formatTemplateParameterPlaceholder(Params[I], Optional, Policy);
+ if (Optional)
+ Current = &OptionalBuilder;
+ if (I > 0)
+ Current->AddChunk(CodeCompletionString::CK_Comma);
+ Current->AddChunk(I == CurrentArg
+ ? CodeCompletionString::CK_CurrentParameter
+ : CodeCompletionString::CK_Placeholder,
+ Current->getAllocator().CopyString(Placeholder));
+ }
+ // Add the optional chunk to the main string if we ever used it.
+ if (Current == &OptionalBuilder)
+ Builder.AddOptionalChunk(OptionalBuilder.TakeString());
+ Builder.AddChunk(CodeCompletionString::CK_RightAngle);
+ // For function templates, ResultType was the function's return type.
+ // Give some clue this is a function. (Don't show the possibly-bulky params).
+ if (isa<FunctionTemplateDecl>(TD))
+ Builder.AddInformativeChunk("()");
+ return Builder.TakeString();
+}
+
CodeCompletionString *
CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
unsigned CurrentArg, Sema &S, CodeCompletionAllocator &Allocator,
- CodeCompletionTUInfo &CCTUInfo, bool IncludeBriefComments) const {
+ CodeCompletionTUInfo &CCTUInfo, bool IncludeBriefComments,
+ bool Braced) const {
PrintingPolicy Policy = getCompletionPrintingPolicy(S);
// Show signatures of constructors as they are declared:
// vector(int n) rather than vector<string>(int n)
@@ -3770,22 +3877,20 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
// FIXME: Set priority, availability appropriately.
CodeCompletionBuilder Result(Allocator, CCTUInfo, 1,
CXAvailability_Available);
+
+ if (getKind() == CK_Template)
+ return createTemplateSignatureString(getTemplate(), Result, CurrentArg,
+ Policy);
+
FunctionDecl *FDecl = getFunction();
const FunctionProtoType *Proto =
- dyn_cast<FunctionProtoType>(getFunctionType());
- if (!FDecl && !Proto) {
- // Function without a prototype. Just give the return type and a
- // highlighted ellipsis.
- const FunctionType *FT = getFunctionType();
- Result.AddResultTypeChunk(Result.getAllocator().CopyString(
- FT->getReturnType().getAsString(Policy)));
- Result.AddChunk(CodeCompletionString::CK_LeftParen);
- Result.AddChunk(CodeCompletionString::CK_CurrentParameter, "...");
- Result.AddChunk(CodeCompletionString::CK_RightParen);
- return Result.TakeString();
- }
+ dyn_cast_or_null<FunctionProtoType>(getFunctionType());
- if (FDecl) {
+ // First, the name/type of the callee.
+ if (getKind() == CK_Aggregate) {
+ Result.AddTextChunk(
+ Result.getAllocator().CopyString(getAggregate()->getName()));
+ } else if (FDecl) {
if (IncludeBriefComments) {
if (auto RC = getParameterComment(S.getASTContext(), *this, CurrentArg))
Result.addBriefComment(RC->getBriefText(S.getASTContext()));
@@ -3797,14 +3902,21 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
FDecl->getDeclName().print(OS, Policy);
Result.AddTextChunk(Result.getAllocator().CopyString(OS.str()));
} else {
+ // Function without a declaration. Just give the return type.
Result.AddResultTypeChunk(Result.getAllocator().CopyString(
- Proto->getReturnType().getAsString(Policy)));
+ getFunctionType()->getReturnType().getAsString(Policy)));
}
- Result.AddChunk(CodeCompletionString::CK_LeftParen);
- AddOverloadParameterChunks(S.getASTContext(), Policy, FDecl, Proto, Result,
- CurrentArg);
- Result.AddChunk(CodeCompletionString::CK_RightParen);
+ // Next, the brackets and parameters.
+ Result.AddChunk(Braced ? CodeCompletionString::CK_LeftBrace
+ : CodeCompletionString::CK_LeftParen);
+ if (getKind() == CK_Aggregate)
+ AddOverloadAggregateChunks(getAggregate(), Policy, Result, CurrentArg);
+ else
+ AddOverloadParameterChunks(S.getASTContext(), Policy, FDecl, Proto, Result,
+ CurrentArg);
+ Result.AddChunk(Braced ? CodeCompletionString::CK_RightBrace
+ : CodeCompletionString::CK_RightParen);
return Result.TakeString();
}
@@ -5408,11 +5520,18 @@ QualType getApproximateType(const Expr *E) {
: getApproximateType(CDSME->getBase());
if (CDSME->isArrow() && !Base.isNull())
Base = Base->getPointeeType(); // could handle unique_ptr etc here?
- RecordDecl *RD = Base.isNull() ? nullptr : getAsRecordDecl(Base);
+ auto *RD =
+ Base.isNull()
+ ? nullptr
+ : llvm::dyn_cast_or_null<CXXRecordDecl>(getAsRecordDecl(Base));
if (RD && RD->isCompleteDefinition()) {
- for (const auto *Member : RD->lookup(CDSME->getMember()))
- if (const ValueDecl *VD = llvm::dyn_cast<ValueDecl>(Member))
- return VD->getType().getNonReferenceType();
+ // Look up member heuristically, including in bases.
+ for (const auto *Member : RD->lookupDependentName(
+ CDSME->getMember(), [](const NamedDecl *Member) {
+ return llvm::isa<ValueDecl>(Member);
+ })) {
+ return llvm::cast<ValueDecl>(Member)->getType().getNonReferenceType();
+ }
}
}
return Unresolved;
@@ -5843,36 +5962,37 @@ static QualType getParamType(Sema &SemaRef,
// overload candidates.
QualType ParamType;
for (auto &Candidate : Candidates) {
- if (const auto *FType = Candidate.getFunctionType())
- if (const auto *Proto = dyn_cast<FunctionProtoType>(FType))
- if (N < Proto->getNumParams()) {
- if (ParamType.isNull())
- ParamType = Proto->getParamType(N);
- else if (!SemaRef.Context.hasSameUnqualifiedType(
- ParamType.getNonReferenceType(),
- Proto->getParamType(N).getNonReferenceType()))
- // Otherwise return a default-constructed QualType.
- return QualType();
- }
+ QualType CandidateParamType = Candidate.getParamType(N);
+ if (CandidateParamType.isNull())
+ continue;
+ if (ParamType.isNull()) {
+ ParamType = CandidateParamType;
+ continue;
+ }
+ if (!SemaRef.Context.hasSameUnqualifiedType(
+ ParamType.getNonReferenceType(),
+ CandidateParamType.getNonReferenceType()))
+ // Two conflicting types, give up.
+ return QualType();
}
return ParamType;
}
static QualType
-ProduceSignatureHelp(Sema &SemaRef, Scope *S,
- MutableArrayRef<ResultCandidate> Candidates,
- unsigned CurrentArg, SourceLocation OpenParLoc) {
+ProduceSignatureHelp(Sema &SemaRef, MutableArrayRef<ResultCandidate> Candidates,
+ unsigned CurrentArg, SourceLocation OpenParLoc,
+ bool Braced) {
if (Candidates.empty())
return QualType();
if (SemaRef.getPreprocessor().isCodeCompletionReached())
SemaRef.CodeCompleter->ProcessOverloadCandidates(
- SemaRef, CurrentArg, Candidates.data(), Candidates.size(), OpenParLoc);
+ SemaRef, CurrentArg, Candidates.data(), Candidates.size(), OpenParLoc,
+ Braced);
return getParamType(SemaRef, Candidates, CurrentArg);
}
-QualType Sema::ProduceCallSignatureHelp(Scope *S, Expr *Fn,
- ArrayRef<Expr *> Args,
+QualType Sema::ProduceCallSignatureHelp(Expr *Fn, ArrayRef<Expr *> Args,
SourceLocation OpenParLoc) {
Fn = unwrapParenList(Fn);
if (!CodeCompleter || !Fn)
@@ -5969,53 +6089,158 @@ QualType Sema::ProduceCallSignatureHelp(Scope *S, Expr *Fn,
}
}
mergeCandidatesWithResults(*this, Results, CandidateSet, Loc, Args.size());
- QualType ParamType =
- ProduceSignatureHelp(*this, S, Results, Args.size(), OpenParLoc);
+ QualType ParamType = ProduceSignatureHelp(*this, Results, Args.size(),
+ OpenParLoc, /*Braced=*/false);
return !CandidateSet.empty() ? ParamType : QualType();
}
-QualType Sema::ProduceConstructorSignatureHelp(Scope *S, QualType Type,
+// Determine which param to continue aggregate initialization from after
+// a designated initializer.
+//
+// Given struct S { int a,b,c,d,e; }:
+// after `S{.b=1,` we want to suggest c to continue
+// after `S{.b=1, 2,` we continue with d (this is legal C and ext in C++)
+// after `S{.b=1, .a=2,` we continue with b (this is legal C and ext in C++)
+//
+// Possible outcomes:
+// - we saw a designator for a field, and continue from the returned index.
+// Only aggregate initialization is allowed.
+// - we saw a designator, but it was complex or we couldn't find the field.
+// Only aggregate initialization is possible, but we can't assist with it.
+// Returns an out-of-range index.
+// - we saw no designators, just positional arguments.
+// Returns None.
+static llvm::Optional<unsigned>
+getNextAggregateIndexAfterDesignatedInit(const ResultCandidate &Aggregate,
+ ArrayRef<Expr *> Args) {
+ static constexpr unsigned Invalid = std::numeric_limits<unsigned>::max();
+ assert(Aggregate.getKind() == ResultCandidate::CK_Aggregate);
+
+ // Look for designated initializers.
+ // They're in their syntactic form, not yet resolved to fields.
+ IdentifierInfo *DesignatedFieldName = nullptr;
+ unsigned ArgsAfterDesignator = 0;
+ for (const Expr *Arg : Args) {
+ if (const auto *DIE = dyn_cast<DesignatedInitExpr>(Arg)) {
+ if (DIE->size() == 1 && DIE->getDesignator(0)->isFieldDesignator()) {
+ DesignatedFieldName = DIE->getDesignator(0)->getFieldName();
+ ArgsAfterDesignator = 0;
+ } else {
+ return Invalid; // Complicated designator.
+ }
+ } else if (isa<DesignatedInitUpdateExpr>(Arg)) {
+ return Invalid; // Unsupported.
+ } else {
+ ++ArgsAfterDesignator;
+ }
+ }
+ if (!DesignatedFieldName)
+ return llvm::None;
+
+ // Find the index within the class's fields.
+ // (Probing getParamDecl() directly would be quadratic in number of fields).
+ unsigned DesignatedIndex = 0;
+ const FieldDecl *DesignatedField = nullptr;
+ for (const auto *Field : Aggregate.getAggregate()->fields()) {
+ if (Field->getIdentifier() == DesignatedFieldName) {
+ DesignatedField = Field;
+ break;
+ }
+ ++DesignatedIndex;
+ }
+ if (!DesignatedField)
+ return Invalid; // Designator referred to a missing field, give up.
+
+ // Find the index within the aggregate (which may have leading bases).
+ unsigned AggregateSize = Aggregate.getNumParams();
+ while (DesignatedIndex < AggregateSize &&
+ Aggregate.getParamDecl(DesignatedIndex) != DesignatedField)
+ ++DesignatedIndex;
+
+ // Continue from the index after the last named field.
+ return DesignatedIndex + ArgsAfterDesignator + 1;
+}
+
+QualType Sema::ProduceConstructorSignatureHelp(QualType Type,
SourceLocation Loc,
ArrayRef<Expr *> Args,
- SourceLocation OpenParLoc) {
+ SourceLocation OpenParLoc,
+ bool Braced) {
if (!CodeCompleter)
return QualType();
+ SmallVector<ResultCandidate, 8> Results;
// A complete type is needed to lookup for constructors.
- CXXRecordDecl *RD =
- isCompleteType(Loc, Type) ? Type->getAsCXXRecordDecl() : nullptr;
+ RecordDecl *RD =
+ isCompleteType(Loc, Type) ? Type->getAsRecordDecl() : nullptr;
if (!RD)
return Type;
+ CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD);
+
+ // Consider aggregate initialization.
+ // We don't check that types so far are correct.
+ // We also don't handle C99/C++17 brace-elision, we assume init-list elements
+ // are 1:1 with fields.
+ // FIXME: it would be nice to support "unwrapping" aggregates that contain
+ // a single subaggregate, like std::array<T, N> -> T __elements[N].
+ if (Braced && !RD->isUnion() &&
+ (!LangOpts.CPlusPlus || (CRD && CRD->isAggregate()))) {
+ ResultCandidate AggregateSig(RD);
+ unsigned AggregateSize = AggregateSig.getNumParams();
+
+ if (auto NextIndex =
+ getNextAggregateIndexAfterDesignatedInit(AggregateSig, Args)) {
+ // A designator was used, only aggregate init is possible.
+ if (*NextIndex >= AggregateSize)
+ return Type;
+ Results.push_back(AggregateSig);
+ return ProduceSignatureHelp(*this, Results, *NextIndex, OpenParLoc,
+ Braced);
+ }
+
+ // Describe aggregate initialization, but also constructors below.
+ if (Args.size() < AggregateSize)
+ Results.push_back(AggregateSig);
+ }
// FIXME: Provide support for member initializers.
// FIXME: Provide support for variadic template constructors.
- OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
+ if (CRD) {
+ OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
+ for (NamedDecl *C : LookupConstructors(CRD)) {
+ if (auto *FD = dyn_cast<FunctionDecl>(C)) {
+ // FIXME: we can't yet provide correct signature help for initializer
+ // list constructors, so skip them entirely.
+ if (Braced && LangOpts.CPlusPlus && isInitListConstructor(FD))
+ continue;
+ AddOverloadCandidate(FD, DeclAccessPair::make(FD, C->getAccess()), Args,
+ CandidateSet,
+ /*SuppressUserConversions=*/false,
+ /*PartialOverloading=*/true,
+ /*AllowExplicit*/ true);
+ } else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(C)) {
+ if (Braced && LangOpts.CPlusPlus &&
+ isInitListConstructor(FTD->getTemplatedDecl()))
+ continue;
- for (NamedDecl *C : LookupConstructors(RD)) {
- if (auto *FD = dyn_cast<FunctionDecl>(C)) {
- AddOverloadCandidate(FD, DeclAccessPair::make(FD, C->getAccess()), Args,
- CandidateSet,
- /*SuppressUserConversions=*/false,
- /*PartialOverloading=*/true,
- /*AllowExplicit*/ true);
- } else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(C)) {
- AddTemplateOverloadCandidate(
- FTD, DeclAccessPair::make(FTD, C->getAccess()),
- /*ExplicitTemplateArgs=*/nullptr, Args, CandidateSet,
- /*SuppressUserConversions=*/false,
- /*PartialOverloading=*/true);
+ AddTemplateOverloadCandidate(
+ FTD, DeclAccessPair::make(FTD, C->getAccess()),
+ /*ExplicitTemplateArgs=*/nullptr, Args, CandidateSet,
+ /*SuppressUserConversions=*/false,
+ /*PartialOverloading=*/true);
+ }
}
+ mergeCandidatesWithResults(*this, Results, CandidateSet, Loc, Args.size());
}
- SmallVector<ResultCandidate, 8> Results;
- mergeCandidatesWithResults(*this, Results, CandidateSet, Loc, Args.size());
- return ProduceSignatureHelp(*this, S, Results, Args.size(), OpenParLoc);
+ return ProduceSignatureHelp(*this, Results, Args.size(), OpenParLoc, Braced);
}
QualType Sema::ProduceCtorInitMemberSignatureHelp(
- Scope *S, Decl *ConstructorDecl, CXXScopeSpec SS, ParsedType TemplateTypeTy,
- ArrayRef<Expr *> ArgExprs, IdentifierInfo *II, SourceLocation OpenParLoc) {
+ Decl *ConstructorDecl, CXXScopeSpec SS, ParsedType TemplateTypeTy,
+ ArrayRef<Expr *> ArgExprs, IdentifierInfo *II, SourceLocation OpenParLoc,
+ bool Braced) {
if (!CodeCompleter)
return QualType();
@@ -6026,12 +6251,66 @@ QualType Sema::ProduceCtorInitMemberSignatureHelp(
// FIXME: Add support for Base class constructors as well.
if (ValueDecl *MemberDecl = tryLookupCtorInitMemberDecl(
Constructor->getParent(), SS, TemplateTypeTy, II))
- return ProduceConstructorSignatureHelp(getCurScope(), MemberDecl->getType(),
+ return ProduceConstructorSignatureHelp(MemberDecl->getType(),
MemberDecl->getLocation(), ArgExprs,
- OpenParLoc);
+ OpenParLoc, Braced);
return QualType();
}
+static bool argMatchesTemplateParams(const ParsedTemplateArgument &Arg,
+ unsigned Index,
+ const TemplateParameterList &Params) {
+ const NamedDecl *Param;
+ if (Index < Params.size())
+ Param = Params.getParam(Index);
+ else if (Params.hasParameterPack())
+ Param = Params.asArray().back();
+ else
+ return false; // too many args
+
+ switch (Arg.getKind()) {
+ case ParsedTemplateArgument::Type:
+ return llvm::isa<TemplateTypeParmDecl>(Param); // constraints not checked
+ case ParsedTemplateArgument::NonType:
+ return llvm::isa<NonTypeTemplateParmDecl>(Param); // type not checked
+ case ParsedTemplateArgument::Template:
+ return llvm::isa<TemplateTemplateParmDecl>(Param); // signature not checked
+ }
+ llvm_unreachable("Unhandled switch case");
+}
+
+QualType Sema::ProduceTemplateArgumentSignatureHelp(
+ TemplateTy ParsedTemplate, ArrayRef<ParsedTemplateArgument> Args,
+ SourceLocation LAngleLoc) {
+ if (!CodeCompleter || !ParsedTemplate)
+ return QualType();
+
+ SmallVector<ResultCandidate, 8> Results;
+ auto Consider = [&](const TemplateDecl *TD) {
+ // Only add if the existing args are compatible with the template.
+ bool Matches = true;
+ for (unsigned I = 0; I < Args.size(); ++I) {
+ if (!argMatchesTemplateParams(Args[I], I, *TD->getTemplateParameters())) {
+ Matches = false;
+ break;
+ }
+ }
+ if (Matches)
+ Results.emplace_back(TD);
+ };
+
+ TemplateName Template = ParsedTemplate.get();
+ if (const auto *TD = Template.getAsTemplateDecl()) {
+ Consider(TD);
+ } else if (const auto *OTS = Template.getAsOverloadedTemplate()) {
+ for (const NamedDecl *ND : *OTS)
+ if (const auto *TD = llvm::dyn_cast<TemplateDecl>(ND))
+ Consider(TD);
+ }
+ return ProduceSignatureHelp(*this, Results, Args.size(), LAngleLoc,
+ /*Braced=*/false);
+}
+
static QualType getDesignatedType(QualType BaseType, const Designation &Desig) {
for (unsigned I = 0; I < Desig.getNumDesignators(); ++I) {
if (BaseType.isNull())
@@ -6073,7 +6352,15 @@ void Sema::CodeCompleteDesignator(QualType BaseType,
CodeCompleter->getCodeCompletionTUInfo(), CCC);
Results.EnterNewScope();
- for (const auto *FD : RD->fields()) {
+ for (const Decl *D : RD->decls()) {
+ const FieldDecl *FD;
+ if (auto *IFD = dyn_cast<IndirectFieldDecl>(D))
+ FD = IFD->getAnonField();
+ else if (auto *DFD = dyn_cast<FieldDecl>(D))
+ FD = DFD;
+ else
+ continue;
+
// FIXME: Make use of previous designators to mark any fields before those
// inaccessible, and also compute the next initializer priority.
ResultBuilder::Result Result(FD, Results.getBasePriority(FD));
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 466e37831f66..ce99d4848cca 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -18,7 +18,6 @@
#include "clang/Sema/Template.h"
#include "clang/Sema/Overload.h"
#include "clang/Sema/Initialization.h"
-#include "clang/Sema/SemaInternal.h"
#include "clang/AST/ExprConcepts.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/OperatorPrecedence.h"
@@ -1058,7 +1057,7 @@ concepts::ExprRequirement::ExprRequirement(
concepts::ExprRequirement::ReturnTypeRequirement::
ReturnTypeRequirement(TemplateParameterList *TPL) :
- TypeConstraintInfo(TPL, 0) {
+ TypeConstraintInfo(TPL, false) {
assert(TPL->size() == 1);
const TypeConstraint *TC =
cast<TemplateTypeParmDecl>(TPL->getParam(0))->getTypeConstraint();
@@ -1070,7 +1069,7 @@ ReturnTypeRequirement(TemplateParameterList *TPL) :
Constraint->getTemplateArgsAsWritten() &&
TemplateSpecializationType::anyInstantiationDependentTemplateArguments(
Constraint->getTemplateArgsAsWritten()->arguments().drop_front(1));
- TypeConstraintInfo.setInt(Dependent ? 1 : 0);
+ TypeConstraintInfo.setInt(Dependent ? true : false);
}
concepts::TypeRequirement::TypeRequirement(TypeSourceInfo *T) :
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index e89cecd08cca..e7e60b7e7daf 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -653,7 +653,7 @@ static void checkNoThrow(Sema &S, const Stmt *E,
}
if (ThrowingDecls.empty()) {
// [dcl.fct.def.coroutine]p15
- // The expression co_­await promise.final_­suspend() shall not be
+ // The expression co_await promise.final_suspend() shall not be
// potentially-throwing ([except.spec]).
//
// First time seeing an error, emit the error message.
@@ -663,32 +663,32 @@ static void checkNoThrow(Sema &S, const Stmt *E,
ThrowingDecls.insert(D);
}
};
- auto SC = E->getStmtClass();
- if (SC == Expr::CXXConstructExprClass) {
- auto const *Ctor = cast<CXXConstructExpr>(E)->getConstructor();
+
+ if (auto *CE = dyn_cast<CXXConstructExpr>(E)) {
+ CXXConstructorDecl *Ctor = CE->getConstructor();
checkDeclNoexcept(Ctor);
// Check the corresponding destructor of the constructor.
- checkDeclNoexcept(Ctor->getParent()->getDestructor(), true);
- } else if (SC == Expr::CallExprClass || SC == Expr::CXXMemberCallExprClass ||
- SC == Expr::CXXOperatorCallExprClass) {
- if (!cast<CallExpr>(E)->isTypeDependent()) {
- checkDeclNoexcept(cast<CallExpr>(E)->getCalleeDecl());
- auto ReturnType = cast<CallExpr>(E)->getCallReturnType(S.getASTContext());
- // Check the destructor of the call return type, if any.
- if (ReturnType.isDestructedType() ==
- QualType::DestructionKind::DK_cxx_destructor) {
- const auto *T =
- cast<RecordType>(ReturnType.getCanonicalType().getTypePtr());
- checkDeclNoexcept(
- dyn_cast<CXXRecordDecl>(T->getDecl())->getDestructor(), true);
- }
+ checkDeclNoexcept(Ctor->getParent()->getDestructor(), /*IsDtor=*/true);
+ } else if (auto *CE = dyn_cast<CallExpr>(E)) {
+ if (CE->isTypeDependent())
+ return;
+
+ checkDeclNoexcept(CE->getCalleeDecl());
+ QualType ReturnType = CE->getCallReturnType(S.getASTContext());
+ // Check the destructor of the call return type, if any.
+ if (ReturnType.isDestructedType() ==
+ QualType::DestructionKind::DK_cxx_destructor) {
+ const auto *T =
+ cast<RecordType>(ReturnType.getCanonicalType().getTypePtr());
+ checkDeclNoexcept(dyn_cast<CXXRecordDecl>(T->getDecl())->getDestructor(),
+ /*IsDtor=*/true);
+ }
+ } else
+ for (const auto *Child : E->children()) {
+ if (!Child)
+ continue;
+ checkNoThrow(S, Child, ThrowingDecls);
}
- }
- for (const auto *Child : E->children()) {
- if (!Child)
- continue;
- checkNoThrow(S, Child, ThrowingDecls);
- }
}
bool Sema::checkFinalSuspendNoThrow(const Stmt *FinalSuspend) {
@@ -1184,13 +1184,13 @@ bool CoroutineStmtBuilder::makeReturnOnAllocFailure() {
"cannot make statement while the promise type is dependent");
// [dcl.fct.def.coroutine]p10
- // If a search for the name get_­return_­object_­on_­allocation_­failure in
+ // If a search for the name get_return_object_on_allocation_failure in
// the scope of the promise type ([class.member.lookup]) finds any
// declarations, then the result of a call to an allocation function used to
// obtain storage for the coroutine state is assumed to return nullptr if it
// fails to obtain storage, ... If the allocation function returns nullptr,
// ... and the return value is obtained by a call to
- // T::get_­return_­object_­on_­allocation_­failure(), where T is the
+ // T::get_return_object_on_allocation_failure(), where T is the
// promise type.
DeclarationName DN =
S.PP.getIdentifierInfo("get_return_object_on_allocation_failure");
@@ -1433,10 +1433,10 @@ bool CoroutineStmtBuilder::makeOnFallthrough() {
"cannot make statement while the promise type is dependent");
// [dcl.fct.def.coroutine]/p6
- // If searches for the names return_­void and return_­value in the scope of
+ // If searches for the names return_void and return_value in the scope of
// the promise type each find any declarations, the program is ill-formed.
- // [Note 1: If return_­void is found, flowing off the end of a coroutine is
- // equivalent to a co_­return with no operand. Otherwise, flowing off the end
+ // [Note 1: If return_void is found, flowing off the end of a coroutine is
+ // equivalent to a co_return with no operand. Otherwise, flowing off the end
// of a coroutine results in undefined behavior ([stmt.return.coroutine]). —
// end note]
bool HasRVoid, HasRValue;
@@ -1529,7 +1529,7 @@ bool CoroutineStmtBuilder::makeOnException() {
bool CoroutineStmtBuilder::makeReturnObject() {
// [dcl.fct.def.coroutine]p7
- // The expression promise.get_­return_­object() is used to initialize the
+ // The expression promise.get_return_object() is used to initialize the
// returned reference or prvalue result object of a call to a coroutine.
ExprResult ReturnObject =
buildPromiseCall(S, Fn.CoroutinePromise, Loc, "get_return_object", None);
@@ -1740,30 +1740,39 @@ ClassTemplateDecl *Sema::lookupCoroutineTraits(SourceLocation KwLoc,
return nullptr;
}
- if (!InStd) {
- // Found only in std::experimental.
- Diag(KwLoc, diag::warn_deprecated_coroutine_namespace)
- << "coroutine_traits";
- } else if (InExp) {
- // Found in std and std::experimental.
- Diag(KwLoc,
- diag::err_mixed_use_std_and_experimental_namespace_for_coroutine);
- Diag(KwLoc, diag::warn_deprecated_coroutine_namespace)
- << "coroutine_traits";
- return nullptr;
- }
-
// Prefer ::std to std::experimental.
auto &Result = InStd ? ResStd : ResExp;
CoroTraitsNamespaceCache = InStd ? StdSpace : ExpSpace;
// coroutine_traits is required to be a class template.
- if (!(StdCoroutineTraitsCache = Result.getAsSingle<ClassTemplateDecl>())) {
+ StdCoroutineTraitsCache = Result.getAsSingle<ClassTemplateDecl>();
+ if (!StdCoroutineTraitsCache) {
Result.suppressDiagnostics();
NamedDecl *Found = *Result.begin();
Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits);
return nullptr;
}
+
+ if (InExp) {
+ // Found in std::experimental
+ Diag(KwLoc, diag::warn_deprecated_coroutine_namespace)
+ << "coroutine_traits";
+ ResExp.suppressDiagnostics();
+ auto *Found = *ResExp.begin();
+ Diag(Found->getLocation(), diag::note_entity_declared_at) << Found;
+
+ if (InStd &&
+ StdCoroutineTraitsCache != ResExp.getAsSingle<ClassTemplateDecl>()) {
+ // Also found something different in std
+ Diag(KwLoc,
+ diag::err_mixed_use_std_and_experimental_namespace_for_coroutine);
+ Diag(StdCoroutineTraitsCache->getLocation(),
+ diag::note_entity_declared_at)
+ << StdCoroutineTraitsCache;
+
+ return nullptr;
+ }
+ }
}
Namespace = CoroTraitsNamespaceCache;
return StdCoroutineTraitsCache;
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 3c58f1d19c04..3252671991b7 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -1586,10 +1586,13 @@ void Sema::FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S,
/// We've determined that \p New is a redeclaration of \p Old. Check that they
/// have compatible owning modules.
bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) {
- // FIXME: The Modules TS is not clear about how friend declarations are
- // to be treated. It's not meaningful to have different owning modules for
- // linkage in redeclarations of the same entity, so for now allow the
- // redeclaration and change the owning modules to match.
+ // [module.interface]p7:
+ // A declaration is attached to a module as follows:
+ // - If the declaration is a non-dependent friend declaration that nominates a
+ // function with a declarator-id that is a qualified-id or template-id or that
+ // nominates a class other than with an elaborated-type-specifier with neither
+ // a nested-name-specifier nor a simple-template-id, it is attached to the
+ // module to which the friend is attached ([basic.link]).
if (New->getFriendObjectKind() &&
Old->getOwningModuleForLinkage() != New->getOwningModuleForLinkage()) {
New->setLocalOwningModule(Old->getOwningModule());
@@ -1628,6 +1631,52 @@ bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) {
return false;
}
+// [module.interface]p6:
+// A redeclaration of an entity X is implicitly exported if X was introduced by
+// an exported declaration; otherwise it shall not be exported.
+bool Sema::CheckRedeclarationExported(NamedDecl *New, NamedDecl *Old) {
+ // [module.interface]p1:
+ // An export-declaration shall inhabit a namespace scope.
+ //
+ // So it is meaningless to talk about redeclaration which is not at namespace
+ // scope.
+ if (!New->getLexicalDeclContext()
+ ->getNonTransparentContext()
+ ->isFileContext() ||
+ !Old->getLexicalDeclContext()
+ ->getNonTransparentContext()
+ ->isFileContext())
+ return false;
+
+ bool IsNewExported = New->isInExportDeclContext();
+ bool IsOldExported = Old->isInExportDeclContext();
+
+ // It should be irrevelant if both of them are not exported.
+ if (!IsNewExported && !IsOldExported)
+ return false;
+
+ if (IsOldExported)
+ return false;
+
+ assert(IsNewExported);
+
+ Diag(New->getLocation(), diag::err_redeclaration_non_exported) << New;
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+ return true;
+}
+
+// A wrapper function for checking the semantic restrictions of
+// a redeclaration within a module.
+bool Sema::CheckRedeclarationInModule(NamedDecl *New, NamedDecl *Old) {
+ if (CheckRedeclarationModuleOwnership(New, Old))
+ return true;
+
+ if (CheckRedeclarationExported(New, Old))
+ return true;
+
+ return false;
+}
+
static bool isUsingDecl(NamedDecl *D) {
return isa<UsingShadowDecl>(D) ||
isa<UnresolvedUsingTypenameDecl>(D) ||
@@ -3390,7 +3439,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
}
}
- if (CheckRedeclarationModuleOwnership(New, Old))
+ if (CheckRedeclarationInModule(New, Old))
return true;
if (!getLangOpts().CPlusPlus) {
@@ -4269,7 +4318,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
return New->setInvalidDecl();
}
- if (CheckRedeclarationModuleOwnership(New, Old))
+ if (CheckRedeclarationInModule(New, Old))
return;
// Variables with external linkage are analyzed in FinalizeDeclaratorGroup.
@@ -5759,7 +5808,15 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
else if (isa<BlockDecl>(Cur))
Diag(Loc, diag::err_invalid_declarator_in_block)
<< Name << SS.getRange();
- else
+ else if (isa<ExportDecl>(Cur)) {
+ if (!isa<NamespaceDecl>(DC))
+ Diag(Loc, diag::err_export_non_namespace_scope_name)
+ << Name << SS.getRange();
+ else
+ // The cases that DC is not NamespaceDecl should be handled in
+ // CheckRedeclarationExported.
+ return false;
+ } else
Diag(Loc, diag::err_invalid_declarator_scope)
<< Name << cast<NamedDecl>(Cur) << cast<NamedDecl>(DC) << SS.getRange();
@@ -7798,8 +7855,6 @@ void Sema::CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl,
DeclarationName Name = R.getLookupName();
// Emit warning and note.
- if (getSourceManager().isInSystemMacro(R.getNameLoc()))
- return;
ShadowedDeclKind Kind = computeShadowedDeclKind(ShadowedDecl, OldDC);
Diag(R.getNameLoc(), WarningDiag) << Name << Kind << OldDC;
if (!CaptureLoc.isInvalid())
@@ -9128,6 +9183,13 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_in_union);
NewFD->setInvalidDecl();
}
+ if ((Parent->isClass() || Parent->isStruct()) &&
+ Parent->hasAttr<SYCLSpecialClassAttr>() &&
+ NewFD->getKind() == Decl::Kind::CXXMethod &&
+ NewFD->getName() == "__init" && D.isFunctionDefinition()) {
+ if (auto *Def = Parent->getDefinition())
+ Def->setInitMethod(true);
+ }
}
SetNestedNameSpecifier(*this, NewFD, D);
@@ -9921,7 +9983,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
<< NewFD;
// Turn this into a variadic function with no parameters.
- const FunctionType *FT = NewFD->getType()->getAs<FunctionType>();
+ const auto *FT = NewFD->getType()->castAs<FunctionType>();
FunctionProtoType::ExtProtoInfo EPI(
Context.getDefaultCallingConvention(true, false));
EPI.Variadic = true;
@@ -14632,8 +14694,10 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
Diag(FD->getLocation(), diag::ext_pure_function_definition);
if (!FD->isInvalidDecl()) {
- // Don't diagnose unused parameters of defaulted or deleted functions.
- if (!FD->isDeleted() && !FD->isDefaulted() && !FD->hasSkippedBody())
+ // Don't diagnose unused parameters of defaulted, deleted or naked
+ // functions.
+ if (!FD->isDeleted() && !FD->isDefaulted() && !FD->hasSkippedBody() &&
+ !FD->hasAttr<NakedAttr>())
DiagnoseUnusedParameters(FD->parameters());
DiagnoseSizeOfParametersAndReturnValue(FD->parameters(),
FD->getReturnType(), FD);
@@ -15002,7 +15066,24 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
diag_id = diag::ext_implicit_function_decl;
else
diag_id = diag::warn_implicit_function_decl;
+
+ TypoCorrection Corrected;
+ // Because typo correction is expensive, only do it if the implicit
+ // function declaration is going to be treated as an error.
+ //
+ // Perform the corection before issuing the main diagnostic, as some consumers
+ // use typo-correction callbacks to enhance the main diagnostic.
+ if (S && !ExternCPrev &&
+ (Diags.getDiagnosticLevel(diag_id, Loc) >= DiagnosticsEngine::Error)) {
+ DeclFilterCCC<FunctionDecl> CCC{};
+ Corrected = CorrectTypo(DeclarationNameInfo(&II, Loc), LookupOrdinaryName,
+ S, nullptr, CCC, CTK_NonError);
+ }
+
Diag(Loc, diag_id) << &II;
+ if (Corrected)
+ diagnoseTypo(Corrected, PDiag(diag::note_function_suggestion),
+ /*ErrorRecovery*/ false);
// If we found a prior declaration of this function, don't bother building
// another one. We've already pushed that one into scope, so there's nothing
@@ -15010,18 +15091,6 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
if (ExternCPrev)
return ExternCPrev;
- // Because typo correction is expensive, only do it if the implicit
- // function declaration is going to be treated as an error.
- if (Diags.getDiagnosticLevel(diag_id, Loc) >= DiagnosticsEngine::Error) {
- TypoCorrection Corrected;
- DeclFilterCCC<FunctionDecl> CCC{};
- if (S && (Corrected =
- CorrectTypo(DeclarationNameInfo(&II, Loc), LookupOrdinaryName,
- S, nullptr, CCC, CTK_NonError)))
- diagnoseTypo(Corrected, PDiag(diag::note_function_suggestion),
- /*ErrorRecovery*/false);
- }
-
// Set a Declarator for the implicit definition: int foo();
const char *Dummy;
AttributeFactory attrFactory;
@@ -15191,11 +15260,11 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
Context.BuiltinInfo.isConstWithoutErrno(BuiltinID))
FD->addAttr(ConstAttr::CreateImplicit(Context, FD->getLocation()));
- // We make "fma" on some platforms const because we know it does not set
+ // We make "fma" on GNU or Windows const because we know it does not set
// errno in those environments even though it could set errno based on the
// C standard.
const llvm::Triple &Trip = Context.getTargetInfo().getTriple();
- if ((Trip.isGNUEnvironment() || Trip.isAndroid() || Trip.isOSMSVCRT()) &&
+ if ((Trip.isGNUEnvironment() || Trip.isOSMSVCRT()) &&
!FD->hasAttr<ConstAttr>()) {
switch (BuiltinID) {
case Builtin::BI__builtin_fma:
@@ -16532,7 +16601,7 @@ CreateNewDecl:
SetMemberAccessSpecifier(New, PrevDecl, AS);
if (PrevDecl)
- CheckRedeclarationModuleOwnership(New, PrevDecl);
+ CheckRedeclarationInModule(New, PrevDecl);
if (TUK == TUK_Definition && (!SkipBody || !SkipBody->ShouldSkip))
New->startDefinition();
@@ -16682,8 +16751,21 @@ void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD,
RD->completeDefinition();
}
- if (isa<CXXRecordDecl>(Tag)) {
+ if (auto *RD = dyn_cast<CXXRecordDecl>(Tag)) {
FieldCollector->FinishClass();
+ if (RD->hasAttr<SYCLSpecialClassAttr>()) {
+ auto *Def = RD->getDefinition();
+ assert(Def && "The record is expected to have a completed definition");
+ unsigned NumInitMethods = 0;
+ for (auto *Method : Def->methods()) {
+ if (!Method->getIdentifier())
+ continue;
+ if (Method->getName() == "__init")
+ NumInitMethods++;
+ }
+ if (NumInitMethods > 1 || !Def->hasInitMethod())
+ Diag(RD->getLocation(), diag::err_sycl_special_type_num_init_method);
+ }
}
// Exit this scope of this tag's definition.
@@ -18586,7 +18668,7 @@ void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name,
AttributeCommonInfo Info(AliasName, SourceRange(AliasNameLoc),
AttributeCommonInfo::AS_Pragma);
AsmLabelAttr *Attr = AsmLabelAttr::CreateImplicit(
- Context, AliasName->getName(), /*LiteralLabel=*/true, Info);
+ Context, AliasName->getName(), /*IsLiteralLabel=*/true, Info);
// If a declaration that:
// 1) declares a function or a variable
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index b6bd2e69629d..f04236ab96c3 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -2625,37 +2625,53 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
NewII = &S.Context.Idents.get("watchos_app_extension");
if (NewII) {
- auto adjustWatchOSVersion = [](VersionTuple Version) -> VersionTuple {
- if (Version.empty())
- return Version;
- auto Major = Version.getMajor();
- auto NewMajor = Major >= 9 ? Major - 7 : 0;
- if (NewMajor >= 2) {
- if (Version.getMinor().hasValue()) {
- if (Version.getSubminor().hasValue())
- return VersionTuple(NewMajor, Version.getMinor().getValue(),
- Version.getSubminor().getValue());
- else
- return VersionTuple(NewMajor, Version.getMinor().getValue());
- }
- return VersionTuple(NewMajor);
+ const auto *SDKInfo = S.getDarwinSDKInfoForAvailabilityChecking();
+ const auto *IOSToWatchOSMapping =
+ SDKInfo ? SDKInfo->getVersionMapping(
+ DarwinSDKInfo::OSEnvPair::iOStoWatchOSPair())
+ : nullptr;
+
+ auto adjustWatchOSVersion =
+ [IOSToWatchOSMapping](VersionTuple Version) -> VersionTuple {
+ if (Version.empty())
+ return Version;
+ auto MinimumWatchOSVersion = VersionTuple(2, 0);
+
+ if (IOSToWatchOSMapping) {
+ if (auto MappedVersion = IOSToWatchOSMapping->map(
+ Version, MinimumWatchOSVersion, None)) {
+ return MappedVersion.getValue();
}
+ }
- return VersionTuple(2, 0);
- };
+ auto Major = Version.getMajor();
+ auto NewMajor = Major >= 9 ? Major - 7 : 0;
+ if (NewMajor >= 2) {
+ if (Version.getMinor().hasValue()) {
+ if (Version.getSubminor().hasValue())
+ return VersionTuple(NewMajor, Version.getMinor().getValue(),
+ Version.getSubminor().getValue());
+ else
+ return VersionTuple(NewMajor, Version.getMinor().getValue());
+ }
+ return VersionTuple(NewMajor);
+ }
- auto NewIntroduced = adjustWatchOSVersion(Introduced.Version);
- auto NewDeprecated = adjustWatchOSVersion(Deprecated.Version);
- auto NewObsoleted = adjustWatchOSVersion(Obsoleted.Version);
+ return MinimumWatchOSVersion;
+ };
- AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
- ND, AL, NewII, true /*Implicit*/, NewIntroduced, NewDeprecated,
- NewObsoleted, IsUnavailable, Str, IsStrict, Replacement,
- Sema::AMK_None,
- PriorityModifier + Sema::AP_InferredFromOtherPlatform);
- if (NewAttr)
- D->addAttr(NewAttr);
- }
+ auto NewIntroduced = adjustWatchOSVersion(Introduced.Version);
+ auto NewDeprecated = adjustWatchOSVersion(Deprecated.Version);
+ auto NewObsoleted = adjustWatchOSVersion(Obsoleted.Version);
+
+ AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
+ ND, AL, NewII, true /*Implicit*/, NewIntroduced, NewDeprecated,
+ NewObsoleted, IsUnavailable, Str, IsStrict, Replacement,
+ Sema::AMK_None,
+ PriorityModifier + Sema::AP_InferredFromOtherPlatform);
+ if (NewAttr)
+ D->addAttr(NewAttr);
+ }
} else if (S.Context.getTargetInfo().getTriple().isTvOS()) {
// Transcribe "ios" to "tvos" (and add a new attribute) if the versioning
// matches before the start of the tvOS platform.
@@ -2666,14 +2682,38 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
NewII = &S.Context.Idents.get("tvos_app_extension");
if (NewII) {
+ const auto *SDKInfo = S.getDarwinSDKInfoForAvailabilityChecking();
+ const auto *IOSToTvOSMapping =
+ SDKInfo ? SDKInfo->getVersionMapping(
+ DarwinSDKInfo::OSEnvPair::iOStoTvOSPair())
+ : nullptr;
+
+ auto AdjustTvOSVersion =
+ [IOSToTvOSMapping](VersionTuple Version) -> VersionTuple {
+ if (Version.empty())
+ return Version;
+
+ if (IOSToTvOSMapping) {
+ if (auto MappedVersion =
+ IOSToTvOSMapping->map(Version, VersionTuple(0, 0), None)) {
+ return MappedVersion.getValue();
+ }
+ }
+ return Version;
+ };
+
+ auto NewIntroduced = AdjustTvOSVersion(Introduced.Version);
+ auto NewDeprecated = AdjustTvOSVersion(Deprecated.Version);
+ auto NewObsoleted = AdjustTvOSVersion(Obsoleted.Version);
+
AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
- ND, AL, NewII, true /*Implicit*/, Introduced.Version,
- Deprecated.Version, Obsoleted.Version, IsUnavailable, Str, IsStrict,
- Replacement, Sema::AMK_None,
+ ND, AL, NewII, true /*Implicit*/, NewIntroduced, NewDeprecated,
+ NewObsoleted, IsUnavailable, Str, IsStrict, Replacement,
+ Sema::AMK_None,
PriorityModifier + Sema::AP_InferredFromOtherPlatform);
if (NewAttr)
D->addAttr(NewAttr);
- }
+ }
} else if (S.Context.getTargetInfo().getTriple().getOS() ==
llvm::Triple::IOS &&
S.Context.getTargetInfo().getTriple().isMacCatalystEnvironment()) {
@@ -8261,6 +8301,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_SYCLKernel:
handleSYCLKernelAttr(S, D, AL);
break;
+ case ParsedAttr::AT_SYCLSpecialClass:
+ handleSimpleAttribute<SYCLSpecialClassAttr>(S, D, AL);
+ break;
case ParsedAttr::AT_Format:
handleFormatAttr(S, D, AL);
break;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 01f0079198c7..16cdb7e57723 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -13012,7 +13012,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS,
NewDecl->setInvalidDecl();
else if (OldDecl) {
NewDecl->setPreviousDecl(OldDecl);
- CheckRedeclarationModuleOwnership(NewDecl, OldDecl);
+ CheckRedeclarationInModule(NewDecl, OldDecl);
}
NewND = NewDecl;
diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp
index d6e659e17069..d4fefc3d18d8 100644
--- a/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/clang/lib/Sema/SemaDeclObjC.cpp
@@ -2212,9 +2212,8 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
Diag(IVI->getLocation(), diag::err_inconsistent_ivar_count);
}
-static void WarnUndefinedMethod(Sema &S, SourceLocation ImpLoc,
- ObjCMethodDecl *method,
- bool &IncompleteImpl,
+static void WarnUndefinedMethod(Sema &S, ObjCImplDecl *Impl,
+ ObjCMethodDecl *method, bool &IncompleteImpl,
unsigned DiagID,
NamedDecl *NeededFor = nullptr) {
// No point warning no definition of method which is 'unavailable'.
@@ -2227,10 +2226,19 @@ static void WarnUndefinedMethod(Sema &S, SourceLocation ImpLoc,
// separate warnings. We will give that approach a try, as that
// matches what we do with protocols.
{
- const Sema::SemaDiagnosticBuilder &B = S.Diag(ImpLoc, DiagID);
+ const Sema::SemaDiagnosticBuilder &B = S.Diag(Impl->getLocation(), DiagID);
B << method;
if (NeededFor)
B << NeededFor;
+
+ // Add an empty definition at the end of the @implementation.
+ std::string FixItStr;
+ llvm::raw_string_ostream Out(FixItStr);
+ method->print(Out, Impl->getASTContext().getPrintingPolicy());
+ Out << " {\n}\n\n";
+
+ SourceLocation Loc = Impl->getAtEndRange().getBegin();
+ B << FixItHint::CreateInsertion(Loc, FixItStr);
}
// Issue a note to the original declaration.
@@ -2679,14 +2687,10 @@ static void findProtocolsWithExplicitImpls(const ObjCInterfaceDecl *Super,
/// CheckProtocolMethodDefs - This routine checks unimplemented methods
/// Declared in protocol, and those referenced by it.
-static void CheckProtocolMethodDefs(Sema &S,
- SourceLocation ImpLoc,
- ObjCProtocolDecl *PDecl,
- bool& IncompleteImpl,
- const Sema::SelectorSet &InsMap,
- const Sema::SelectorSet &ClsMap,
- ObjCContainerDecl *CDecl,
- LazyProtocolNameSet &ProtocolsExplictImpl) {
+static void CheckProtocolMethodDefs(
+ Sema &S, ObjCImplDecl *Impl, ObjCProtocolDecl *PDecl, bool &IncompleteImpl,
+ const Sema::SelectorSet &InsMap, const Sema::SelectorSet &ClsMap,
+ ObjCContainerDecl *CDecl, LazyProtocolNameSet &ProtocolsExplictImpl) {
ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl);
ObjCInterfaceDecl *IDecl = C ? C->getClassInterface()
: dyn_cast<ObjCInterfaceDecl>(CDecl);
@@ -2773,9 +2777,8 @@ static void CheckProtocolMethodDefs(Sema &S,
if (C || MethodInClass->isPropertyAccessor())
continue;
unsigned DIAG = diag::warn_unimplemented_protocol_method;
- if (!S.Diags.isIgnored(DIAG, ImpLoc)) {
- WarnUndefinedMethod(S, ImpLoc, method, IncompleteImpl, DIAG,
- PDecl);
+ if (!S.Diags.isIgnored(DIAG, Impl->getLocation())) {
+ WarnUndefinedMethod(S, Impl, method, IncompleteImpl, DIAG, PDecl);
}
}
}
@@ -2796,15 +2799,15 @@ static void CheckProtocolMethodDefs(Sema &S,
continue;
unsigned DIAG = diag::warn_unimplemented_protocol_method;
- if (!S.Diags.isIgnored(DIAG, ImpLoc)) {
- WarnUndefinedMethod(S, ImpLoc, method, IncompleteImpl, DIAG, PDecl);
+ if (!S.Diags.isIgnored(DIAG, Impl->getLocation())) {
+ WarnUndefinedMethod(S, Impl, method, IncompleteImpl, DIAG, PDecl);
}
}
}
// Check on this protocols's referenced protocols, recursively.
for (auto *PI : PDecl->protocols())
- CheckProtocolMethodDefs(S, ImpLoc, PI, IncompleteImpl, InsMap, ClsMap,
- CDecl, ProtocolsExplictImpl);
+ CheckProtocolMethodDefs(S, Impl, PI, IncompleteImpl, InsMap, ClsMap, CDecl,
+ ProtocolsExplictImpl);
}
/// MatchAllMethodDeclarations - Check methods declared in interface
@@ -2827,7 +2830,7 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
if (!I->isPropertyAccessor() &&
!InsMap.count(I->getSelector())) {
if (ImmediateClass)
- WarnUndefinedMethod(*this, IMPDecl->getLocation(), I, IncompleteImpl,
+ WarnUndefinedMethod(*this, IMPDecl, I, IncompleteImpl,
diag::warn_undef_method_impl);
continue;
} else {
@@ -2857,7 +2860,7 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
if (!I->isPropertyAccessor() &&
!ClsMap.count(I->getSelector())) {
if (ImmediateClass)
- WarnUndefinedMethod(*this, IMPDecl->getLocation(), I, IncompleteImpl,
+ WarnUndefinedMethod(*this, IMPDecl, I, IncompleteImpl,
diag::warn_undef_method_impl);
} else {
ObjCMethodDecl *ImpMethodDecl =
@@ -3024,16 +3027,15 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl> (CDecl)) {
for (auto *PI : I->all_referenced_protocols())
- CheckProtocolMethodDefs(*this, IMPDecl->getLocation(), PI, IncompleteImpl,
- InsMap, ClsMap, I, ExplicitImplProtocols);
+ CheckProtocolMethodDefs(*this, IMPDecl, PI, IncompleteImpl, InsMap,
+ ClsMap, I, ExplicitImplProtocols);
} else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) {
// For extended class, unimplemented methods in its protocols will
// be reported in the primary class.
if (!C->IsClassExtension()) {
for (auto *P : C->protocols())
- CheckProtocolMethodDefs(*this, IMPDecl->getLocation(), P,
- IncompleteImpl, InsMap, ClsMap, CDecl,
- ExplicitImplProtocols);
+ CheckProtocolMethodDefs(*this, IMPDecl, P, IncompleteImpl, InsMap,
+ ClsMap, CDecl, ExplicitImplProtocols);
DiagnoseUnimplementedProperties(S, IMPDecl, CDecl,
/*SynthesizeProperties=*/false);
}
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 3af4c6f4bc41..29cb4be7b1ba 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -391,9 +391,8 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
NewProto->getExtProtoInfo().withExceptionSpec(ESI)));
}
- if (getLangOpts().MSVCCompat && ESI.Type != EST_DependentNoexcept) {
- // Allow missing exception specifications in redeclarations as an extension.
- DiagID = diag::ext_ms_missing_exception_specification;
+ if (getLangOpts().MSVCCompat && isDynamicExceptionSpec(ESI.Type)) {
+ DiagID = diag::ext_missing_exception_specification;
ReturnValueOnError = false;
} else if (New->isReplaceableGlobalAllocationFunction() &&
ESI.Type != EST_DependentNoexcept) {
@@ -402,6 +401,10 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
DiagID = diag::ext_missing_exception_specification;
ReturnValueOnError = false;
} else if (ESI.Type == EST_NoThrow) {
+ // Don't emit any warning for missing 'nothrow' in MSVC.
+ if (getLangOpts().MSVCCompat) {
+ return false;
+ }
// Allow missing attribute 'nothrow' in redeclarations, since this is a very
// common omission.
DiagID = diag::ext_missing_exception_specification;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index d32b3f217aa0..7de43705c2b1 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -55,7 +55,6 @@
using namespace clang;
using namespace sema;
-using llvm::RoundingMode;
/// Determine whether the use of this declaration is valid, without
/// emitting diagnostics.
@@ -4500,6 +4499,10 @@ Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo,
}
// C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
+ if (isUnevaluatedContext() && ExprKind == UETT_SizeOf &&
+ TInfo->getType()->isVariablyModifiedType())
+ TInfo = TransformToPotentiallyEvaluated(TInfo);
+
return new (Context) UnaryExprOrTypeTraitExpr(
ExprKind, TInfo, Context.getSizeType(), OpLoc, R.getEnd());
}
@@ -4646,6 +4649,38 @@ static bool isMSPropertySubscriptExpr(Sema &S, Expr *Base) {
return isa<MSPropertySubscriptExpr>(BaseNoParens);
}
+// Returns the type used for LHS[RHS], given one of LHS, RHS is type-dependent.
+// Typically this is DependentTy, but can sometimes be more precise.
+//
+// There are cases when we could determine a non-dependent type:
+// - LHS and RHS may have non-dependent types despite being type-dependent
+// (e.g. unbounded array static members of the current instantiation)
+// - one may be a dependent-sized array with known element type
+// - one may be a dependent-typed valid index (enum in current instantiation)
+//
+// We *always* return a dependent type, in such cases it is DependentTy.
+// This avoids creating type-dependent expressions with non-dependent types.
+// FIXME: is this important to avoid? See https://reviews.llvm.org/D107275
+static QualType getDependentArraySubscriptType(Expr *LHS, Expr *RHS,
+ const ASTContext &Ctx) {
+ assert(LHS->isTypeDependent() || RHS->isTypeDependent());
+ QualType LTy = LHS->getType(), RTy = RHS->getType();
+ QualType Result = Ctx.DependentTy;
+ if (RTy->isIntegralOrUnscopedEnumerationType()) {
+ if (const PointerType *PT = LTy->getAs<PointerType>())
+ Result = PT->getPointeeType();
+ else if (const ArrayType *AT = LTy->getAsArrayTypeUnsafe())
+ Result = AT->getElementType();
+ } else if (LTy->isIntegralOrUnscopedEnumerationType()) {
+ if (const PointerType *PT = RTy->getAs<PointerType>())
+ Result = PT->getPointeeType();
+ else if (const ArrayType *AT = RTy->getAsArrayTypeUnsafe())
+ Result = AT->getElementType();
+ }
+ // Ensure we return a dependent type.
+ return Result->isDependentType() ? Result : Ctx.DependentTy;
+}
+
ExprResult
Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
Expr *idx, SourceLocation rbLoc) {
@@ -4738,8 +4773,9 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
// Build an unanalyzed expression if either operand is type-dependent.
if (getLangOpts().CPlusPlus &&
(base->isTypeDependent() || idx->isTypeDependent())) {
- return new (Context) ArraySubscriptExpr(base, idx, Context.DependentTy,
- VK_LValue, OK_Ordinary, rbLoc);
+ return new (Context) ArraySubscriptExpr(
+ base, idx, getDependentArraySubscriptType(base, idx, getASTContext()),
+ VK_LValue, OK_Ordinary, rbLoc);
}
// MSDN, property (C++)
@@ -5493,7 +5529,8 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
if (LHSTy->isDependentType() || RHSTy->isDependentType()) {
BaseExpr = LHSExp;
IndexExpr = RHSExp;
- ResultType = Context.DependentTy;
+ ResultType =
+ getDependentArraySubscriptType(LHSExp, RHSExp, getASTContext());
} else if (const PointerType *PTy = LHSTy->getAs<PointerType>()) {
BaseExpr = LHSExp;
IndexExpr = RHSExp;
@@ -7694,8 +7731,7 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
CastExpr = Result.get();
}
- if (getLangOpts().CPlusPlus && !castType->isVoidType() &&
- !getSourceManager().isInSystemMacro(LParenLoc))
+ if (getLangOpts().CPlusPlus && !castType->isVoidType())
Diag(LParenLoc, diag::warn_old_style_cast) << CastExpr->getSourceRange();
CheckTollFreeBridgeCast(castType, CastExpr);
@@ -15913,7 +15949,7 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc,
// promoted type and the underlying type are the same except for
// signedness. Ask the AST for the correctly corresponding type and see
// if that's compatible.
- if (!PromoteType.isNull() &&
+ if (!PromoteType.isNull() && !UnderlyingType->isBooleanType() &&
PromoteType->isUnsignedIntegerType() !=
UnderlyingType->isUnsignedIntegerType()) {
UnderlyingType =
@@ -16569,6 +16605,16 @@ ExprResult Sema::TransformToPotentiallyEvaluated(Expr *E) {
return TransformToPE(*this).TransformExpr(E);
}
+TypeSourceInfo *Sema::TransformToPotentiallyEvaluated(TypeSourceInfo *TInfo) {
+ assert(isUnevaluatedContext() &&
+ "Should only transform unevaluated expressions");
+ ExprEvalContexts.back().Context =
+ ExprEvalContexts[ExprEvalContexts.size() - 2].Context;
+ if (isUnevaluatedContext())
+ return TInfo;
+ return TransformToPE(*this).TransformType(TInfo);
+}
+
void
Sema::PushExpressionEvaluationContext(
ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl,
@@ -19176,10 +19222,12 @@ ExprResult Sema::CheckBooleanCondition(SourceLocation Loc, Expr *E,
}
Sema::ConditionResult Sema::ActOnCondition(Scope *S, SourceLocation Loc,
- Expr *SubExpr, ConditionKind CK) {
- // Empty conditions are valid in for-statements.
+ Expr *SubExpr, ConditionKind CK,
+ bool MissingOK) {
+ // MissingOK indicates whether having no condition expression is valid
+ // (for loop) or invalid (e.g. while loop).
if (!SubExpr)
- return ConditionResult();
+ return MissingOK ? ConditionResult() : ConditionError();
ExprResult Cond;
switch (CK) {
@@ -19197,7 +19245,7 @@ Sema::ConditionResult Sema::ActOnCondition(Scope *S, SourceLocation Loc,
}
if (Cond.isInvalid()) {
Cond = CreateRecoveryExpr(SubExpr->getBeginLoc(), SubExpr->getEndLoc(),
- {SubExpr});
+ {SubExpr}, PreferredConditionType(CK));
if (!Cond.get())
return ConditionError();
}
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 54f0242d2ca1..b34b744d7312 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -6614,7 +6614,7 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
const Type *ClassOrBound;
Step(Kind K, const Type *ClassOrBound = nullptr)
- : K(K), Quals(), ClassOrBound(ClassOrBound) {}
+ : K(K), ClassOrBound(ClassOrBound) {}
QualType rebuild(ASTContext &Ctx, QualType T) const {
T = Ctx.getQualifiedType(T, Quals);
switch (K) {
@@ -7410,8 +7410,10 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
// the member function body.
if (!BaseType->isDependentType() &&
!isThisOutsideMemberFunctionBody(BaseType) &&
- RequireCompleteType(OpLoc, BaseType, diag::err_incomplete_member_access))
- return ExprError();
+ RequireCompleteType(OpLoc, BaseType,
+ diag::err_incomplete_member_access)) {
+ return CreateRecoveryExpr(Base->getBeginLoc(), Base->getEndLoc(), {Base});
+ }
// C++ [basic.lookup.classref]p2:
// If the id-expression in a class member access (5.2.5) is an
@@ -7767,7 +7769,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
TypeLocBuilder TLB;
DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T);
- DecltypeTL.setNameLoc(DS.getTypeSpecTypeLoc());
+ DecltypeTL.setDecltypeLoc(DS.getTypeSpecTypeLoc());
+ DecltypeTL.setRParenLoc(DS.getTypeofParensRange().getEnd());
TypeSourceInfo *DestructedTypeInfo = TLB.getTypeSourceInfo(Context, T);
PseudoDestructorTypeStorage Destructed(DestructedTypeInfo);
@@ -8697,7 +8700,7 @@ Sema::ActOnTypeRequirement(SourceLocation TypenameKWLoc, CXXScopeSpec &SS,
if (TypeName) {
QualType T = CheckTypenameType(ETK_Typename, TypenameKWLoc,
SS.getWithLocInContext(Context), *TypeName,
- NameLoc, &TSI, /*DeducedTypeContext=*/false);
+ NameLoc, &TSI, /*DeducedTSTContext=*/false);
if (T.isNull())
return nullptr;
} else {
@@ -8748,7 +8751,7 @@ Sema::ActOnCompoundRequirement(
/*HasTypeConstraint=*/true);
if (BuildTypeConstraint(SS, TypeConstraint, TParam,
- /*EllpsisLoc=*/SourceLocation(),
+ /*EllipsisLoc=*/SourceLocation(),
/*AllowUnexpandedPack=*/true))
// Just produce a requirement with no type requirements.
return BuildExprRequirement(E, /*IsSimple=*/false, NoexceptLoc, {});
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 83006f9d804a..dfd93aa4638d 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -504,9 +504,12 @@ Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType,
}
}
- assert(BaseType->isDependentType() ||
- NameInfo.getName().isDependentName() ||
- isDependentScopeSpecifier(SS));
+ assert(BaseType->isDependentType() || NameInfo.getName().isDependentName() ||
+ isDependentScopeSpecifier(SS) ||
+ (TemplateArgs && llvm::any_of(TemplateArgs->arguments(),
+ [](const TemplateArgumentLoc &Arg) {
+ return Arg.getArgument().isDependent();
+ })));
// Get the type being accessed in BaseType. If this is an arrow, the BaseExpr
// must have pointer type, and the accessed type is the pointee.
@@ -1642,6 +1645,9 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
<< BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
<< FixItHint::CreateReplacement(OpLoc, "->");
+ if (S.isSFINAEContext())
+ return ExprError();
+
// Recurse as an -> access.
IsArrow = true;
return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS,
diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp
index bdc8e1e0b336..4702c405fb4e 100644
--- a/clang/lib/Sema/SemaExprObjC.cpp
+++ b/clang/lib/Sema/SemaExprObjC.cpp
@@ -1280,11 +1280,11 @@ static ObjCMethodDecl *findMethodInCurrentClass(Sema &S, Selector Sel) {
// whether Sel is potentially direct in this context.
if (ObjCMethodDecl *MD = IFace->lookupMethod(Sel, /*isInstance=*/true))
return MD;
- if (ObjCMethodDecl *MD = IFace->lookupPrivateMethod(Sel, /*isInstance=*/true))
+ if (ObjCMethodDecl *MD = IFace->lookupPrivateMethod(Sel, /*Instance=*/true))
return MD;
if (ObjCMethodDecl *MD = IFace->lookupMethod(Sel, /*isInstance=*/false))
return MD;
- if (ObjCMethodDecl *MD = IFace->lookupPrivateMethod(Sel, /*isInstance=*/false))
+ if (ObjCMethodDecl *MD = IFace->lookupPrivateMethod(Sel, /*Instance=*/false))
return MD;
return nullptr;
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 635e93ba8460..af6ee24240ce 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -620,7 +620,7 @@ void LookupResult::resolveKind() {
getSema().diagnoseEquivalentInternalLinkageDeclarations(
getNameLoc(), HasNonFunction, EquivalentNonFunctions);
- Decls.set_size(N);
+ Decls.truncate(N);
if (HasNonFunction && (HasFunction || HasUnresolved))
Ambiguous = true;
@@ -4307,18 +4307,35 @@ void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) {
if (!CList.empty() && !CList.back().isResolved())
CList.pop_back();
if (NamedDecl *NewND = Correction.getCorrectionDecl()) {
- std::string CorrectionStr = Correction.getAsString(SemaRef.getLangOpts());
- for (TypoResultList::iterator RI = CList.begin(), RIEnd = CList.end();
- RI != RIEnd; ++RI) {
- // If the Correction refers to a decl already in the result list,
- // replace the existing result if the string representation of Correction
- // comes before the current result alphabetically, then stop as there is
- // nothing more to be done to add Correction to the candidate set.
- if (RI->getCorrectionDecl() == NewND) {
- if (CorrectionStr < RI->getAsString(SemaRef.getLangOpts()))
- *RI = Correction;
- return;
- }
+ auto RI = llvm::find_if(CList, [NewND](const TypoCorrection &TypoCorr) {
+ return TypoCorr.getCorrectionDecl() == NewND;
+ });
+ if (RI != CList.end()) {
+ // The Correction refers to a decl already in the list. No insertion is
+ // necessary and all further cases will return.
+
+ auto IsDeprecated = [](Decl *D) {
+ while (D) {
+ if (D->isDeprecated())
+ return true;
+ D = llvm::dyn_cast_or_null<NamespaceDecl>(D->getDeclContext());
+ }
+ return false;
+ };
+
+ // Prefer non deprecated Corrections over deprecated and only then
+ // sort using an alphabetical order.
+ std::pair<bool, std::string> NewKey = {
+ IsDeprecated(Correction.getFoundDecl()),
+ Correction.getAsString(SemaRef.getLangOpts())};
+
+ std::pair<bool, std::string> PrevKey = {
+ IsDeprecated(RI->getFoundDecl()),
+ RI->getAsString(SemaRef.getLangOpts())};
+
+ if (NewKey < PrevKey)
+ *RI = Correction;
+ return;
}
}
if (CList.empty() || Correction.isResolved())
diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp
index a4b9f3c242c1..747734f2d0ff 100644
--- a/clang/lib/Sema/SemaModule.cpp
+++ b/clang/lib/Sema/SemaModule.cpp
@@ -395,7 +395,7 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
// [module.interface]p1:
// An export-declaration shall inhabit a namespace scope and appear in the
// purview of a module interface unit.
- Diag(ExportLoc, diag::err_export_not_in_module_interface);
+ Diag(ExportLoc, diag::err_export_not_in_module_interface) << 0;
}
return Import;
@@ -527,21 +527,30 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc,
// Set this temporarily so we know the export-declaration was braced.
D->setRBraceLoc(LBraceLoc);
+ CurContext->addDecl(D);
+ PushDeclContext(S, D);
+
// C++2a [module.interface]p1:
// An export-declaration shall appear only [...] in the purview of a module
// interface unit. An export-declaration shall not appear directly or
// indirectly within [...] a private-module-fragment.
if (ModuleScopes.empty() || !ModuleScopes.back().Module->isModulePurview()) {
Diag(ExportLoc, diag::err_export_not_in_module_interface) << 0;
+ D->setInvalidDecl();
+ return D;
} else if (!ModuleScopes.back().ModuleInterface) {
Diag(ExportLoc, diag::err_export_not_in_module_interface) << 1;
Diag(ModuleScopes.back().BeginLoc,
diag::note_not_module_interface_add_export)
<< FixItHint::CreateInsertion(ModuleScopes.back().BeginLoc, "export ");
+ D->setInvalidDecl();
+ return D;
} else if (ModuleScopes.back().Module->Kind ==
Module::PrivateModuleFragment) {
Diag(ExportLoc, diag::err_export_in_private_module_fragment);
Diag(ModuleScopes.back().BeginLoc, diag::note_private_module_fragment);
+ D->setInvalidDecl();
+ return D;
}
for (const DeclContext *DC = CurContext; DC; DC = DC->getLexicalParent()) {
@@ -553,7 +562,7 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc,
Diag(ND->getLocation(), diag::note_anonymous_namespace);
// Don't diagnose internal-linkage declarations in this region.
D->setInvalidDecl();
- break;
+ return D;
}
// A declaration is exported if it is [...] a namespace-definition
@@ -572,10 +581,10 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc,
Diag(ExportLoc, diag::err_export_within_export);
if (ED->hasBraces())
Diag(ED->getLocation(), diag::note_export);
+ D->setInvalidDecl();
+ return D;
}
- CurContext->addDecl(D);
- PushDeclContext(S, D);
D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::VisibleWhenImported);
return D;
}
diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp
index 74c73ace3c5f..118afb81dd72 100644
--- a/clang/lib/Sema/SemaObjCProperty.cpp
+++ b/clang/lib/Sema/SemaObjCProperty.cpp
@@ -112,8 +112,8 @@ CheckPropertyAgainstProtocol(Sema &S, ObjCPropertyDecl *Prop,
return;
// Look for a property with the same name.
- if (ObjCPropertyDecl *ProtoProp =
- Proto->lookup(Prop->getDeclName()).find_first<ObjCPropertyDecl>()) {
+ if (ObjCPropertyDecl *ProtoProp = Proto->getProperty(
+ Prop->getIdentifier(), Prop->isInstanceProperty())) {
S.DiagnosePropertyMismatch(Prop, ProtoProp, Proto->getIdentifier(), true);
return;
}
@@ -231,8 +231,8 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
bool FoundInSuper = false;
ObjCInterfaceDecl *CurrentInterfaceDecl = IFace;
while (ObjCInterfaceDecl *Super = CurrentInterfaceDecl->getSuperClass()) {
- if (ObjCPropertyDecl *SuperProp =
- Super->lookup(Res->getDeclName()).find_first<ObjCPropertyDecl>()) {
+ if (ObjCPropertyDecl *SuperProp = Super->getProperty(
+ Res->getIdentifier(), Res->isInstanceProperty())) {
DiagnosePropertyMismatch(Res, SuperProp, Super->getIdentifier(), false);
FoundInSuper = true;
break;
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index ba0481874577..ae91a6470471 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -36,6 +36,7 @@
#include "llvm/ADT/PointerEmbeddedInt.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Frontend/OpenMP/OMPAssume.h"
#include "llvm/Frontend/OpenMP/OMPConstants.h"
#include <set>
@@ -7051,7 +7052,8 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
QualType AdjustedFnType = FD->getType();
if (NumAppendArgs) {
- if (isa<FunctionNoProtoType>(FD->getType())) {
+ const auto *PTy = AdjustedFnType->getAsAdjusted<FunctionProtoType>();
+ if (!PTy) {
Diag(FD->getLocation(), diag::err_omp_declare_variant_prototype_required)
<< SR;
return None;
@@ -7069,8 +7071,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
Diag(SR.getBegin(), diag::err_omp_interop_type_not_found) << SR;
return None;
}
- QualType InteropType = QualType(TD->getTypeForDecl(), 0);
- auto *PTy = cast<FunctionProtoType>(FD->getType());
+ QualType InteropType = Context.getTypeDeclType(TD);
if (PTy->isVariadic()) {
Diag(FD->getLocation(), diag::err_omp_append_args_with_varargs) << SR;
return None;
@@ -13148,7 +13149,7 @@ StmtResult Sema::ActOnOpenMPUnrollDirective(ArrayRef<OMPClause *> Clauses,
if (FullClause) {
if (!VerifyPositiveIntegerConstantInClause(
LoopHelper.NumIterations, OMPC_full, /*StrictlyPositive=*/false,
- /*SuppressExprDigs=*/true)
+ /*SuppressExprDiags=*/true)
.isUsable()) {
Diag(AStmt->getBeginLoc(), diag::err_omp_unroll_full_variable_trip_count);
Diag(FullClause->getBeginLoc(), diag::note_omp_directive_here)
@@ -20761,8 +20762,7 @@ Sema::ActOnOpenMPEndDeclareTargetDirective() {
void Sema::ActOnFinishedOpenMPDeclareTargetContext(
DeclareTargetContextInfo &DTCI) {
for (auto &It : DTCI.ExplicitlyMapped)
- ActOnOpenMPDeclareTargetName(It.first, It.second.Loc, It.second.MT,
- DTCI.DT);
+ ActOnOpenMPDeclareTargetName(It.first, It.second.Loc, It.second.MT, DTCI);
}
NamedDecl *Sema::lookupOpenMPDeclareTargetName(Scope *CurScope,
@@ -20799,9 +20799,9 @@ NamedDecl *Sema::lookupOpenMPDeclareTargetName(Scope *CurScope,
return ND;
}
-void Sema::ActOnOpenMPDeclareTargetName(
- NamedDecl *ND, SourceLocation Loc, OMPDeclareTargetDeclAttr::MapTypeTy MT,
- OMPDeclareTargetDeclAttr::DevTypeTy DT) {
+void Sema::ActOnOpenMPDeclareTargetName(NamedDecl *ND, SourceLocation Loc,
+ OMPDeclareTargetDeclAttr::MapTypeTy MT,
+ DeclareTargetContextInfo &DTCI) {
assert((isa<VarDecl>(ND) || isa<FunctionDecl>(ND) ||
isa<FunctionTemplateDecl>(ND)) &&
"Expected variable, function or function template.");
@@ -20818,10 +20818,10 @@ void Sema::ActOnOpenMPDeclareTargetName(
auto *VD = cast<ValueDecl>(ND);
llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
OMPDeclareTargetDeclAttr::getActiveAttr(VD);
- if (ActiveAttr.hasValue() && ActiveAttr.getValue()->getDevType() != DT &&
+ if (ActiveAttr.hasValue() && ActiveAttr.getValue()->getDevType() != DTCI.DT &&
ActiveAttr.getValue()->getLevel() == Level) {
Diag(Loc, diag::err_omp_device_type_mismatch)
- << OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(DT)
+ << OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(DTCI.DT)
<< OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(
ActiveAttr.getValue()->getDevType());
return;
@@ -20835,8 +20835,16 @@ void Sema::ActOnOpenMPDeclareTargetName(
if (ActiveAttr.hasValue() && ActiveAttr.getValue()->getLevel() == Level)
return;
- auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(Context, MT, DT, Level,
- SourceRange(Loc, Loc));
+ Expr *IndirectE = nullptr;
+ bool IsIndirect = false;
+ if (DTCI.Indirect.hasValue()) {
+ IndirectE = DTCI.Indirect.getValue();
+ if (!IndirectE)
+ IsIndirect = true;
+ }
+ auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(
+ Context, MT, DTCI.DT, IndirectE, IsIndirect, Level,
+ SourceRange(Loc, Loc));
ND->addAttr(A);
if (ASTMutationListener *ML = Context.getASTMutationListener())
ML->DeclarationMarkedOpenMPDeclareTarget(ND, A);
@@ -20927,9 +20935,16 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
if (ActiveAttr.hasValue() && ActiveAttr.getValue()->getLevel() >= Level)
return;
DeclareTargetContextInfo &DTCI = DeclareTargetNesting.back();
+ Expr *IndirectE = nullptr;
+ bool IsIndirect = false;
+ if (DTCI.Indirect.hasValue()) {
+ IndirectE = DTCI.Indirect.getValue();
+ if (!IndirectE)
+ IsIndirect = true;
+ }
auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(
- Context, OMPDeclareTargetDeclAttr::MT_To, DTCI.DT, Level,
- SourceRange(DTCI.Loc, DTCI.Loc));
+ Context, OMPDeclareTargetDeclAttr::MT_To, DTCI.DT, IndirectE,
+ IsIndirect, Level, SourceRange(DTCI.Loc, DTCI.Loc));
D->addAttr(A);
if (ASTMutationListener *ML = Context.getASTMutationListener())
ML->DeclarationMarkedOpenMPDeclareTarget(D, A);
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 42b1340f9a65..483247aaa7c5 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -2405,9 +2405,8 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
if (FromType->isObjCObjectPointerType() && ToPointeeType->isVoidType() &&
!getLangOpts().ObjCAutoRefCount) {
ConvertedType = BuildSimilarlyQualifiedPointerType(
- FromType->getAs<ObjCObjectPointerType>(),
- ToPointeeType,
- ToType, Context);
+ FromType->castAs<ObjCObjectPointerType>(), ToPointeeType, ToType,
+ Context);
return true;
}
const PointerType *FromTypePtr = FromType->getAs<PointerType>();
@@ -3718,8 +3717,7 @@ compareConversionFunctions(Sema &S, FunctionDecl *Function1,
CallingConv Conv2CC = Conv2FuncRet->getCallConv();
CXXMethodDecl *CallOp = Conv2->getParent()->getLambdaCallOperator();
- const FunctionProtoType *CallOpProto =
- CallOp->getType()->getAs<FunctionProtoType>();
+ const auto *CallOpProto = CallOp->getType()->castAs<FunctionProtoType>();
CallingConv CallOpCC =
CallOp->getType()->castAs<FunctionType>()->getCallConv();
@@ -9416,12 +9414,12 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
AddOverloadCandidate(
FD, FoundDecl, Args, CandidateSet, /*SuppressUserConversions=*/false,
PartialOverloading, /*AllowExplicit=*/true,
- /*AllowExplicitConversions=*/false, ADLCallKind::UsesADL);
+ /*AllowExplicitConversion=*/false, ADLCallKind::UsesADL);
if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD)) {
AddOverloadCandidate(
FD, FoundDecl, {Args[1], Args[0]}, CandidateSet,
/*SuppressUserConversions=*/false, PartialOverloading,
- /*AllowExplicit=*/true, /*AllowExplicitConversions=*/false,
+ /*AllowExplicit=*/true, /*AllowExplicitConversion=*/false,
ADLCallKind::UsesADL, None, OverloadCandidateParamOrder::Reversed);
}
} else {
@@ -14322,8 +14320,7 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
FoundDecl = MemExpr->getFoundDecl();
Qualifier = MemExpr->getQualifier();
UnbridgedCasts.restore();
- } else {
- UnresolvedMemberExpr *UnresExpr = cast<UnresolvedMemberExpr>(NakedMemExpr);
+ } else if (auto *UnresExpr = dyn_cast<UnresolvedMemberExpr>(NakedMemExpr)) {
Qualifier = UnresExpr->getQualifier();
QualType ObjectType = UnresExpr->getBaseType();
@@ -14436,7 +14433,9 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
}
MemExpr = cast<MemberExpr>(MemExprE->IgnoreParens());
- }
+ } else
+ // Unimaged NakedMemExpr type.
+ return ExprError();
QualType ResultType = Method->getReturnType();
ExprValueKind VK = Expr::getValueKindForType(ResultType);
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index 815463307ecc..f8c713c8545d 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -48,3 +48,101 @@ bool Sema::checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) {
return DiagKind != SemaDiagnosticBuilder::K_Immediate &&
DiagKind != SemaDiagnosticBuilder::K_ImmediateWithCallStack;
}
+
+static bool isZeroSizedArray(Sema &SemaRef, QualType Ty) {
+ if (const auto *CAT = SemaRef.getASTContext().getAsConstantArrayType(Ty))
+ return CAT->getSize() == 0;
+ return false;
+}
+
+void Sema::deepTypeCheckForSYCLDevice(SourceLocation UsedAt,
+ llvm::DenseSet<QualType> Visited,
+ ValueDecl *DeclToCheck) {
+ assert(getLangOpts().SYCLIsDevice &&
+ "Should only be called during SYCL compilation");
+ // Emit notes only for the first discovered declaration of unsupported type
+ // to avoid mess of notes. This flag is to track that error already happened.
+ bool NeedToEmitNotes = true;
+
+ auto Check = [&](QualType TypeToCheck, const ValueDecl *D) {
+ bool ErrorFound = false;
+ if (isZeroSizedArray(*this, TypeToCheck)) {
+ SYCLDiagIfDeviceCode(UsedAt, diag::err_typecheck_zero_array_size) << 1;
+ ErrorFound = true;
+ }
+ // Checks for other types can also be done here.
+ if (ErrorFound) {
+ if (NeedToEmitNotes) {
+ if (auto *FD = dyn_cast<FieldDecl>(D))
+ SYCLDiagIfDeviceCode(FD->getLocation(),
+ diag::note_illegal_field_declared_here)
+ << FD->getType()->isPointerType() << FD->getType();
+ else
+ SYCLDiagIfDeviceCode(D->getLocation(), diag::note_declared_at);
+ }
+ }
+
+ return ErrorFound;
+ };
+
+ // In case we have a Record used do the DFS for a bad field.
+ SmallVector<const ValueDecl *, 4> StackForRecursion;
+ StackForRecursion.push_back(DeclToCheck);
+
+ // While doing DFS save how we get there to emit a nice set of notes.
+ SmallVector<const FieldDecl *, 4> History;
+ History.push_back(nullptr);
+
+ do {
+ const ValueDecl *Next = StackForRecursion.pop_back_val();
+ if (!Next) {
+ assert(!History.empty());
+ // Found a marker, we have gone up a level.
+ History.pop_back();
+ continue;
+ }
+ QualType NextTy = Next->getType();
+
+ if (!Visited.insert(NextTy).second)
+ continue;
+
+ auto EmitHistory = [&]() {
+ // The first element is always nullptr.
+ for (uint64_t Index = 1; Index < History.size(); ++Index) {
+ SYCLDiagIfDeviceCode(History[Index]->getLocation(),
+ diag::note_within_field_of_type)
+ << History[Index]->getType();
+ }
+ };
+
+ if (Check(NextTy, Next)) {
+ if (NeedToEmitNotes)
+ EmitHistory();
+ NeedToEmitNotes = false;
+ }
+
+ // In case pointer/array/reference type is met get pointee type, then
+ // proceed with that type.
+ while (NextTy->isAnyPointerType() || NextTy->isArrayType() ||
+ NextTy->isReferenceType()) {
+ if (NextTy->isArrayType())
+ NextTy = QualType{NextTy->getArrayElementTypeNoTypeQual(), 0};
+ else
+ NextTy = NextTy->getPointeeType();
+ if (Check(NextTy, Next)) {
+ if (NeedToEmitNotes)
+ EmitHistory();
+ NeedToEmitNotes = false;
+ }
+ }
+
+ if (const auto *RecDecl = NextTy->getAsRecordDecl()) {
+ if (auto *NextFD = dyn_cast<FieldDecl>(Next))
+ History.push_back(NextFD);
+ // When nullptr is discovered, this means we've gone back up a level, so
+ // the history should be cleaned.
+ StackForRecursion.push_back(nullptr);
+ llvm::copy(RecDecl->fields(), std::back_inserter(StackForRecursion));
+ }
+ } while (!StackForRecursion.empty());
+}
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 1d90759f2406..746eb82a5bdc 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -410,9 +410,13 @@ StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
ArrayRef<Stmt *> Elts, bool isStmtExpr) {
const unsigned NumElts = Elts.size();
- // If we're in C89 mode, check that we don't have any decls after stmts. If
- // so, emit an extension diagnostic.
- if (!getLangOpts().C99 && !getLangOpts().CPlusPlus) {
+ // If we're in C mode, check that we don't have any decls after stmts. If
+ // so, emit an extension diagnostic in C89 and potentially a warning in later
+ // versions.
+ const unsigned MixedDeclsCodeID = getLangOpts().C99
+ ? diag::warn_mixed_decls_code
+ : diag::ext_mixed_decls_code;
+ if (!getLangOpts().CPlusPlus && !Diags.isIgnored(MixedDeclsCodeID, L)) {
// Note that __extension__ can be around a decl.
unsigned i = 0;
// Skip over all declarations.
@@ -425,7 +429,7 @@ StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
if (i != NumElts) {
Decl *D = *cast<DeclStmt>(Elts[i])->decl_begin();
- Diag(D->getLocation(), diag::ext_mixed_decls_code);
+ Diag(D->getLocation(), MixedDeclsCodeID);
}
}
@@ -869,12 +873,7 @@ StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc,
Stmt *thenStmt, SourceLocation ElseLoc,
Stmt *elseStmt) {
if (Cond.isInvalid())
- Cond = ConditionResult(
- *this, nullptr,
- MakeFullExpr(new (Context) OpaqueValueExpr(SourceLocation(),
- Context.BoolTy, VK_PRValue),
- IfLoc),
- false);
+ return StmtError();
bool ConstevalOrNegatedConsteval =
StatementKind == IfStatementKind::ConstevalNonNegated ||
@@ -2468,6 +2467,7 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc,
Stmt *First, SourceLocation ColonLoc,
Expr *Range, SourceLocation RParenLoc,
BuildForRangeKind Kind) {
+ // FIXME: recover in order to allow the body to be parsed.
if (!First)
return StmtError();
@@ -3878,7 +3878,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
RetValExp, nullptr, /*RecoverUncorrectedTypos=*/true);
if (RetVal.isInvalid())
return StmtError();
- StmtResult R = BuildReturnStmt(ReturnLoc, RetVal.get());
+ StmtResult R =
+ BuildReturnStmt(ReturnLoc, RetVal.get(), /*AllowRecovery=*/true);
if (R.isInvalid() || ExprEvalContexts.back().isDiscardedStatementContext())
return R;
@@ -3908,7 +3909,8 @@ static bool CheckSimplerImplicitMovesMSVCWorkaround(const Sema &S,
return false;
}
-StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
+StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
+ bool AllowRecovery) {
// Check for unexpanded parameter packs.
if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp))
return StmtError();
@@ -3985,11 +3987,25 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// If we've already decided this function is invalid, e.g. because
// we saw a `return` whose expression had an error, don't keep
// trying to deduce its return type.
- if (FD->isInvalidDecl())
- return StmtError();
- if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) {
+ // (Some return values may be needlessly wrapped in RecoveryExpr).
+ if (FD->isInvalidDecl() ||
+ DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) {
FD->setInvalidDecl();
- return StmtError();
+ if (!AllowRecovery)
+ return StmtError();
+ // The deduction failure is diagnosed and marked, try to recover.
+ if (RetValExp) {
+ // Wrap return value with a recovery expression of the previous type.
+ // If no deduction yet, use DependentTy.
+ auto Recovery = CreateRecoveryExpr(
+ RetValExp->getBeginLoc(), RetValExp->getEndLoc(), RetValExp,
+ AT->isDeduced() ? FnRetType : QualType());
+ if (Recovery.isInvalid())
+ return StmtError();
+ RetValExp = Recovery.get();
+ } else {
+ // Nothing to do: a ReturnStmt with no value is fine recovery.
+ }
} else {
FnRetType = FD->getReturnType();
}
@@ -4002,7 +4018,7 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
ReturnStmt *Result = nullptr;
if (FnRetType->isVoidType()) {
if (RetValExp) {
- if (isa<InitListExpr>(RetValExp)) {
+ if (auto *ILE = dyn_cast<InitListExpr>(RetValExp)) {
// We simply never allow init lists as the return value of void
// functions. This is compatible because this was never allowed before,
// so there's no legacy code to deal with.
@@ -4018,8 +4034,12 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
Diag(ReturnLoc, diag::err_return_init_list)
<< CurDecl << FunctionKind << RetValExp->getSourceRange();
- // Drop the expression.
- RetValExp = nullptr;
+ // Preserve the initializers in the AST.
+ RetValExp = AllowRecovery
+ ? CreateRecoveryExpr(ILE->getLBraceLoc(),
+ ILE->getRBraceLoc(), ILE->inits())
+ .get()
+ : nullptr;
} else if (!RetValExp->isTypeDependent()) {
// C99 6.8.6.4p1 (ext_ since GCC warns)
unsigned D = diag::ext_return_has_expr;
@@ -4116,6 +4136,9 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
InitializedEntity::InitializeResult(ReturnLoc, RetType);
ExprResult Res = PerformMoveOrCopyInitialization(
Entity, NRInfo, RetValExp, SupressSimplerImplicitMoves);
+ if (Res.isInvalid() && AllowRecovery)
+ Res = CreateRecoveryExpr(RetValExp->getBeginLoc(),
+ RetValExp->getEndLoc(), RetValExp, RetType);
if (Res.isInvalid()) {
// FIXME: Clean up temporaries here anyway?
return StmtError();
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 2482f6d404ea..64a0b45feb98 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2063,7 +2063,7 @@ DeclResult Sema::CheckClassTemplate(
}
if (PrevClassTemplate)
- CheckRedeclarationModuleOwnership(NewTemplate, PrevClassTemplate);
+ CheckRedeclarationInModule(NewTemplate, PrevClassTemplate);
if (Invalid) {
NewTemplate->setInvalidDecl();
@@ -3672,7 +3672,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
SmallVector<TemplateArgument, 4> Converted;
if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs,
false, Converted,
- /*UpdateArgsWithConversion=*/true))
+ /*UpdateArgsWithConversions=*/true))
return QualType();
QualType CanonType;
@@ -4318,7 +4318,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
SmallVector<TemplateArgument, 4> Converted;
if (CheckTemplateArgumentList(VarTemplate, TemplateNameLoc, TemplateArgs,
false, Converted,
- /*UpdateArgsWithConversion=*/true))
+ /*UpdateArgsWithConversions=*/true))
return true;
// Find the variable template (partial) specialization declaration that
@@ -4489,7 +4489,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
if (CheckTemplateArgumentList(
Template, TemplateNameLoc,
const_cast<TemplateArgumentListInfo &>(TemplateArgs), false,
- Converted, /*UpdateArgsWithConversion=*/true))
+ Converted, /*UpdateArgsWithConversions=*/true))
return true;
// Produce a placeholder value if the specialization is dependent.
@@ -4677,7 +4677,7 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
if (CheckTemplateArgumentList(NamedConcept, ConceptNameInfo.getLoc(),
const_cast<TemplateArgumentListInfo&>(*TemplateArgs),
/*PartialTemplateArgs=*/false, Converted,
- /*UpdateArgsWithConversion=*/false))
+ /*UpdateArgsWithConversions=*/false))
return ExprError();
ConstraintSatisfaction Satisfaction;
@@ -8343,7 +8343,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
SmallVector<TemplateArgument, 4> Converted;
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc,
TemplateArgs, false, Converted,
- /*UpdateArgsWithConversion=*/true))
+ /*UpdateArgsWithConversions=*/true))
return true;
// Find the class template (partial) specialization declaration that
@@ -9595,7 +9595,7 @@ DeclResult Sema::ActOnExplicitInstantiation(
SmallVector<TemplateArgument, 4> Converted;
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc,
TemplateArgs, false, Converted,
- /*UpdateArgsWithConversion=*/true))
+ /*UpdateArgsWithConversions=*/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 e9636d2b942e..22dd395d9943 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -4452,7 +4452,7 @@ namespace {
public:
SubstituteDeducedTypeTransform(Sema &SemaRef, DependentAuto DA)
- : TreeTransform<SubstituteDeducedTypeTransform>(SemaRef), Replacement(),
+ : TreeTransform<SubstituteDeducedTypeTransform>(SemaRef),
ReplacementIsPack(DA.IsPack), UseTypeSugar(true) {}
SubstituteDeducedTypeTransform(Sema &SemaRef, QualType Replacement,
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 7d4c000e7e90..7c6bb4c8a5f8 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2790,11 +2790,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
CurrentInstantiationScope = I->Scope;
// Allow 'this' within late-parsed attributes.
- NamedDecl *ND = dyn_cast<NamedDecl>(I->NewDecl);
- CXXRecordDecl *ThisContext =
- dyn_cast_or_null<CXXRecordDecl>(ND->getDeclContext());
+ auto *ND = cast<NamedDecl>(I->NewDecl);
+ auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(ND->getDeclContext());
CXXThisScopeRAII ThisScope(*this, ThisContext, Qualifiers(),
- ND && ND->isCXXInstanceMember());
+ ND->isCXXInstanceMember());
Attr *NewAttr =
instantiateTemplateAttribute(I->TmplAttr, Context, *this, TemplateArgs);
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 27ac2cd08f2a..1da0dfec3f23 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3637,7 +3637,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
InstTemplateArgs,
false,
Converted,
- /*UpdateArgsWithConversion=*/true))
+ /*UpdateArgsWithConversions=*/true))
return nullptr;
// Figure out where to insert this class template explicit specialization
@@ -3759,7 +3759,7 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
SmallVector<TemplateArgument, 4> Converted;
if (SemaRef.CheckTemplateArgumentList(InstVarTemplate, D->getLocation(),
VarTemplateArgsInfo, false, Converted,
- /*UpdateArgsWithConversion=*/true))
+ /*UpdateArgsWithConversions=*/true))
return nullptr;
// Check whether we've already seen a declaration of this specialization.
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 7a038301a249..959f4903b030 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeLocVisitor.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/Specifiers.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/DeclSpec.h"
@@ -1495,8 +1496,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
}
case DeclSpec::TST_int128:
if (!S.Context.getTargetInfo().hasInt128Type() &&
- !S.getLangOpts().SYCLIsDevice &&
- !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice))
+ !(S.getLangOpts().SYCLIsDevice || S.getLangOpts().CUDAIsDevice ||
+ (S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice)))
S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported)
<< "__int128";
if (DS.getTypeSpecSign() == TypeSpecifierSign::Unsigned)
@@ -2515,7 +2516,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
Diag(ArraySize->getBeginLoc(),
isSFINAEContext() ? diag::err_typecheck_zero_array_size
: diag::ext_typecheck_zero_array_size)
- << ArraySize->getSourceRange();
+ << 0 << ArraySize->getSourceRange();
}
// Is the array too large?
@@ -5973,6 +5974,11 @@ namespace {
Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
TL.setUnderlyingTInfo(TInfo);
}
+ void VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
+ assert(DS.getTypeSpecType() == DeclSpec::TST_decltype);
+ TL.setDecltypeLoc(DS.getTypeSpecTypeLoc());
+ TL.setRParenLoc(DS.getTypeofParensRange().getEnd());
+ }
void VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
// FIXME: This holds only because we only have one unary transform.
assert(DS.getTypeSpecType() == DeclSpec::TST_underlyingType);
@@ -6036,6 +6042,8 @@ namespace {
DS.getTypeSpecType() == TST_auto_type ||
DS.getTypeSpecType() == TST_unspecified);
TL.setNameLoc(DS.getTypeSpecTypeLoc());
+ if (DS.getTypeSpecType() == TST_decltype_auto)
+ TL.setRParenLoc(DS.getTypeofParensRange().getEnd());
if (!DS.isConstrainedAuto())
return;
TemplateIdAnnotation *TemplateId = DS.getRepAsTemplateId();
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 298a3f7a83d8..e43b3ca968eb 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -4076,7 +4076,8 @@ Sema::ConditionResult TreeTransform<Derived>::TransformCondition(
if (CondExpr.isInvalid())
return Sema::ConditionError();
- return getSema().ActOnCondition(nullptr, Loc, CondExpr.get(), Kind);
+ return getSema().ActOnCondition(nullptr, Loc, CondExpr.get(), Kind,
+ /*MissingOK=*/true);
}
return Sema::ConditionResult();
@@ -6228,15 +6229,15 @@ QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB,
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
E.get() != T->getUnderlyingExpr()) {
- Result = getDerived().RebuildDecltypeType(E.get(), TL.getNameLoc());
+ Result = getDerived().RebuildDecltypeType(E.get(), TL.getDecltypeLoc());
if (Result.isNull())
return QualType();
}
else E.get();
DecltypeTypeLoc NewTL = TLB.push<DecltypeTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
-
+ NewTL.setDecltypeLoc(TL.getDecltypeLoc());
+ NewTL.setRParenLoc(TL.getRParenLoc());
return Result;
}
@@ -6634,6 +6635,7 @@ QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB,
NewTL.setFoundDecl(TL.getFoundDecl());
NewTL.setLAngleLoc(TL.getLAngleLoc());
NewTL.setRAngleLoc(TL.getRAngleLoc());
+ NewTL.setRParenLoc(TL.getRParenLoc());
for (unsigned I = 0; I < NewTL.getNumArgs(); ++I)
NewTL.setArgLocInfo(I, NewTemplateArgs.arguments()[I].getLocInfo());
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index f93e0d2ed1c4..d806fb9e1949 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -142,7 +142,6 @@ using namespace clang;
using namespace clang::serialization;
using namespace clang::serialization::reader;
using llvm::BitstreamCursor;
-using llvm::RoundingMode;
//===----------------------------------------------------------------------===//
// ChainedASTReaderListener implementation
@@ -1888,10 +1887,6 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
HFI.isPragmaOnce |= (Flags >> 4) & 0x01;
HFI.DirInfo = (Flags >> 1) & 0x07;
HFI.IndexHeaderMapHeader = Flags & 0x01;
- // FIXME: Find a better way to handle this. Maybe just store a
- // "has been included" flag?
- HFI.NumIncludes = std::max(endian::readNext<uint16_t, little, unaligned>(d),
- HFI.NumIncludes);
HFI.ControllingMacroID = Reader.getGlobalIdentifierID(
M, endian::readNext<uint32_t, little, unaligned>(d));
if (unsigned FrameworkOffset =
@@ -2963,6 +2958,22 @@ ASTReader::ReadControlBlock(ModuleFile &F,
}
}
+void ASTReader::readIncludedFiles(ModuleFile &F, StringRef Blob,
+ Preprocessor &PP) {
+ using namespace llvm::support;
+
+ const unsigned char *D = (const unsigned char *)Blob.data();
+ unsigned FileCount = endian::readNext<uint32_t, little, unaligned>(D);
+
+ for (unsigned I = 0; I < FileCount; ++I) {
+ size_t ID = endian::readNext<uint32_t, little, unaligned>(D);
+ InputFileInfo IFI = readInputFileInfo(F, ID);
+ if (llvm::ErrorOr<const FileEntry *> File =
+ PP.getFileManager().getFile(IFI.Filename))
+ PP.getIncludedFiles().insert(*File);
+ }
+}
+
llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
unsigned ClientLoadCapabilities) {
BitstreamCursor &Stream = F.Stream;
@@ -3701,6 +3712,10 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
break;
}
+ case PP_INCLUDED_FILES:
+ readIncludedFiles(F, Blob, PP);
+ break;
+
case LATE_PARSED_TEMPLATE:
LateParsedTemplates.emplace_back(
std::piecewise_construct, std::forward_as_tuple(&F),
@@ -4762,11 +4777,11 @@ ASTReader::ASTReadResult ASTReader::readUnhashedControlBlockImpl(
break;
unsigned Count = Record[0];
const char *Byte = Blob.data();
- F->SearchPathUsage = llvm::BitVector(Count, 0);
+ F->SearchPathUsage = llvm::BitVector(Count, false);
for (unsigned I = 0; I < Count; ++Byte)
for (unsigned Bit = 0; Bit < 8 && I < Count; ++Bit, ++I)
if (*Byte & (1 << Bit))
- F->SearchPathUsage[I] = 1;
+ F->SearchPathUsage[I] = true;
break;
}
}
@@ -6629,7 +6644,8 @@ void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
}
void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
- TL.setNameLoc(readSourceLocation());
+ TL.setDecltypeLoc(readSourceLocation());
+ TL.setRParenLoc(readSourceLocation());
}
void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
@@ -6652,6 +6668,8 @@ void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) {
TL.setArgLocInfo(i, Reader.readTemplateArgumentLocInfo(
TL.getTypePtr()->getArg(i).getKind()));
}
+ if (Reader.readBool())
+ TL.setRParenLoc(readSourceLocation());
}
void TypeLocReader::VisitDeducedTemplateSpecializationTypeLoc(
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 2144befcdb14..1ab26e58a404 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2945,391 +2945,6 @@ uint64_t ASTReader::getGlobalBitOffset(ModuleFile &M, uint64_t LocalOffset) {
return LocalOffset + M.GlobalBitOffset;
}
-static bool isSameTemplateParameterList(const ASTContext &C,
- const TemplateParameterList *X,
- const TemplateParameterList *Y);
-static bool isSameEntity(NamedDecl *X, NamedDecl *Y);
-
-/// Determine whether two template parameters are similar enough
-/// that they may be used in declarations of the same template.
-static bool isSameTemplateParameter(const NamedDecl *X,
- const NamedDecl *Y) {
- if (X->getKind() != Y->getKind())
- return false;
-
- if (const auto *TX = dyn_cast<TemplateTypeParmDecl>(X)) {
- const auto *TY = cast<TemplateTypeParmDecl>(Y);
- if (TX->isParameterPack() != TY->isParameterPack())
- return false;
- if (TX->hasTypeConstraint() != TY->hasTypeConstraint())
- return false;
- const TypeConstraint *TXTC = TX->getTypeConstraint();
- const TypeConstraint *TYTC = TY->getTypeConstraint();
- if (!TXTC != !TYTC)
- return false;
- if (TXTC && TYTC) {
- auto *NCX = TXTC->getNamedConcept();
- auto *NCY = TYTC->getNamedConcept();
- if (!NCX || !NCY || !isSameEntity(NCX, NCY))
- return false;
- if (TXTC->hasExplicitTemplateArgs() != TYTC->hasExplicitTemplateArgs())
- return false;
- if (TXTC->hasExplicitTemplateArgs()) {
- const auto *TXTCArgs = TXTC->getTemplateArgsAsWritten();
- const auto *TYTCArgs = TYTC->getTemplateArgsAsWritten();
- if (TXTCArgs->NumTemplateArgs != TYTCArgs->NumTemplateArgs)
- return false;
- llvm::FoldingSetNodeID XID, YID;
- for (const auto &ArgLoc : TXTCArgs->arguments())
- ArgLoc.getArgument().Profile(XID, X->getASTContext());
- for (const auto &ArgLoc : TYTCArgs->arguments())
- ArgLoc.getArgument().Profile(YID, Y->getASTContext());
- if (XID != YID)
- return false;
- }
- }
- return true;
- }
-
- if (const auto *TX = dyn_cast<NonTypeTemplateParmDecl>(X)) {
- const auto *TY = cast<NonTypeTemplateParmDecl>(Y);
- return TX->isParameterPack() == TY->isParameterPack() &&
- TX->getASTContext().hasSameType(TX->getType(), TY->getType());
- }
-
- const auto *TX = cast<TemplateTemplateParmDecl>(X);
- const auto *TY = cast<TemplateTemplateParmDecl>(Y);
- return TX->isParameterPack() == TY->isParameterPack() &&
- isSameTemplateParameterList(TX->getASTContext(),
- TX->getTemplateParameters(),
- TY->getTemplateParameters());
-}
-
-static NamespaceDecl *getNamespace(const NestedNameSpecifier *X) {
- if (auto *NS = X->getAsNamespace())
- return NS;
- if (auto *NAS = X->getAsNamespaceAlias())
- return NAS->getNamespace();
- return nullptr;
-}
-
-static bool isSameQualifier(const NestedNameSpecifier *X,
- const NestedNameSpecifier *Y) {
- if (auto *NSX = getNamespace(X)) {
- auto *NSY = getNamespace(Y);
- if (!NSY || NSX->getCanonicalDecl() != NSY->getCanonicalDecl())
- return false;
- } else if (X->getKind() != Y->getKind())
- return false;
-
- // FIXME: For namespaces and types, we're permitted to check that the entity
- // is named via the same tokens. We should probably do so.
- switch (X->getKind()) {
- case NestedNameSpecifier::Identifier:
- if (X->getAsIdentifier() != Y->getAsIdentifier())
- return false;
- break;
- case NestedNameSpecifier::Namespace:
- case NestedNameSpecifier::NamespaceAlias:
- // We've already checked that we named the same namespace.
- break;
- case NestedNameSpecifier::TypeSpec:
- case NestedNameSpecifier::TypeSpecWithTemplate:
- if (X->getAsType()->getCanonicalTypeInternal() !=
- Y->getAsType()->getCanonicalTypeInternal())
- return false;
- break;
- case NestedNameSpecifier::Global:
- case NestedNameSpecifier::Super:
- return true;
- }
-
- // Recurse into earlier portion of NNS, if any.
- auto *PX = X->getPrefix();
- auto *PY = Y->getPrefix();
- if (PX && PY)
- return isSameQualifier(PX, PY);
- return !PX && !PY;
-}
-
-/// Determine whether two template parameter lists are similar enough
-/// that they may be used in declarations of the same template.
-static bool isSameTemplateParameterList(const ASTContext &C,
- const TemplateParameterList *X,
- const TemplateParameterList *Y) {
- if (X->size() != Y->size())
- return false;
-
- for (unsigned I = 0, N = X->size(); I != N; ++I)
- if (!isSameTemplateParameter(X->getParam(I), Y->getParam(I)))
- return false;
-
- const Expr *XRC = X->getRequiresClause();
- const Expr *YRC = Y->getRequiresClause();
- if (!XRC != !YRC)
- return false;
- if (XRC) {
- llvm::FoldingSetNodeID XRCID, YRCID;
- XRC->Profile(XRCID, C, /*Canonical=*/true);
- YRC->Profile(YRCID, C, /*Canonical=*/true);
- if (XRCID != YRCID)
- return false;
- }
-
- return true;
-}
-
-/// Determine whether the attributes we can overload on are identical for A and
-/// B. Will ignore any overloadable attrs represented in the type of A and B.
-static bool hasSameOverloadableAttrs(const FunctionDecl *A,
- const FunctionDecl *B) {
- // Note that pass_object_size attributes are represented in the function's
- // ExtParameterInfo, so we don't need to check them here.
-
- llvm::FoldingSetNodeID Cand1ID, Cand2ID;
- auto AEnableIfAttrs = A->specific_attrs<EnableIfAttr>();
- auto BEnableIfAttrs = B->specific_attrs<EnableIfAttr>();
-
- for (auto Pair : zip_longest(AEnableIfAttrs, BEnableIfAttrs)) {
- Optional<EnableIfAttr *> Cand1A = std::get<0>(Pair);
- Optional<EnableIfAttr *> Cand2A = std::get<1>(Pair);
-
- // Return false if the number of enable_if attributes is different.
- if (!Cand1A || !Cand2A)
- return false;
-
- Cand1ID.clear();
- Cand2ID.clear();
-
- (*Cand1A)->getCond()->Profile(Cand1ID, A->getASTContext(), true);
- (*Cand2A)->getCond()->Profile(Cand2ID, B->getASTContext(), true);
-
- // Return false if any of the enable_if expressions of A and B are
- // different.
- if (Cand1ID != Cand2ID)
- return false;
- }
- return true;
-}
-
-/// Determine whether the two declarations refer to the same entity.
-static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
- if (X == Y)
- return true;
-
- if (X->getDeclName() != Y->getDeclName())
- return false;
-
- // Must be in the same context.
- //
- // Note that we can't use DeclContext::Equals here, because the DeclContexts
- // could be two different declarations of the same function. (We will fix the
- // semantic DC to refer to the primary definition after merging.)
- if (!declaresSameEntity(cast<Decl>(X->getDeclContext()->getRedeclContext()),
- cast<Decl>(Y->getDeclContext()->getRedeclContext())))
- return false;
-
- // Two typedefs refer to the same entity if they have the same underlying
- // type.
- if (const auto *TypedefX = dyn_cast<TypedefNameDecl>(X))
- if (const auto *TypedefY = dyn_cast<TypedefNameDecl>(Y))
- return X->getASTContext().hasSameType(TypedefX->getUnderlyingType(),
- TypedefY->getUnderlyingType());
-
- // Must have the same kind.
- if (X->getKind() != Y->getKind())
- return false;
-
- // Objective-C classes and protocols with the same name always match.
- if (isa<ObjCInterfaceDecl>(X) || isa<ObjCProtocolDecl>(X))
- return true;
-
- if (isa<ClassTemplateSpecializationDecl>(X)) {
- // No need to handle these here: we merge them when adding them to the
- // template.
- return false;
- }
-
- // Compatible tags match.
- if (const auto *TagX = dyn_cast<TagDecl>(X)) {
- const auto *TagY = cast<TagDecl>(Y);
- return (TagX->getTagKind() == TagY->getTagKind()) ||
- ((TagX->getTagKind() == TTK_Struct || TagX->getTagKind() == TTK_Class ||
- TagX->getTagKind() == TTK_Interface) &&
- (TagY->getTagKind() == TTK_Struct || TagY->getTagKind() == TTK_Class ||
- TagY->getTagKind() == TTK_Interface));
- }
-
- // Functions with the same type and linkage match.
- // FIXME: This needs to cope with merging of prototyped/non-prototyped
- // functions, etc.
- if (const auto *FuncX = dyn_cast<FunctionDecl>(X)) {
- const auto *FuncY = cast<FunctionDecl>(Y);
- if (const auto *CtorX = dyn_cast<CXXConstructorDecl>(X)) {
- const auto *CtorY = cast<CXXConstructorDecl>(Y);
- if (CtorX->getInheritedConstructor() &&
- !isSameEntity(CtorX->getInheritedConstructor().getConstructor(),
- CtorY->getInheritedConstructor().getConstructor()))
- return false;
- }
-
- if (FuncX->isMultiVersion() != FuncY->isMultiVersion())
- return false;
-
- // Multiversioned functions with different feature strings are represented
- // as separate declarations.
- if (FuncX->isMultiVersion()) {
- const auto *TAX = FuncX->getAttr<TargetAttr>();
- const auto *TAY = FuncY->getAttr<TargetAttr>();
- assert(TAX && TAY && "Multiversion Function without target attribute");
-
- if (TAX->getFeaturesStr() != TAY->getFeaturesStr())
- return false;
- }
-
- ASTContext &C = FuncX->getASTContext();
-
- const Expr *XRC = FuncX->getTrailingRequiresClause();
- const Expr *YRC = FuncY->getTrailingRequiresClause();
- if (!XRC != !YRC)
- return false;
- if (XRC) {
- llvm::FoldingSetNodeID XRCID, YRCID;
- XRC->Profile(XRCID, C, /*Canonical=*/true);
- YRC->Profile(YRCID, C, /*Canonical=*/true);
- if (XRCID != YRCID)
- return false;
- }
-
- auto GetTypeAsWritten = [](const FunctionDecl *FD) {
- // Map to the first declaration that we've already merged into this one.
- // The TSI of redeclarations might not match (due to calling conventions
- // being inherited onto the type but not the TSI), but the TSI type of
- // the first declaration of the function should match across modules.
- FD = FD->getCanonicalDecl();
- return FD->getTypeSourceInfo() ? FD->getTypeSourceInfo()->getType()
- : FD->getType();
- };
- QualType XT = GetTypeAsWritten(FuncX), YT = GetTypeAsWritten(FuncY);
- if (!C.hasSameType(XT, YT)) {
- // We can get functions with different types on the redecl chain in C++17
- // if they have differing exception specifications and at least one of
- // the excpetion specs is unresolved.
- auto *XFPT = XT->getAs<FunctionProtoType>();
- auto *YFPT = YT->getAs<FunctionProtoType>();
- if (C.getLangOpts().CPlusPlus17 && XFPT && YFPT &&
- (isUnresolvedExceptionSpec(XFPT->getExceptionSpecType()) ||
- isUnresolvedExceptionSpec(YFPT->getExceptionSpecType())) &&
- C.hasSameFunctionTypeIgnoringExceptionSpec(XT, YT))
- return true;
- return false;
- }
-
- return FuncX->getLinkageInternal() == FuncY->getLinkageInternal() &&
- hasSameOverloadableAttrs(FuncX, FuncY);
- }
-
- // Variables with the same type and linkage match.
- if (const auto *VarX = dyn_cast<VarDecl>(X)) {
- const auto *VarY = cast<VarDecl>(Y);
- if (VarX->getLinkageInternal() == VarY->getLinkageInternal()) {
- ASTContext &C = VarX->getASTContext();
- if (C.hasSameType(VarX->getType(), VarY->getType()))
- return true;
-
- // We can get decls with different types on the redecl chain. Eg.
- // template <typename T> struct S { static T Var[]; }; // #1
- // template <typename T> T S<T>::Var[sizeof(T)]; // #2
- // Only? happens when completing an incomplete array type. In this case
- // when comparing #1 and #2 we should go through their element type.
- const ArrayType *VarXTy = C.getAsArrayType(VarX->getType());
- const ArrayType *VarYTy = C.getAsArrayType(VarY->getType());
- if (!VarXTy || !VarYTy)
- return false;
- if (VarXTy->isIncompleteArrayType() || VarYTy->isIncompleteArrayType())
- return C.hasSameType(VarXTy->getElementType(), VarYTy->getElementType());
- }
- return false;
- }
-
- // Namespaces with the same name and inlinedness match.
- if (const auto *NamespaceX = dyn_cast<NamespaceDecl>(X)) {
- const auto *NamespaceY = cast<NamespaceDecl>(Y);
- return NamespaceX->isInline() == NamespaceY->isInline();
- }
-
- // Identical template names and kinds match if their template parameter lists
- // and patterns match.
- if (const auto *TemplateX = dyn_cast<TemplateDecl>(X)) {
- const auto *TemplateY = cast<TemplateDecl>(Y);
- return isSameEntity(TemplateX->getTemplatedDecl(),
- TemplateY->getTemplatedDecl()) &&
- isSameTemplateParameterList(TemplateX->getASTContext(),
- TemplateX->getTemplateParameters(),
- TemplateY->getTemplateParameters());
- }
-
- // Fields with the same name and the same type match.
- if (const auto *FDX = dyn_cast<FieldDecl>(X)) {
- const auto *FDY = cast<FieldDecl>(Y);
- // FIXME: Also check the bitwidth is odr-equivalent, if any.
- return X->getASTContext().hasSameType(FDX->getType(), FDY->getType());
- }
-
- // Indirect fields with the same target field match.
- if (const auto *IFDX = dyn_cast<IndirectFieldDecl>(X)) {
- const auto *IFDY = cast<IndirectFieldDecl>(Y);
- return IFDX->getAnonField()->getCanonicalDecl() ==
- IFDY->getAnonField()->getCanonicalDecl();
- }
-
- // Enumerators with the same name match.
- if (isa<EnumConstantDecl>(X))
- // FIXME: Also check the value is odr-equivalent.
- return true;
-
- // Using shadow declarations with the same target match.
- if (const auto *USX = dyn_cast<UsingShadowDecl>(X)) {
- const auto *USY = cast<UsingShadowDecl>(Y);
- return USX->getTargetDecl() == USY->getTargetDecl();
- }
-
- // Using declarations with the same qualifier match. (We already know that
- // the name matches.)
- if (const auto *UX = dyn_cast<UsingDecl>(X)) {
- const auto *UY = cast<UsingDecl>(Y);
- return isSameQualifier(UX->getQualifier(), UY->getQualifier()) &&
- UX->hasTypename() == UY->hasTypename() &&
- UX->isAccessDeclaration() == UY->isAccessDeclaration();
- }
- if (const auto *UX = dyn_cast<UnresolvedUsingValueDecl>(X)) {
- const auto *UY = cast<UnresolvedUsingValueDecl>(Y);
- return isSameQualifier(UX->getQualifier(), UY->getQualifier()) &&
- UX->isAccessDeclaration() == UY->isAccessDeclaration();
- }
- if (const auto *UX = dyn_cast<UnresolvedUsingTypenameDecl>(X)) {
- return isSameQualifier(
- UX->getQualifier(),
- cast<UnresolvedUsingTypenameDecl>(Y)->getQualifier());
- }
-
- // Using-pack declarations are only created by instantiation, and match if
- // they're instantiated from matching UnresolvedUsing...Decls.
- if (const auto *UX = dyn_cast<UsingPackDecl>(X)) {
- return declaresSameEntity(
- UX->getInstantiatedFromUsingDecl(),
- cast<UsingPackDecl>(Y)->getInstantiatedFromUsingDecl());
- }
-
- // Namespace alias definitions with the same target match.
- if (const auto *NAX = dyn_cast<NamespaceAliasDecl>(X)) {
- const auto *NAY = cast<NamespaceAliasDecl>(Y);
- return NAX->getNamespace()->Equals(NAY->getNamespace());
- }
-
- return false;
-}
-
/// Find the context in which we should search for previous declarations when
/// looking for declarations to merge.
DeclContext *ASTDeclReader::getPrimaryContextForMerging(ASTReader &Reader,
@@ -3511,12 +3126,13 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
return Result;
}
+ ASTContext &C = Reader.getContext();
DeclContext *DC = D->getDeclContext()->getRedeclContext();
if (TypedefNameForLinkage) {
auto It = Reader.ImportedTypedefNamesForLinkage.find(
std::make_pair(DC, TypedefNameForLinkage));
if (It != Reader.ImportedTypedefNamesForLinkage.end())
- if (isSameEntity(It->second, D))
+ if (C.isSameEntity(It->second, D))
return FindExistingResult(Reader, D, It->second, AnonymousDeclNumber,
TypedefNameForLinkage);
// Go on to check in other places in case an existing typedef name
@@ -3528,7 +3144,7 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
// in its context by number.
if (auto *Existing = getAnonymousDeclForMerging(
Reader, D->getLexicalDeclContext(), AnonymousDeclNumber))
- if (isSameEntity(Existing, D))
+ if (C.isSameEntity(Existing, D))
return FindExistingResult(Reader, D, Existing, AnonymousDeclNumber,
TypedefNameForLinkage);
} else if (DC->isTranslationUnit() &&
@@ -3560,7 +3176,7 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
IEnd = IdResolver.end();
I != IEnd; ++I) {
if (NamedDecl *Existing = getDeclForMerging(*I, TypedefNameForLinkage))
- if (isSameEntity(Existing, D))
+ if (C.isSameEntity(Existing, D))
return FindExistingResult(Reader, D, Existing, AnonymousDeclNumber,
TypedefNameForLinkage);
}
@@ -3568,7 +3184,7 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
DeclContext::lookup_result R = MergeDC->noload_lookup(Name);
for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; ++I) {
if (NamedDecl *Existing = getDeclForMerging(*I, TypedefNameForLinkage))
- if (isSameEntity(Existing, D))
+ if (C.isSameEntity(Existing, D))
return FindExistingResult(Reader, D, Existing, AnonymousDeclNumber,
TypedefNameForLinkage);
}
@@ -4781,10 +4397,12 @@ void ASTDeclReader::UpdateDecl(Decl *D,
case UPD_DECL_MARKED_OPENMP_DECLARETARGET: {
auto MapType = Record.readEnum<OMPDeclareTargetDeclAttr::MapTypeTy>();
auto DevType = Record.readEnum<OMPDeclareTargetDeclAttr::DevTypeTy>();
+ Expr *IndirectE = Record.readExpr();
+ bool Indirect = Record.readBool();
unsigned Level = Record.readInt();
D->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit(
- Reader.getContext(), MapType, DevType, Level, readSourceRange(),
- AttributeCommonInfo::AS_Pragma));
+ Reader.getContext(), MapType, DevType, IndirectE, Indirect, Level,
+ readSourceRange(), AttributeCommonInfo::AS_Pragma));
break;
}
diff --git a/clang/lib/Serialization/ASTReaderInternals.h b/clang/lib/Serialization/ASTReaderInternals.h
index 265a77fdb215..4a4cfcce156d 100644
--- a/clang/lib/Serialization/ASTReaderInternals.h
+++ b/clang/lib/Serialization/ASTReaderInternals.h
@@ -30,7 +30,6 @@ class ASTReader;
class FileEntry;
struct HeaderFileInfo;
class HeaderSearch;
-class IdentifierTable;
class ObjCMethodDecl;
namespace serialization {
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 65a780e67510..763fc9537c04 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -427,7 +427,8 @@ void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
}
void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
- Record.AddSourceLocation(TL.getNameLoc());
+ Record.AddSourceLocation(TL.getDecltypeLoc());
+ Record.AddSourceLocation(TL.getRParenLoc());
}
void TypeLocWriter::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
@@ -451,6 +452,9 @@ void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) {
Record.AddTemplateArgumentLocInfo(TL.getTypePtr()->getArg(I).getKind(),
TL.getArgLocInfo(I));
}
+ Record.push_back(TL.isDecltypeAuto());
+ if (TL.isDecltypeAuto())
+ Record.AddSourceLocation(TL.getRParenLoc());
}
void TypeLocWriter::VisitDeducedTemplateSpecializationTypeLoc(
@@ -858,6 +862,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(CUDA_PRAGMA_FORCE_HOST_DEVICE_DEPTH);
RECORD(PP_CONDITIONAL_STACK);
RECORD(DECLS_TO_CHECK_FOR_DEFERRED_DIAGS);
+ RECORD(PP_INCLUDED_FILES);
// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
@@ -1769,7 +1774,7 @@ namespace {
std::pair<unsigned, unsigned>
EmitKeyDataLength(raw_ostream& Out, key_type_ref key, data_type_ref Data) {
unsigned KeyLen = key.Filename.size() + 1 + 8 + 8;
- unsigned DataLen = 1 + 2 + 4 + 4;
+ unsigned DataLen = 1 + 4 + 4;
for (auto ModInfo : Data.KnownHeaders)
if (Writer.getLocalOrImportedSubmoduleID(ModInfo.getModule()))
DataLen += 4;
@@ -1801,7 +1806,6 @@ namespace {
| (Data.HFI.DirInfo << 1)
| Data.HFI.IndexHeaderMapHeader;
LE.write<uint8_t>(Flags);
- LE.write<uint16_t>(Data.HFI.NumIncludes);
if (!Data.HFI.ControllingMacro)
LE.write<uint32_t>(Data.HFI.ControllingMacroID);
@@ -2250,6 +2254,29 @@ static bool shouldIgnoreMacro(MacroDirective *MD, bool IsModule,
return false;
}
+void ASTWriter::writeIncludedFiles(raw_ostream &Out, const Preprocessor &PP) {
+ using namespace llvm::support;
+
+ const Preprocessor::IncludedFilesSet &IncludedFiles = PP.getIncludedFiles();
+
+ std::vector<uint32_t> IncludedInputFileIDs;
+ IncludedInputFileIDs.reserve(IncludedFiles.size());
+
+ for (const FileEntry *File : IncludedFiles) {
+ auto InputFileIt = InputFileIDs.find(File);
+ if (InputFileIt == InputFileIDs.end())
+ continue;
+ IncludedInputFileIDs.push_back(InputFileIt->second);
+ }
+
+ llvm::sort(IncludedInputFileIDs);
+
+ endian::Writer LE(Out, little);
+ LE.write<uint32_t>(IncludedInputFileIDs.size());
+ for (uint32_t ID : IncludedInputFileIDs)
+ LE.write<uint32_t>(ID);
+}
+
/// Writes the block containing the serialized form of the
/// preprocessor.
void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
@@ -2458,6 +2485,20 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
MacroOffsetsBase - ASTBlockStartOffset};
Stream.EmitRecordWithBlob(MacroOffsetAbbrev, Record, bytes(MacroOffsets));
}
+
+ {
+ auto Abbrev = std::make_shared<BitCodeAbbrev>();
+ Abbrev->Add(BitCodeAbbrevOp(PP_INCLUDED_FILES));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned IncludedFilesAbbrev = Stream.EmitAbbrev(std::move(Abbrev));
+
+ SmallString<2048> Buffer;
+ raw_svector_ostream Out(Buffer);
+ writeIncludedFiles(Out, PP);
+ RecordData::value_type Record[] = {PP_INCLUDED_FILES};
+ Stream.EmitRecordWithBlob(IncludedFilesAbbrev, Record, Buffer.data(),
+ Buffer.size());
+ }
}
void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec,
diff --git a/clang/lib/Serialization/ModuleManager.cpp b/clang/lib/Serialization/ModuleManager.cpp
index f4882c7be3f7..4fd217cf7a6e 100644
--- a/clang/lib/Serialization/ModuleManager.cpp
+++ b/clang/lib/Serialization/ModuleManager.cpp
@@ -304,23 +304,22 @@ ModuleManager::addInMemoryBuffer(StringRef FileName,
InMemoryBuffers[Entry] = std::move(Buffer);
}
-ModuleManager::VisitState *ModuleManager::allocateVisitState() {
+std::unique_ptr<ModuleManager::VisitState> ModuleManager::allocateVisitState() {
// Fast path: if we have a cached state, use it.
if (FirstVisitState) {
- VisitState *Result = FirstVisitState;
- FirstVisitState = FirstVisitState->NextState;
- Result->NextState = nullptr;
+ auto Result = std::move(FirstVisitState);
+ FirstVisitState = std::move(Result->NextState);
return Result;
}
// Allocate and return a new state.
- return new VisitState(size());
+ return std::make_unique<VisitState>(size());
}
-void ModuleManager::returnVisitState(VisitState *State) {
+void ModuleManager::returnVisitState(std::unique_ptr<VisitState> State) {
assert(State->NextState == nullptr && "Visited state is in list?");
- State->NextState = FirstVisitState;
- FirstVisitState = State;
+ State->NextState = std::move(FirstVisitState);
+ FirstVisitState = std::move(State);
}
void ModuleManager::setGlobalIndex(GlobalModuleIndex *Index) {
@@ -351,8 +350,6 @@ ModuleManager::ModuleManager(FileManager &FileMgr,
: FileMgr(FileMgr), ModuleCache(&ModuleCache),
PCHContainerRdr(PCHContainerRdr), HeaderSearchInfo(HeaderSearchInfo) {}
-ModuleManager::~ModuleManager() { delete FirstVisitState; }
-
void ModuleManager::visit(llvm::function_ref<bool(ModuleFile &M)> Visitor,
llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit) {
// If the visitation order vector is the wrong size, recompute the order.
@@ -396,11 +393,10 @@ void ModuleManager::visit(llvm::function_ref<bool(ModuleFile &M)> Visitor,
assert(VisitOrder.size() == N && "Visitation order is wrong?");
- delete FirstVisitState;
FirstVisitState = nullptr;
}
- VisitState *State = allocateVisitState();
+ auto State = allocateVisitState();
unsigned VisitNumber = State->NextVisitNumber++;
// If the caller has provided us with a hit-set that came from the global
@@ -452,7 +448,7 @@ void ModuleManager::visit(llvm::function_ref<bool(ModuleFile &M)> Visitor,
} while (true);
}
- returnVisitState(State);
+ returnVisitState(std::move(State));
}
bool ModuleManager::lookupModuleFile(StringRef FileName, off_t ExpectedSize,
diff --git a/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
index 7cdd78b8adfb..7841fd82e370 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
@@ -302,7 +302,7 @@ class ExplodedGraphViewer : public Checker< check::EndAnalysis > {
public:
ExplodedGraphViewer() {}
void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const {
- Eng.ViewGraph(0);
+ Eng.ViewGraph(false);
}
};
diff --git a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
index 66ef781871ec..e2209e3debfd 100644
--- a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -22,15 +22,14 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "llvm/Support/YAMLTraits.h"
-#include <algorithm>
#include <limits>
#include <memory>
-#include <unordered_map>
#include <utility>
using namespace clang;
@@ -38,577 +37,651 @@ using namespace ento;
using namespace taint;
namespace {
-class GenericTaintChecker : public Checker<check::PreCall, check::PostCall> {
-public:
- static void *getTag() {
- static int Tag;
- return &Tag;
- }
- void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
- void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
+class GenericTaintChecker;
- void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
- const char *Sep) const override;
+/// Check for CWE-134: Uncontrolled Format String.
+constexpr llvm::StringLiteral MsgUncontrolledFormatString =
+ "Untrusted data is used as a format string "
+ "(CWE-134: Uncontrolled Format String)";
- using ArgVector = SmallVector<unsigned, 2>;
- using SignedArgVector = SmallVector<int, 2>;
+/// Check for:
+/// CERT/STR02-C. "Sanitize data passed to complex subsystems"
+/// CWE-78, "Failure to Sanitize Data into an OS Command"
+constexpr llvm::StringLiteral MsgSanitizeSystemArgs =
+ "Untrusted data is passed to a system call "
+ "(CERT/STR02-C. Sanitize data passed to complex subsystems)";
- enum class VariadicType { None, Src, Dst };
+/// Check if tainted data is used as a buffer size in strn.. functions,
+/// and allocators.
+constexpr llvm::StringLiteral MsgTaintedBufferSize =
+ "Untrusted data is used to specify the buffer size "
+ "(CERT/STR31-C. Guarantee that storage for strings has sufficient space "
+ "for character data and the null terminator)";
- /// Used to parse the configuration file.
- struct TaintConfiguration {
- using NameScopeArgs = std::tuple<std::string, std::string, ArgVector>;
+/// Check if tainted data is used as a custom sink's parameter.
+constexpr llvm::StringLiteral MsgCustomSink =
+ "Untrusted data is passed to a user-defined sink";
- struct Propagation {
- std::string Name;
- std::string Scope;
- ArgVector SrcArgs;
- SignedArgVector DstArgs;
- VariadicType VarType;
- unsigned VarIndex;
- };
+using ArgIdxTy = int;
+using ArgVecTy = llvm::SmallVector<ArgIdxTy, 2>;
- std::vector<Propagation> Propagations;
- std::vector<NameScopeArgs> Filters;
- std::vector<NameScopeArgs> Sinks;
+/// Denotes the return value.
+constexpr ArgIdxTy ReturnValueIndex{-1};
- TaintConfiguration() = default;
- TaintConfiguration(const TaintConfiguration &) = default;
- TaintConfiguration(TaintConfiguration &&) = default;
- TaintConfiguration &operator=(const TaintConfiguration &) = default;
- TaintConfiguration &operator=(TaintConfiguration &&) = default;
- };
+static ArgIdxTy fromArgumentCount(unsigned Count) {
+ assert(Count <=
+ static_cast<std::size_t>(std::numeric_limits<ArgIdxTy>::max()) &&
+ "ArgIdxTy is not large enough to represent the number of arguments.");
+ return Count;
+}
- /// Convert SignedArgVector to ArgVector.
- ArgVector convertToArgVector(CheckerManager &Mgr, const std::string &Option,
- const SignedArgVector &Args);
+/// Check if the region the expression evaluates to is the standard input,
+/// and thus, is tainted.
+/// FIXME: Move this to Taint.cpp.
+bool isStdin(SVal Val, const ASTContext &ACtx) {
+ // FIXME: What if Val is NonParamVarRegion?
- /// Parse the config.
- void parseConfiguration(CheckerManager &Mgr, const std::string &Option,
- TaintConfiguration &&Config);
+ // The region should be symbolic, we do not know it's value.
+ const auto *SymReg = dyn_cast_or_null<SymbolicRegion>(Val.getAsRegion());
+ if (!SymReg)
+ return false;
- static const unsigned InvalidArgIndex{std::numeric_limits<unsigned>::max()};
- /// Denotes the return vale.
- static const unsigned ReturnValueIndex{std::numeric_limits<unsigned>::max() -
- 1};
+ // Get it's symbol and find the declaration region it's pointing to.
+ const auto *Sm = dyn_cast<SymbolRegionValue>(SymReg->getSymbol());
+ if (!Sm)
+ return false;
+ const auto *DeclReg = dyn_cast<DeclRegion>(Sm->getRegion());
+ if (!DeclReg)
+ return false;
-private:
- mutable std::unique_ptr<BugType> BT;
- void initBugType() const {
- if (!BT)
- BT = std::make_unique<BugType>(this, "Use of Untrusted Data",
- "Untrusted Data");
+ // This region corresponds to a declaration, find out if it's a global/extern
+ // variable named stdin with the proper type.
+ if (const auto *D = dyn_cast_or_null<VarDecl>(DeclReg->getDecl())) {
+ D = D->getCanonicalDecl();
+ // FIXME: This should look for an exact match.
+ if (D->getName().contains("stdin") && D->isExternC()) {
+ const QualType FILETy = ACtx.getFILEType().getCanonicalType();
+ const QualType Ty = D->getType().getCanonicalType();
+
+ if (Ty->isPointerType())
+ return Ty->getPointeeType() == FILETy;
+ }
}
+ return false;
+}
- struct FunctionData {
- FunctionData() = delete;
- FunctionData(const FunctionDecl *FDecl, StringRef Name,
- std::string FullName)
- : FDecl(FDecl), Name(Name), FullName(std::move(FullName)) {}
- FunctionData(const FunctionData &) = default;
- FunctionData(FunctionData &&) = default;
- FunctionData &operator=(const FunctionData &) = delete;
- FunctionData &operator=(FunctionData &&) = delete;
+SVal getPointeeOf(const CheckerContext &C, Loc LValue) {
+ const QualType ArgTy = LValue.getType(C.getASTContext());
+ if (!ArgTy->isPointerType() || !ArgTy->getPointeeType()->isVoidType())
+ return C.getState()->getSVal(LValue);
- static Optional<FunctionData> create(const CallEvent &Call,
- const CheckerContext &C) {
- if (!Call.getDecl())
- return None;
+ // Do not dereference void pointers. Treat them as byte pointers instead.
+ // FIXME: we might want to consider more than just the first byte.
+ return C.getState()->getSVal(LValue, C.getASTContext().CharTy);
+}
- const FunctionDecl *FDecl = Call.getDecl()->getAsFunction();
- if (!FDecl || (FDecl->getKind() != Decl::Function &&
- FDecl->getKind() != Decl::CXXMethod))
- return None;
+/// Given a pointer/reference argument, return the value it refers to.
+Optional<SVal> getPointeeOf(const CheckerContext &C, SVal Arg) {
+ if (auto LValue = Arg.getAs<Loc>())
+ return getPointeeOf(C, *LValue);
+ return None;
+}
- StringRef Name = C.getCalleeName(FDecl);
- std::string FullName = FDecl->getQualifiedNameAsString();
- if (Name.empty() || FullName.empty())
- return None;
+/// Given a pointer, return the SVal of its pointee or if it is tainted,
+/// otherwise return the pointer's SVal if tainted.
+/// Also considers stdin as a taint source.
+Optional<SVal> getTaintedPointeeOrPointer(const CheckerContext &C, SVal Arg) {
+ const ProgramStateRef State = C.getState();
- return FunctionData{FDecl, Name, std::move(FullName)};
- }
+ if (auto Pointee = getPointeeOf(C, Arg))
+ if (isTainted(State, *Pointee)) // FIXME: isTainted(...) ? Pointee : None;
+ return Pointee;
- bool isInScope(StringRef Scope) const {
- return StringRef(FullName).startswith(Scope);
- }
+ if (isTainted(State, Arg))
+ return Arg;
- const FunctionDecl *const FDecl;
- const StringRef Name;
- const std::string FullName;
- };
+ // FIXME: This should be done by the isTainted() API.
+ if (isStdin(Arg, C.getASTContext()))
+ return Arg;
- /// Catch taint related bugs. Check if tainted data is passed to a
- /// system call etc. Returns true on matching.
- bool checkPre(const CallEvent &Call, const FunctionData &FData,
- CheckerContext &C) const;
+ return None;
+}
- /// Add taint sources on a pre-visit. Returns true on matching.
- bool addSourcesPre(const CallEvent &Call, const FunctionData &FData,
- CheckerContext &C) const;
+bool isTaintedOrPointsToTainted(const Expr *E, const ProgramStateRef &State,
+ CheckerContext &C) {
+ return getTaintedPointeeOrPointer(C, C.getSVal(E)).hasValue();
+}
- /// Mark filter's arguments not tainted on a pre-visit. Returns true on
- /// matching.
- bool addFiltersPre(const CallEvent &Call, const FunctionData &FData,
- CheckerContext &C) const;
+/// ArgSet is used to describe arguments relevant for taint detection or
+/// taint application. A discrete set of argument indexes and a variadic
+/// argument list signified by a starting index are supported.
+class ArgSet {
+public:
+ ArgSet() = default;
+ ArgSet(ArgVecTy &&DiscreteArgs, Optional<ArgIdxTy> VariadicIndex = None)
+ : DiscreteArgs(std::move(DiscreteArgs)),
+ VariadicIndex(std::move(VariadicIndex)) {}
- /// Propagate taint generated at pre-visit. Returns true on matching.
- static bool propagateFromPre(const CallEvent &Call, CheckerContext &C);
+ bool contains(ArgIdxTy ArgIdx) const {
+ if (llvm::is_contained(DiscreteArgs, ArgIdx))
+ return true;
- /// Check if the region the expression evaluates to is the standard input,
- /// and thus, is tainted.
- static bool isStdin(const Expr *E, CheckerContext &C);
+ return VariadicIndex && ArgIdx >= *VariadicIndex;
+ }
- /// Given a pointer argument, return the value it points to.
- static Optional<SVal> getPointeeOf(CheckerContext &C, const Expr *Arg);
+ bool isEmpty() const { return DiscreteArgs.empty() && !VariadicIndex; }
- /// Check for CWE-134: Uncontrolled Format String.
- static constexpr llvm::StringLiteral MsgUncontrolledFormatString =
- "Untrusted data is used as a format string "
- "(CWE-134: Uncontrolled Format String)";
- bool checkUncontrolledFormatString(const CallEvent &Call,
- CheckerContext &C) const;
+ ArgVecTy ArgsUpTo(ArgIdxTy LastArgIdx) const {
+ ArgVecTy Args;
+ for (ArgIdxTy I = ReturnValueIndex; I <= LastArgIdx; ++I) {
+ if (contains(I))
+ Args.push_back(I);
+ }
+ return Args;
+ }
- /// Check for:
- /// CERT/STR02-C. "Sanitize data passed to complex subsystems"
- /// CWE-78, "Failure to Sanitize Data into an OS Command"
- static constexpr llvm::StringLiteral MsgSanitizeSystemArgs =
- "Untrusted data is passed to a system call "
- "(CERT/STR02-C. Sanitize data passed to complex subsystems)";
- bool checkSystemCall(const CallEvent &Call, StringRef Name,
- CheckerContext &C) const;
+private:
+ ArgVecTy DiscreteArgs;
+ Optional<ArgIdxTy> VariadicIndex;
+};
- /// Check if tainted data is used as a buffer size ins strn.. functions,
- /// and allocators.
- static constexpr llvm::StringLiteral MsgTaintedBufferSize =
- "Untrusted data is used to specify the buffer size "
- "(CERT/STR31-C. Guarantee that storage for strings has sufficient space "
- "for character data and the null terminator)";
- bool checkTaintedBufferSize(const CallEvent &Call, CheckerContext &C) const;
+/// A struct used to specify taint propagation rules for a function.
+///
+/// If any of the possible taint source arguments is tainted, all of the
+/// destination arguments should also be tainted. If ReturnValueIndex is added
+/// to the dst list, the return value will be tainted.
+class GenericTaintRule {
+ /// Arguments which are taints sinks and should be checked, and a report
+ /// should be emitted if taint reaches these.
+ ArgSet SinkArgs;
+ /// Arguments which should be sanitized on function return.
+ ArgSet FilterArgs;
+ /// Arguments which can participate in taint propagationa. If any of the
+ /// arguments in PropSrcArgs is tainted, all arguments in PropDstArgs should
+ /// be tainted.
+ ArgSet PropSrcArgs;
+ ArgSet PropDstArgs;
- /// 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 CallEvent &Call, const FunctionData &FData,
- CheckerContext &C) const;
+ /// A message that explains why the call is sensitive to taint.
+ Optional<StringRef> SinkMsg;
- /// Generate a report if the expression is tainted or points to tainted data.
- bool generateReportIfTainted(const Expr *E, StringRef Msg,
- CheckerContext &C) const;
+ GenericTaintRule() = default;
- struct TaintPropagationRule;
- template <typename T>
- using ConfigDataMap =
- std::unordered_multimap<std::string, std::pair<std::string, T>>;
- using NameRuleMap = ConfigDataMap<TaintPropagationRule>;
- using NameArgMap = ConfigDataMap<ArgVector>;
+ GenericTaintRule(ArgSet &&Sink, ArgSet &&Filter, ArgSet &&Src, ArgSet &&Dst,
+ Optional<StringRef> SinkMsg = None)
+ : SinkArgs(std::move(Sink)), FilterArgs(std::move(Filter)),
+ PropSrcArgs(std::move(Src)), PropDstArgs(std::move(Dst)),
+ SinkMsg(SinkMsg) {}
- /// 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);
+public:
+ /// Make a rule that reports a warning if taint reaches any of \p FilterArgs
+ /// arguments.
+ static GenericTaintRule Sink(ArgSet &&SinkArgs,
+ Optional<StringRef> Msg = None) {
+ return {std::move(SinkArgs), {}, {}, {}, Msg};
+ }
- /// A struct used to specify taint propagation rules for a function.
- ///
- /// If any of the possible taint source arguments is tainted, all of the
- /// destination arguments should also be tainted. Use InvalidArgIndex in the
- /// src list to specify that all of the arguments can introduce taint. Use
- /// InvalidArgIndex in the dst arguments to signify that all the non-const
- /// pointer and reference arguments might be tainted on return. If
- /// ReturnValueIndex is added to the dst list, the return value will be
- /// tainted.
- struct TaintPropagationRule {
- using PropagationFuncType = bool (*)(bool IsTainted, const CallEvent &Call,
- CheckerContext &C);
+ /// Make a rule that sanitizes all FilterArgs arguments.
+ static GenericTaintRule Filter(ArgSet &&FilterArgs) {
+ return {{}, std::move(FilterArgs), {}, {}};
+ }
- /// List of arguments which can be taint sources and should be checked.
- ArgVector SrcArgs;
- /// List of arguments which should be tainted on function return.
- ArgVector DstArgs;
- /// Index for the first variadic parameter if exist.
- unsigned VariadicIndex;
- /// Show when a function has variadic parameters. If it has, it marks all
- /// of them as source or destination.
- VariadicType VarType;
- /// Special function for tainted source determination. If defined, it can
- /// override the default behavior.
- PropagationFuncType PropagationFunc;
+ /// Make a rule that unconditionally taints all Args.
+ /// If Func is provided, it must also return true for taint to propagate.
+ static GenericTaintRule Source(ArgSet &&SourceArgs) {
+ return {{}, {}, {}, std::move(SourceArgs)};
+ }
- TaintPropagationRule()
- : VariadicIndex(InvalidArgIndex), VarType(VariadicType::None),
- PropagationFunc(nullptr) {}
+ /// Make a rule that taints all PropDstArgs if any of PropSrcArgs is tainted.
+ static GenericTaintRule Prop(ArgSet &&SrcArgs, ArgSet &&DstArgs) {
+ return {{}, {}, std::move(SrcArgs), std::move(DstArgs)};
+ }
- TaintPropagationRule(ArgVector &&Src, ArgVector &&Dst,
- VariadicType Var = VariadicType::None,
- unsigned VarIndex = InvalidArgIndex,
- PropagationFuncType Func = nullptr)
- : SrcArgs(std::move(Src)), DstArgs(std::move(Dst)),
- VariadicIndex(VarIndex), VarType(Var), PropagationFunc(Func) {}
+ /// Make a rule that taints all PropDstArgs if any of PropSrcArgs is tainted.
+ static GenericTaintRule SinkProp(ArgSet &&SinkArgs, ArgSet &&SrcArgs,
+ ArgSet &&DstArgs,
+ Optional<StringRef> Msg = None) {
+ return {
+ std::move(SinkArgs), {}, std::move(SrcArgs), std::move(DstArgs), Msg};
+ }
- /// Get the propagation rule for a given function.
- static TaintPropagationRule
- getTaintPropagationRule(const NameRuleMap &CustomPropagations,
- const FunctionData &FData, CheckerContext &C);
+ /// Process a function which could either be a taint source, a taint sink, a
+ /// taint filter or a taint propagator.
+ void process(const GenericTaintChecker &Checker, const CallEvent &Call,
+ CheckerContext &C) const;
- void addSrcArg(unsigned A) { SrcArgs.push_back(A); }
- void addDstArg(unsigned A) { DstArgs.push_back(A); }
+ /// Handles the resolution of indexes of type ArgIdxTy to Expr*-s.
+ static const Expr *GetArgExpr(ArgIdxTy ArgIdx, const CallEvent &Call) {
+ return ArgIdx == ReturnValueIndex ? Call.getOriginExpr()
+ : Call.getArgExpr(ArgIdx);
+ };
- bool isNull() const {
- return SrcArgs.empty() && DstArgs.empty() &&
- VariadicType::None == VarType;
- }
+ /// Functions for custom taintedness propagation.
+ static bool UntrustedEnv(CheckerContext &C);
+};
- bool isDestinationArgument(unsigned ArgNum) const {
- return llvm::is_contained(DstArgs, ArgNum);
- }
+using RuleLookupTy = CallDescriptionMap<GenericTaintRule>;
- static bool isTaintedOrPointsToTainted(const Expr *E,
- const ProgramStateRef &State,
- CheckerContext &C) {
- if (isTainted(State, E, C.getLocationContext()) || isStdin(E, C))
- return true;
+/// Used to parse the configuration file.
+struct TaintConfiguration {
+ using NameScopeArgs = std::tuple<std::string, std::string, ArgVecTy>;
+ enum class VariadicType { None, Src, Dst };
- if (!E->getType().getTypePtr()->isPointerType())
- return false;
+ struct Common {
+ std::string Name;
+ std::string Scope;
+ };
- Optional<SVal> V = getPointeeOf(C, E);
- return (V && isTainted(State, *V));
- }
+ struct Sink : Common {
+ ArgVecTy SinkArgs;
+ };
- /// Pre-process a function which propagates taint according to the
- /// taint rule.
- ProgramStateRef process(const CallEvent &Call, CheckerContext &C) const;
+ struct Filter : Common {
+ ArgVecTy FilterArgs;
+ };
- // Functions for custom taintedness propagation.
- static bool postSocket(bool IsTainted, const CallEvent &Call,
- CheckerContext &C);
+ struct Propagation : Common {
+ ArgVecTy SrcArgs;
+ ArgVecTy DstArgs;
+ VariadicType VarType;
+ ArgIdxTy VarIndex;
};
- /// Defines a map between the propagation function's name, scope
- /// and TaintPropagationRule.
- NameRuleMap CustomPropagations;
+ std::vector<Propagation> Propagations;
+ std::vector<Filter> Filters;
+ std::vector<Sink> Sinks;
+
+ TaintConfiguration() = default;
+ TaintConfiguration(const TaintConfiguration &) = default;
+ TaintConfiguration(TaintConfiguration &&) = default;
+ TaintConfiguration &operator=(const TaintConfiguration &) = default;
+ TaintConfiguration &operator=(TaintConfiguration &&) = default;
+};
+
+struct GenericTaintRuleParser {
+ GenericTaintRuleParser(CheckerManager &Mgr) : Mgr(Mgr) {}
+ /// Container type used to gather call identification objects grouped into
+ /// pairs with their corresponding taint rules. It is temporary as it is used
+ /// to finally initialize RuleLookupTy, which is considered to be immutable.
+ using RulesContTy = std::vector<std::pair<CallDescription, GenericTaintRule>>;
+ RulesContTy parseConfiguration(const std::string &Option,
+ TaintConfiguration &&Config) const;
- /// Defines a map between the filter function's name, scope and filtering
- /// args.
- NameArgMap CustomFilters;
+private:
+ using NamePartsTy = llvm::SmallVector<SmallString<32>, 2>;
+
+ /// Validate part of the configuration, which contains a list of argument
+ /// indexes.
+ void validateArgVector(const std::string &Option, const ArgVecTy &Args) const;
+
+ template <typename Config> static NamePartsTy parseNameParts(const Config &C);
+
+ // Takes the config and creates a CallDescription for it and associates a Rule
+ // with that.
+ template <typename Config>
+ static void consumeRulesFromConfig(const Config &C, GenericTaintRule &&Rule,
+ RulesContTy &Rules);
+
+ void parseConfig(const std::string &Option, TaintConfiguration::Sink &&P,
+ RulesContTy &Rules) const;
+ void parseConfig(const std::string &Option, TaintConfiguration::Filter &&P,
+ RulesContTy &Rules) const;
+ void parseConfig(const std::string &Option,
+ TaintConfiguration::Propagation &&P,
+ RulesContTy &Rules) const;
- /// Defines a map between the sink function's name, scope and sinking args.
- NameArgMap CustomSinks;
+ CheckerManager &Mgr;
};
-const unsigned GenericTaintChecker::ReturnValueIndex;
-const unsigned GenericTaintChecker::InvalidArgIndex;
+class GenericTaintChecker : public Checker<check::PreCall, check::PostCall> {
+public:
+ static void *getTag() {
+ static int Tag;
+ return &Tag;
+ }
-// FIXME: these lines can be removed in C++17
-constexpr llvm::StringLiteral GenericTaintChecker::MsgUncontrolledFormatString;
-constexpr llvm::StringLiteral GenericTaintChecker::MsgSanitizeSystemArgs;
-constexpr llvm::StringLiteral GenericTaintChecker::MsgTaintedBufferSize;
-constexpr llvm::StringLiteral GenericTaintChecker::MsgCustomSink;
-} // end of anonymous namespace
+ void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+ void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
-using TaintConfig = GenericTaintChecker::TaintConfiguration;
+ void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
+ const char *Sep) const override;
-LLVM_YAML_IS_SEQUENCE_VECTOR(TaintConfig::Propagation)
-LLVM_YAML_IS_SEQUENCE_VECTOR(TaintConfig::NameScopeArgs)
+ /// Generate a report if the expression is tainted or points to tainted data.
+ bool generateReportIfTainted(const Expr *E, StringRef Msg,
+ CheckerContext &C) const;
+
+private:
+ const BugType BT{this, "Use of Untrusted Data", "Untrusted Data"};
+
+ bool checkUncontrolledFormatString(const CallEvent &Call,
+ CheckerContext &C) const;
+
+ void taintUnsafeSocketProtocol(const CallEvent &Call,
+ CheckerContext &C) const;
+
+ /// Default taint rules are initilized with the help of a CheckerContext to
+ /// access the names of built-in functions like memcpy.
+ void initTaintRules(CheckerContext &C) const;
+
+ /// CallDescription currently cannot restrict matches to the global namespace
+ /// only, which is why multiple CallDescriptionMaps are used, as we want to
+ /// disambiguate global C functions from functions inside user-defined
+ /// namespaces.
+ // TODO: Remove separation to simplify matching logic once CallDescriptions
+ // are more expressive.
+
+ mutable Optional<RuleLookupTy> StaticTaintRules;
+ mutable Optional<RuleLookupTy> DynamicTaintRules;
+};
+} // end of anonymous namespace
+
+/// YAML serialization mapping.
+LLVM_YAML_IS_SEQUENCE_VECTOR(TaintConfiguration::Sink)
+LLVM_YAML_IS_SEQUENCE_VECTOR(TaintConfiguration::Filter)
+LLVM_YAML_IS_SEQUENCE_VECTOR(TaintConfiguration::Propagation)
namespace llvm {
namespace yaml {
-template <> struct MappingTraits<TaintConfig> {
- static void mapping(IO &IO, TaintConfig &Config) {
+template <> struct MappingTraits<TaintConfiguration> {
+ static void mapping(IO &IO, TaintConfiguration &Config) {
IO.mapOptional("Propagations", Config.Propagations);
IO.mapOptional("Filters", Config.Filters);
IO.mapOptional("Sinks", Config.Sinks);
}
};
-template <> struct MappingTraits<TaintConfig::Propagation> {
- static void mapping(IO &IO, TaintConfig::Propagation &Propagation) {
+template <> struct MappingTraits<TaintConfiguration::Sink> {
+ static void mapping(IO &IO, TaintConfiguration::Sink &Sink) {
+ IO.mapRequired("Name", Sink.Name);
+ IO.mapOptional("Scope", Sink.Scope);
+ IO.mapRequired("Args", Sink.SinkArgs);
+ }
+};
+
+template <> struct MappingTraits<TaintConfiguration::Filter> {
+ static void mapping(IO &IO, TaintConfiguration::Filter &Filter) {
+ IO.mapRequired("Name", Filter.Name);
+ IO.mapOptional("Scope", Filter.Scope);
+ IO.mapRequired("Args", Filter.FilterArgs);
+ }
+};
+
+template <> struct MappingTraits<TaintConfiguration::Propagation> {
+ static void mapping(IO &IO, TaintConfiguration::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,
- GenericTaintChecker::VariadicType::None);
- IO.mapOptional("VariadicIndex", Propagation.VarIndex,
- GenericTaintChecker::InvalidArgIndex);
+ IO.mapOptional("VariadicType", Propagation.VarType);
+ IO.mapOptional("VariadicIndex", Propagation.VarIndex);
}
};
-template <> struct ScalarEnumerationTraits<GenericTaintChecker::VariadicType> {
- static void enumeration(IO &IO, GenericTaintChecker::VariadicType &Value) {
- IO.enumCase(Value, "None", GenericTaintChecker::VariadicType::None);
- IO.enumCase(Value, "Src", GenericTaintChecker::VariadicType::Src);
- IO.enumCase(Value, "Dst", GenericTaintChecker::VariadicType::Dst);
- }
-};
-
-template <> struct MappingTraits<TaintConfig::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));
+template <> struct ScalarEnumerationTraits<TaintConfiguration::VariadicType> {
+ static void enumeration(IO &IO, TaintConfiguration::VariadicType &Value) {
+ IO.enumCase(Value, "None", TaintConfiguration::VariadicType::None);
+ IO.enumCase(Value, "Src", TaintConfiguration::VariadicType::Src);
+ IO.enumCase(Value, "Dst", TaintConfiguration::VariadicType::Dst);
}
};
} // namespace yaml
} // namespace llvm
/// A set which is used to pass information from call pre-visit instruction
-/// to the call post-visit. The values are unsigned integers, which are either
+/// to the call post-visit. The values are signed integers, which are either
/// ReturnValueIndex, or indexes of the pointer/reference argument, which
/// points to data, which should be tainted on return.
-REGISTER_SET_WITH_PROGRAMSTATE(TaintArgsOnPostVisit, unsigned)
+REGISTER_SET_WITH_PROGRAMSTATE(TaintArgsOnPostVisit, ArgIdxTy)
-GenericTaintChecker::ArgVector
-GenericTaintChecker::convertToArgVector(CheckerManager &Mgr,
- const std::string &Option,
- const SignedArgVector &Args) {
- ArgVector Result;
- for (int Arg : Args) {
- if (Arg == -1)
- Result.push_back(ReturnValueIndex);
- else if (Arg < -1) {
- Result.push_back(InvalidArgIndex);
+void GenericTaintRuleParser::validateArgVector(const std::string &Option,
+ const ArgVecTy &Args) const {
+ for (ArgIdxTy Arg : Args) {
+ if (Arg < ReturnValueIndex) {
Mgr.reportInvalidCheckerOptionValue(
- this, Option,
+ Mgr.getChecker<GenericTaintChecker>(), Option,
"an argument number for propagation rules greater or equal to -1");
- } else
- Result.push_back(static_cast<unsigned>(Arg));
+ }
}
- return Result;
}
-void GenericTaintChecker::parseConfiguration(CheckerManager &Mgr,
- const std::string &Option,
- TaintConfiguration &&Config) {
- for (auto &P : Config.Propagations) {
- GenericTaintChecker::CustomPropagations.emplace(
- P.Name,
- std::make_pair(P.Scope, TaintPropagationRule{
- std::move(P.SrcArgs),
- convertToArgVector(Mgr, Option, P.DstArgs),
- P.VarType, P.VarIndex}));
+template <typename Config>
+GenericTaintRuleParser::NamePartsTy
+GenericTaintRuleParser::parseNameParts(const Config &C) {
+ NamePartsTy NameParts;
+ if (!C.Scope.empty()) {
+ // If the Scope argument contains multiple "::" parts, those are considered
+ // namespace identifiers.
+ llvm::SmallVector<StringRef, 2> NSParts;
+ StringRef{C.Scope}.split(NSParts, "::", /*MaxSplit*/ -1,
+ /*KeepEmpty*/ false);
+ NameParts.append(NSParts.begin(), NSParts.end());
}
+ NameParts.emplace_back(C.Name);
+ return NameParts;
+}
- for (auto &F : Config.Filters) {
- GenericTaintChecker::CustomFilters.emplace(
- std::get<0>(F),
- std::make_pair(std::move(std::get<1>(F)), std::move(std::get<2>(F))));
- }
+template <typename Config>
+void GenericTaintRuleParser::consumeRulesFromConfig(const Config &C,
+ GenericTaintRule &&Rule,
+ RulesContTy &Rules) {
+ NamePartsTy NameParts = parseNameParts(C);
+ llvm::SmallVector<const char *, 2> CallDescParts{NameParts.size()};
+ llvm::transform(NameParts, CallDescParts.begin(),
+ [](SmallString<32> &S) { return S.c_str(); });
+ Rules.emplace_back(CallDescription(CallDescParts), std::move(Rule));
+}
- for (auto &S : Config.Sinks) {
- GenericTaintChecker::CustomSinks.emplace(
- std::get<0>(S),
- std::make_pair(std::move(std::get<1>(S)), std::move(std::get<2>(S))));
- }
+void GenericTaintRuleParser::parseConfig(const std::string &Option,
+ TaintConfiguration::Sink &&S,
+ RulesContTy &Rules) const {
+ validateArgVector(Option, S.SinkArgs);
+ consumeRulesFromConfig(S, GenericTaintRule::Sink(std::move(S.SinkArgs)),
+ Rules);
}
-template <typename T>
-auto GenericTaintChecker::findFunctionInConfig(const ConfigDataMap<T> &Map,
- const FunctionData &FData) {
- auto Range = Map.equal_range(std::string(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();
+void GenericTaintRuleParser::parseConfig(const std::string &Option,
+ TaintConfiguration::Filter &&S,
+ RulesContTy &Rules) const {
+ validateArgVector(Option, S.FilterArgs);
+ consumeRulesFromConfig(S, GenericTaintRule::Filter(std::move(S.FilterArgs)),
+ Rules);
}
-GenericTaintChecker::TaintPropagationRule
-GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
- 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.
+void GenericTaintRuleParser::parseConfig(const std::string &Option,
+ TaintConfiguration::Propagation &&P,
+ RulesContTy &Rules) const {
+ validateArgVector(Option, P.SrcArgs);
+ validateArgVector(Option, P.DstArgs);
+ bool IsSrcVariadic = P.VarType == TaintConfiguration::VariadicType::Src;
+ bool IsDstVariadic = P.VarType == TaintConfiguration::VariadicType::Dst;
+ Optional<ArgIdxTy> JustVarIndex = P.VarIndex;
+
+ ArgSet SrcDesc(std::move(P.SrcArgs), IsSrcVariadic ? JustVarIndex : None);
+ ArgSet DstDesc(std::move(P.DstArgs), IsDstVariadic ? JustVarIndex : None);
+
+ consumeRulesFromConfig(
+ P, GenericTaintRule::Prop(std::move(SrcDesc), std::move(DstDesc)), Rules);
+}
+
+GenericTaintRuleParser::RulesContTy
+GenericTaintRuleParser::parseConfiguration(const std::string &Option,
+ TaintConfiguration &&Config) const {
+
+ RulesContTy Rules;
+
+ for (auto &F : Config.Filters)
+ parseConfig(Option, std::move(F), Rules);
+
+ for (auto &S : Config.Sinks)
+ parseConfig(Option, std::move(S), Rules);
+
+ for (auto &P : Config.Propagations)
+ parseConfig(Option, std::move(P), Rules);
+
+ return Rules;
+}
+void GenericTaintChecker::initTaintRules(CheckerContext &C) const {
// 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>(FData.FullName)
- // Source functions
- // TODO: Add support for vfscanf & family.
- .Case("fdopen", {{}, {ReturnValueIndex}})
- .Case("fopen", {{}, {ReturnValueIndex}})
- .Case("freopen", {{}, {ReturnValueIndex}})
- .Case("getch", {{}, {ReturnValueIndex}})
- .Case("getchar", {{}, {ReturnValueIndex}})
- .Case("getchar_unlocked", {{}, {ReturnValueIndex}})
- .Case("gets", {{}, {0, ReturnValueIndex}})
- .Case("scanf", {{}, {}, VariadicType::Dst, 1})
- .Case("socket", {{},
- {ReturnValueIndex},
- VariadicType::None,
- InvalidArgIndex,
- &TaintPropagationRule::postSocket})
- .Case("wgetch", {{}, {ReturnValueIndex}})
- // Propagating functions
- .Case("atoi", {{0}, {ReturnValueIndex}})
- .Case("atol", {{0}, {ReturnValueIndex}})
- .Case("atoll", {{0}, {ReturnValueIndex}})
- .Case("fgetc", {{0}, {ReturnValueIndex}})
- .Case("fgetln", {{0}, {ReturnValueIndex}})
- .Case("fgets", {{2}, {0, ReturnValueIndex}})
- .Case("fscanf", {{0}, {}, VariadicType::Dst, 2})
- .Case("sscanf", {{0}, {}, VariadicType::Dst, 2})
- .Case("getc", {{0}, {ReturnValueIndex}})
- .Case("getc_unlocked", {{0}, {ReturnValueIndex}})
- .Case("getdelim", {{3}, {0}})
- .Case("getline", {{2}, {0}})
- .Case("getw", {{0}, {ReturnValueIndex}})
- .Case("pread", {{0, 1, 2, 3}, {1, ReturnValueIndex}})
- .Case("read", {{0, 2}, {1, ReturnValueIndex}})
- .Case("strchr", {{0}, {ReturnValueIndex}})
- .Case("strrchr", {{0}, {ReturnValueIndex}})
- .Case("tolower", {{0}, {ReturnValueIndex}})
- .Case("toupper", {{0}, {ReturnValueIndex}})
- .Default({});
- if (!Rule.isNull())
- return Rule;
+ if (StaticTaintRules || DynamicTaintRules)
+ return;
- // `getenv` returns taint only in untrusted environments.
- if (FData.FullName == "getenv") {
- if (C.getAnalysisManager()
- .getAnalyzerOptions()
- .ShouldAssumeControlledEnvironment)
- return {};
- return {{}, {ReturnValueIndex}};
- }
+ using RulesConstructionTy =
+ std::vector<std::pair<CallDescription, GenericTaintRule>>;
+ using TR = GenericTaintRule;
- assert(FData.FDecl);
+ const Builtin::Context &BI = C.getASTContext().BuiltinInfo;
- // 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) {
- case Builtin::BImemcpy:
- case Builtin::BImemmove:
- case Builtin::BIstrncpy:
- case Builtin::BIstrncat:
- return {{1, 2}, {0, ReturnValueIndex}};
- case Builtin::BIstrlcpy:
- case Builtin::BIstrlcat:
- return {{1, 2}, {0}};
- case Builtin::BIstrndup:
- return {{0, 1}, {ReturnValueIndex}};
+ RulesConstructionTy GlobalCRules{
+ // Sources
+ {{"fdopen"}, TR::Source({{ReturnValueIndex}})},
+ {{"fopen"}, TR::Source({{ReturnValueIndex}})},
+ {{"freopen"}, TR::Source({{ReturnValueIndex}})},
+ {{"getch"}, TR::Source({{ReturnValueIndex}})},
+ {{"getchar"}, TR::Source({{ReturnValueIndex}})},
+ {{"getchar_unlocked"}, TR::Source({{ReturnValueIndex}})},
+ {{"gets"}, TR::Source({{0}, ReturnValueIndex})},
+ {{"scanf"}, TR::Source({{}, 1})},
+ {{"wgetch"}, TR::Source({{}, ReturnValueIndex})},
- default:
- break;
- }
+ // Props
+ {{"atoi"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{"atol"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{"atoll"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{"fgetc"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{"fgetln"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{"fgets"}, TR::Prop({{2}}, {{0}, ReturnValueIndex})},
+ {{"fscanf"}, TR::Prop({{0}}, {{}, 2})},
+ {{"sscanf"}, TR::Prop({{0}}, {{}, 2})},
+ {{"getc"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{"getc_unlocked"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{"getdelim"}, TR::Prop({{3}}, {{0}})},
+ {{"getline"}, TR::Prop({{2}}, {{0}})},
+ {{"getw"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{"pread"}, TR::Prop({{0, 1, 2, 3}}, {{1, ReturnValueIndex}})},
+ {{"read"}, TR::Prop({{0, 2}}, {{1, ReturnValueIndex}})},
+ {{"strchr"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{"strrchr"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{"tolower"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{"toupper"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrncat)}},
+ TR::Prop({{1, 2}}, {{0, ReturnValueIndex}})},
+ {{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrlcpy)}},
+ TR::Prop({{1, 2}}, {{0}})},
+ {{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrlcat)}},
+ TR::Prop({{1, 2}}, {{0}})},
+ {{CDF_MaybeBuiltin, {"snprintf"}},
+ TR::Prop({{1}, 3}, {{0, ReturnValueIndex}})},
+ {{CDF_MaybeBuiltin, {"sprintf"}},
+ TR::Prop({{1}, 2}, {{0, ReturnValueIndex}})},
+ {{CDF_MaybeBuiltin, {"strcpy"}},
+ TR::Prop({{1}}, {{0, ReturnValueIndex}})},
+ {{CDF_MaybeBuiltin, {"stpcpy"}},
+ TR::Prop({{1}}, {{0, ReturnValueIndex}})},
+ {{CDF_MaybeBuiltin, {"strcat"}},
+ TR::Prop({{1}}, {{0, ReturnValueIndex}})},
+ {{CDF_MaybeBuiltin, {"strdup"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{CDF_MaybeBuiltin, {"strdupa"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{CDF_MaybeBuiltin, {"wcsdup"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+
+ // Sinks
+ {{"system"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{"popen"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{"execl"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{"execle"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{"execlp"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{"execvp"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{"execvP"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{"execve"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{"dlopen"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{CDF_MaybeBuiltin, {"malloc"}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
+ {{CDF_MaybeBuiltin, {"calloc"}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
+ {{CDF_MaybeBuiltin, {"alloca"}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
+ {{CDF_MaybeBuiltin, {"memccpy"}}, TR::Sink({{3}}, MsgTaintedBufferSize)},
+ {{CDF_MaybeBuiltin, {"realloc"}}, TR::Sink({{1}}, MsgTaintedBufferSize)},
+ {{{"setproctitle"}}, TR::Sink({{0}, 1}, MsgUncontrolledFormatString)},
+ {{{"setproctitle_fast"}},
+ TR::Sink({{0}, 1}, MsgUncontrolledFormatString)},
+
+ // SinkProps
+ {{CDF_MaybeBuiltin, BI.getName(Builtin::BImemcpy)},
+ TR::SinkProp({{2}}, {{1, 2}}, {{0, ReturnValueIndex}},
+ MsgTaintedBufferSize)},
+ {{CDF_MaybeBuiltin, {BI.getName(Builtin::BImemmove)}},
+ TR::SinkProp({{2}}, {{1, 2}}, {{0, ReturnValueIndex}},
+ MsgTaintedBufferSize)},
+ {{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrncpy)}},
+ TR::SinkProp({{2}}, {{1, 2}}, {{0, ReturnValueIndex}},
+ MsgTaintedBufferSize)},
+ {{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrndup)}},
+ TR::SinkProp({{1}}, {{0, 1}}, {{ReturnValueIndex}},
+ MsgTaintedBufferSize)},
+ {{CDF_MaybeBuiltin, {"bcopy"}},
+ TR::SinkProp({{2}}, {{0, 2}}, {{1}}, MsgTaintedBufferSize)}};
+
+ // `getenv` returns taint only in untrusted environments.
+ if (TR::UntrustedEnv(C)) {
+ // void setproctitle_init(int argc, char *argv[], char *envp[])
+ GlobalCRules.push_back(
+ {{{"setproctitle_init"}}, TR::Sink({{2}}, MsgCustomSink)});
+ GlobalCRules.push_back({{"getenv"}, TR::Source({{ReturnValueIndex}})});
}
- // Process all other functions which could be defined as builtins.
- if (Rule.isNull()) {
- const auto OneOf = [FDecl](const auto &... Name) {
- // FIXME: use fold expression in C++17
- using unused = int[];
- bool ret = false;
- static_cast<void>(unused{
- 0, (ret |= CheckerContext::isCLibraryFunction(FDecl, Name), 0)...});
- return ret;
- };
- if (OneOf("snprintf"))
- return {{1}, {0, ReturnValueIndex}, VariadicType::Src, 3};
- if (OneOf("sprintf"))
- return {{1}, {0, ReturnValueIndex}, VariadicType::Src, 2};
- if (OneOf("strcpy", "stpcpy", "strcat"))
- return {{1}, {0, ReturnValueIndex}};
- if (OneOf("bcopy"))
- return {{0, 2}, {1}};
- if (OneOf("strdup", "strdupa", "wcsdup"))
- return {{0}, {ReturnValueIndex}};
+ StaticTaintRules.emplace(std::make_move_iterator(GlobalCRules.begin()),
+ std::make_move_iterator(GlobalCRules.end()));
+
+ // User-provided taint configuration.
+ CheckerManager *Mgr = C.getAnalysisManager().getCheckerManager();
+ assert(Mgr);
+ GenericTaintRuleParser ConfigParser{*Mgr};
+ std::string Option{"Config"};
+ StringRef ConfigFile =
+ Mgr->getAnalyzerOptions().getCheckerStringOption(this, Option);
+ llvm::Optional<TaintConfiguration> Config =
+ getConfiguration<TaintConfiguration>(*Mgr, this, Option, ConfigFile);
+ if (!Config) {
+ // We don't have external taint config, no parsing required.
+ DynamicTaintRules = RuleLookupTy{};
+ return;
}
- // Skipping the following functions, since they might be used for cleansing or
- // smart memory copy:
- // - memccpy - copying until hitting a special character.
+ GenericTaintRuleParser::RulesContTy Rules{
+ ConfigParser.parseConfiguration(Option, std::move(Config.getValue()))};
- auto It = findFunctionInConfig(CustomPropagations, FData);
- if (It != CustomPropagations.end())
- return It->second.second;
- return {};
+ DynamicTaintRules.emplace(std::make_move_iterator(Rules.begin()),
+ std::make_move_iterator(Rules.end()));
}
void GenericTaintChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
- Optional<FunctionData> FData = FunctionData::create(Call, C);
- if (!FData)
- return;
+ initTaintRules(C);
- // Check for taintedness related errors first: system call, uncontrolled
- // format string, tainted buffer size.
- if (checkPre(Call, *FData, C))
- return;
+ // FIXME: this should be much simpler.
+ if (const auto *Rule =
+ Call.isGlobalCFunction() ? StaticTaintRules->lookup(Call) : nullptr)
+ Rule->process(*this, Call, C);
+ else if (const auto *Rule = DynamicTaintRules->lookup(Call))
+ Rule->process(*this, Call, C);
- // Marks the function's arguments and/or return value tainted if it present in
- // the list.
- if (addSourcesPre(Call, *FData, C))
- return;
+ // FIXME: These edge cases are to be eliminated from here eventually.
+ //
+ // Additional check that is not supported by CallDescription.
+ // TODO: Make CallDescription be able to match attributes such as printf-like
+ // arguments.
+ checkUncontrolledFormatString(Call, C);
- addFiltersPre(Call, *FData, C);
+ // TODO: Modeling sockets should be done in a specific checker.
+ // Socket is a source, which taints the return value.
+ taintUnsafeSocketProtocol(Call, C);
}
void GenericTaintChecker::checkPostCall(const CallEvent &Call,
CheckerContext &C) const {
// Set the marked values as tainted. The return value only accessible from
// checkPostStmt.
- propagateFromPre(Call, C);
-}
-
-void GenericTaintChecker::printState(raw_ostream &Out, ProgramStateRef State,
- const char *NL, const char *Sep) const {
- printTaint(State, Out, NL, Sep);
-}
-
-bool GenericTaintChecker::addSourcesPre(const CallEvent &Call,
- const FunctionData &FData,
- CheckerContext &C) const {
- // First, try generating a propagation rule for this function.
- TaintPropagationRule Rule = TaintPropagationRule::getTaintPropagationRule(
- this->CustomPropagations, FData, C);
- if (!Rule.isNull()) {
- ProgramStateRef State = Rule.process(Call, C);
- if (State) {
- C.addTransition(State);
- return true;
- }
- }
- return false;
-}
-
-bool GenericTaintChecker::addFiltersPre(const CallEvent &Call,
- 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 >= Call.getNumArgs())
- continue;
-
- const Expr *Arg = Call.getArgExpr(ArgNum);
- Optional<SVal> V = getPointeeOf(C, Arg);
- if (V)
- State = removeTaint(State, *V);
- }
-
- if (State != C.getState()) {
- C.addTransition(State);
- return true;
- }
- return false;
-}
-
-bool GenericTaintChecker::propagateFromPre(const CallEvent &Call,
- CheckerContext &C) {
ProgramStateRef State = C.getState();
// Depending on what was tainted at pre-visit, we determined a set of
@@ -616,9 +689,9 @@ bool GenericTaintChecker::propagateFromPre(const CallEvent &Call,
// stored in the state as TaintArgsOnPostVisit set.
TaintArgsOnPostVisitTy TaintArgs = State->get<TaintArgsOnPostVisit>();
if (TaintArgs.isEmpty())
- return false;
+ return;
- for (unsigned ArgNum : TaintArgs) {
+ for (ArgIdxTy ArgNum : TaintArgs) {
// Special handling for the tainted return value.
if (ArgNum == ReturnValueIndex) {
State = addTaint(State, Call.getReturnValue());
@@ -627,234 +700,147 @@ bool GenericTaintChecker::propagateFromPre(const CallEvent &Call,
// The arguments are pointer arguments. The data they are pointing at is
// tainted after the call.
- if (Call.getNumArgs() < (ArgNum + 1))
- return false;
- const Expr *Arg = Call.getArgExpr(ArgNum);
- Optional<SVal> V = getPointeeOf(C, Arg);
- if (V)
+ if (auto V = getPointeeOf(C, Call.getArgSVal(ArgNum)))
State = addTaint(State, *V);
}
// Clear up the taint info from the state.
State = State->remove<TaintArgsOnPostVisit>();
-
- if (State != C.getState()) {
- C.addTransition(State);
- return true;
- }
- return false;
+ C.addTransition(State);
}
-bool GenericTaintChecker::checkPre(const CallEvent &Call,
- const FunctionData &FData,
- CheckerContext &C) const {
- if (checkUncontrolledFormatString(Call, C))
- return true;
-
- if (checkSystemCall(Call, FData.Name, C))
- return true;
-
- if (checkTaintedBufferSize(Call, C))
- return true;
-
- return checkCustomSinks(Call, FData, C);
-}
-
-Optional<SVal> GenericTaintChecker::getPointeeOf(CheckerContext &C,
- const Expr *Arg) {
- ProgramStateRef State = C.getState();
- SVal AddrVal = C.getSVal(Arg->IgnoreParens());
- if (AddrVal.isUnknownOrUndef())
- return None;
-
- Optional<Loc> AddrLoc = AddrVal.getAs<Loc>();
- if (!AddrLoc)
- return None;
-
- QualType ArgTy = Arg->getType().getCanonicalType();
- if (!ArgTy->isPointerType())
- return State->getSVal(*AddrLoc);
-
- QualType ValTy = ArgTy->getPointeeType();
-
- // Do not dereference void pointers. Treat them as byte pointers instead.
- // FIXME: we might want to consider more than just the first byte.
- if (ValTy->isVoidType())
- ValTy = C.getASTContext().CharTy;
-
- return State->getSVal(*AddrLoc, ValTy);
+void GenericTaintChecker::printState(raw_ostream &Out, ProgramStateRef State,
+ const char *NL, const char *Sep) const {
+ printTaint(State, Out, NL, Sep);
}
-ProgramStateRef
-GenericTaintChecker::TaintPropagationRule::process(const CallEvent &Call,
- CheckerContext &C) const {
+void GenericTaintRule::process(const GenericTaintChecker &Checker,
+ const CallEvent &Call, CheckerContext &C) const {
ProgramStateRef State = C.getState();
+ const ArgIdxTy CallNumArgs = fromArgumentCount(Call.getNumArgs());
- // Check for taint in arguments.
- bool IsTainted = true;
- for (unsigned ArgNum : SrcArgs) {
- if (ArgNum >= Call.getNumArgs())
- continue;
+ /// Iterate every call argument, and get their corresponding Expr and SVal.
+ const auto ForEachCallArg = [&C, &Call, CallNumArgs](auto &&Fun) {
+ for (ArgIdxTy I = ReturnValueIndex; I < CallNumArgs; ++I) {
+ const Expr *E = GetArgExpr(I, Call);
+ Fun(I, E, C.getSVal(E));
+ }
+ };
- if ((IsTainted =
- isTaintedOrPointsToTainted(Call.getArgExpr(ArgNum), State, C)))
- break;
- }
+ /// Check for taint sinks.
+ ForEachCallArg([this, &Checker, &C, &State](ArgIdxTy I, const Expr *E, SVal) {
+ if (SinkArgs.contains(I) && isTaintedOrPointsToTainted(E, State, C))
+ Checker.generateReportIfTainted(E, SinkMsg.getValueOr(MsgCustomSink), C);
+ });
- // Check for taint in variadic arguments.
- if (!IsTainted && VariadicType::Src == VarType) {
- // Check if any of the arguments is tainted
- for (unsigned i = VariadicIndex; i < Call.getNumArgs(); ++i) {
- if ((IsTainted =
- isTaintedOrPointsToTainted(Call.getArgExpr(i), State, C)))
- break;
+ /// Check for taint filters.
+ ForEachCallArg([this, &C, &State](ArgIdxTy I, const Expr *E, SVal S) {
+ if (FilterArgs.contains(I)) {
+ State = removeTaint(State, S);
+ if (auto P = getPointeeOf(C, S))
+ State = removeTaint(State, *P);
}
- }
+ });
- if (PropagationFunc)
- IsTainted = PropagationFunc(IsTainted, Call, C);
+ /// Check for taint propagation sources.
+ /// A rule is relevant if PropSrcArgs is empty, or if any of its signified
+ /// args are tainted in context of the current CallEvent.
+ bool IsMatching = PropSrcArgs.isEmpty();
+ ForEachCallArg(
+ [this, &C, &IsMatching, &State](ArgIdxTy I, const Expr *E, SVal) {
+ IsMatching = IsMatching || (PropSrcArgs.contains(I) &&
+ isTaintedOrPointsToTainted(E, State, C));
+ });
- if (!IsTainted)
- return State;
+ if (!IsMatching)
+ return;
- // Mark the arguments which should be tainted after the function returns.
- for (unsigned ArgNum : DstArgs) {
- // Should mark the return value?
- if (ArgNum == ReturnValueIndex) {
- State = State->add<TaintArgsOnPostVisit>(ReturnValueIndex);
- continue;
- }
+ const auto WouldEscape = [](SVal V, QualType Ty) -> bool {
+ if (!V.getAs<Loc>())
+ return false;
- if (ArgNum >= Call.getNumArgs())
- continue;
+ const bool IsNonConstRef = Ty->isReferenceType() && !Ty.isConstQualified();
+ const bool IsNonConstPtr =
+ Ty->isPointerType() && !Ty->getPointeeType().isConstQualified();
- // Mark the given argument.
- State = State->add<TaintArgsOnPostVisit>(ArgNum);
- }
+ return IsNonConstRef || IsNonConstPtr;
+ };
- // Mark all variadic arguments tainted if present.
- if (VariadicType::Dst == VarType) {
- // For all pointer and references that were passed in:
- // If they are not pointing to const data, mark data as tainted.
- // TODO: So far we are just going one level down; ideally we'd need to
- // recurse here.
- for (unsigned i = VariadicIndex; i < Call.getNumArgs(); ++i) {
- const Expr *Arg = Call.getArgExpr(i);
- // Process pointer argument.
- const Type *ArgTy = Arg->getType().getTypePtr();
- QualType PType = ArgTy->getPointeeType();
- if ((!PType.isNull() && !PType.isConstQualified()) ||
- (ArgTy->isReferenceType() && !Arg->getType().isConstQualified())) {
- State = State->add<TaintArgsOnPostVisit>(i);
- }
- }
- }
+ /// Propagate taint where it is necessary.
+ ForEachCallArg(
+ [this, &State, WouldEscape](ArgIdxTy I, const Expr *E, SVal V) {
+ if (PropDstArgs.contains(I))
+ State = State->add<TaintArgsOnPostVisit>(I);
- return State;
-}
+ // TODO: We should traverse all reachable memory regions via the
+ // escaping parameter. Instead of doing that we simply mark only the
+ // referred memory region as tainted.
+ if (WouldEscape(V, E->getType()))
+ State = State->add<TaintArgsOnPostVisit>(I);
+ });
-// If argument 0(protocol domain) is network, the return value should get taint.
-bool GenericTaintChecker::TaintPropagationRule::postSocket(
- bool /*IsTainted*/, const CallEvent &Call, CheckerContext &C) {
- SourceLocation DomLoc = Call.getArgExpr(0)->getExprLoc();
- StringRef DomName = C.getMacroNameOrSpelling(DomLoc);
- // White list the internal communication protocols.
- if (DomName.equals("AF_SYSTEM") || DomName.equals("AF_LOCAL") ||
- DomName.equals("AF_UNIX") || DomName.equals("AF_RESERVED_36"))
- return false;
- return true;
+ C.addTransition(State);
}
-bool GenericTaintChecker::isStdin(const Expr *E, CheckerContext &C) {
- ProgramStateRef State = C.getState();
- SVal Val = C.getSVal(E);
+bool GenericTaintRule::UntrustedEnv(CheckerContext &C) {
+ return !C.getAnalysisManager()
+ .getAnalyzerOptions()
+ .ShouldAssumeControlledEnvironment;
+}
- // stdin is a pointer, so it would be a region.
- const MemRegion *MemReg = Val.getAsRegion();
+bool GenericTaintChecker::generateReportIfTainted(const Expr *E, StringRef Msg,
+ CheckerContext &C) const {
+ assert(E);
+ Optional<SVal> TaintedSVal{getTaintedPointeeOrPointer(C, C.getSVal(E))};
- // The region should be symbolic, we do not know it's value.
- const auto *SymReg = dyn_cast_or_null<SymbolicRegion>(MemReg);
- if (!SymReg)
+ if (!TaintedSVal)
return false;
- // Get it's symbol and find the declaration region it's pointing to.
- const auto *Sm = dyn_cast<SymbolRegionValue>(SymReg->getSymbol());
- if (!Sm)
- return false;
- const auto *DeclReg = dyn_cast_or_null<DeclRegion>(Sm->getRegion());
- if (!DeclReg)
- return false;
-
- // This region corresponds to a declaration, find out if it's a global/extern
- // variable named stdin with the proper type.
- if (const auto *D = dyn_cast_or_null<VarDecl>(DeclReg->getDecl())) {
- D = D->getCanonicalDecl();
- if (D->getName().contains("stdin") && D->isExternC()) {
- const auto *PtrTy = dyn_cast<PointerType>(D->getType().getTypePtr());
- if (PtrTy && PtrTy->getPointeeType().getCanonicalType() ==
- C.getASTContext().getFILEType().getCanonicalType())
- return true;
- }
+ // Generate diagnostic.
+ if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
+ auto report = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
+ report->addRange(E->getSourceRange());
+ report->addVisitor(std::make_unique<TaintBugVisitor>(*TaintedSVal));
+ C.emitReport(std::move(report));
+ return true;
}
return false;
}
+/// TODO: remove checking for printf format attributes and socket whitelisting
+/// from GenericTaintChecker, and that means the following functions:
+/// getPrintfFormatArgumentNum,
+/// GenericTaintChecker::checkUncontrolledFormatString,
+/// GenericTaintChecker::taintUnsafeSocketProtocol
+
static bool getPrintfFormatArgumentNum(const CallEvent &Call,
const CheckerContext &C,
- unsigned &ArgNum) {
+ ArgIdxTy &ArgNum) {
// Find if the function contains a format string argument.
// Handles: fprintf, printf, sprintf, snprintf, vfprintf, vprintf, vsprintf,
// vsnprintf, syslog, custom annotated functions.
- const FunctionDecl *FDecl = Call.getDecl()->getAsFunction();
+ const Decl *CallDecl = Call.getDecl();
+ if (!CallDecl)
+ return false;
+ const FunctionDecl *FDecl = CallDecl->getAsFunction();
if (!FDecl)
return false;
+
+ const ArgIdxTy CallNumArgs = fromArgumentCount(Call.getNumArgs());
+
for (const auto *Format : FDecl->specific_attrs<FormatAttr>()) {
ArgNum = Format->getFormatIdx() - 1;
- if ((Format->getType()->getName() == "printf") &&
- Call.getNumArgs() > ArgNum)
+ if ((Format->getType()->getName() == "printf") && CallNumArgs > ArgNum)
return true;
}
- // Or if a function is named setproctitle (this is a heuristic).
- if (C.getCalleeName(FDecl).contains("setproctitle")) {
- ArgNum = 0;
- return true;
- }
-
- return false;
-}
-
-bool GenericTaintChecker::generateReportIfTainted(const Expr *E, StringRef Msg,
- CheckerContext &C) const {
- assert(E);
-
- // Check for taint.
- ProgramStateRef State = C.getState();
- Optional<SVal> PointedToSVal = getPointeeOf(C, E);
- SVal TaintedSVal;
- if (PointedToSVal && isTainted(State, *PointedToSVal))
- TaintedSVal = *PointedToSVal;
- else if (isTainted(State, E, C.getLocationContext()))
- TaintedSVal = C.getSVal(E);
- else
- return false;
-
- // Generate diagnostic.
- if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
- initBugType();
- auto report = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
- report->addRange(E->getSourceRange());
- report->addVisitor(std::make_unique<TaintBugVisitor>(TaintedSVal));
- C.emitReport(std::move(report));
- return true;
- }
return false;
}
bool GenericTaintChecker::checkUncontrolledFormatString(
const CallEvent &Call, CheckerContext &C) const {
// Check if the function contains a format string argument.
- unsigned ArgNum = 0;
+ ArgIdxTy ArgNum = 0;
if (!getPrintfFormatArgumentNum(Call, C, ArgNum))
return false;
@@ -864,102 +850,32 @@ bool GenericTaintChecker::checkUncontrolledFormatString(
MsgUncontrolledFormatString, C);
}
-bool GenericTaintChecker::checkSystemCall(const CallEvent &Call, StringRef Name,
- CheckerContext &C) const {
- // TODO: It might make sense to run this check on demand. In some cases,
- // we should check if the environment has been cleansed here. We also might
- // need to know if the user was reset before these calls(seteuid).
- unsigned ArgNum = llvm::StringSwitch<unsigned>(Name)
- .Case("system", 0)
- .Case("popen", 0)
- .Case("execl", 0)
- .Case("execle", 0)
- .Case("execlp", 0)
- .Case("execv", 0)
- .Case("execvp", 0)
- .Case("execvP", 0)
- .Case("execve", 0)
- .Case("dlopen", 0)
- .Default(InvalidArgIndex);
-
- if (ArgNum == InvalidArgIndex || Call.getNumArgs() < (ArgNum + 1))
- return false;
-
- return generateReportIfTainted(Call.getArgExpr(ArgNum), MsgSanitizeSystemArgs,
- C);
-}
-
-// TODO: Should this check be a part of the CString checker?
-// If yes, should taint be a global setting?
-bool GenericTaintChecker::checkTaintedBufferSize(const CallEvent &Call,
- CheckerContext &C) const {
- const auto *FDecl = Call.getDecl()->getAsFunction();
- // If the function has a buffer size argument, set ArgNum.
- unsigned ArgNum = InvalidArgIndex;
- unsigned BId = 0;
- if ((BId = FDecl->getMemoryFunctionKind())) {
- switch (BId) {
- case Builtin::BImemcpy:
- case Builtin::BImemmove:
- case Builtin::BIstrncpy:
- ArgNum = 2;
- break;
- case Builtin::BIstrndup:
- ArgNum = 1;
- break;
- default:
- break;
- }
- }
+void GenericTaintChecker::taintUnsafeSocketProtocol(const CallEvent &Call,
+ CheckerContext &C) const {
+ if (Call.getNumArgs() < 1)
+ return;
+ const IdentifierInfo *ID = Call.getCalleeIdentifier();
+ if (!ID)
+ return;
+ if (!ID->getName().equals("socket"))
+ return;
- if (ArgNum == InvalidArgIndex) {
- using CCtx = CheckerContext;
- if (CCtx::isCLibraryFunction(FDecl, "malloc") ||
- CCtx::isCLibraryFunction(FDecl, "calloc") ||
- CCtx::isCLibraryFunction(FDecl, "alloca"))
- ArgNum = 0;
- else if (CCtx::isCLibraryFunction(FDecl, "memccpy"))
- ArgNum = 3;
- else if (CCtx::isCLibraryFunction(FDecl, "realloc"))
- ArgNum = 1;
- else if (CCtx::isCLibraryFunction(FDecl, "bcopy"))
- ArgNum = 2;
- }
+ SourceLocation DomLoc = Call.getArgExpr(0)->getExprLoc();
+ StringRef DomName = C.getMacroNameOrSpelling(DomLoc);
+ // Allow internal communication protocols.
+ bool SafeProtocol = DomName.equals("AF_SYSTEM") ||
+ DomName.equals("AF_LOCAL") || DomName.equals("AF_UNIX") ||
+ DomName.equals("AF_RESERVED_36");
+ if (SafeProtocol)
+ return;
- return ArgNum != InvalidArgIndex && Call.getNumArgs() > ArgNum &&
- generateReportIfTainted(Call.getArgExpr(ArgNum), MsgTaintedBufferSize,
- C);
+ C.addTransition(C.getState()->add<TaintArgsOnPostVisit>(ReturnValueIndex));
}
-bool GenericTaintChecker::checkCustomSinks(const CallEvent &Call,
- const FunctionData &FData,
- CheckerContext &C) const {
- auto It = findFunctionInConfig(CustomSinks, FData);
- if (It == CustomSinks.end())
- return false;
-
- const auto &Value = It->second;
- const GenericTaintChecker::ArgVector &Args = Value.second;
- for (unsigned ArgNum : Args) {
- if (ArgNum >= Call.getNumArgs())
- continue;
-
- if (generateReportIfTainted(Call.getArgExpr(ArgNum), MsgCustomSink, C))
- return true;
- }
-
- return false;
-}
+/// Checker registration
void ento::registerGenericTaintChecker(CheckerManager &Mgr) {
- auto *Checker = Mgr.registerChecker<GenericTaintChecker>();
- std::string Option{"Config"};
- StringRef ConfigFile =
- Mgr.getAnalyzerOptions().getCheckerStringOption(Checker, Option);
- llvm::Optional<TaintConfig> Config =
- getConfiguration<TaintConfig>(Mgr, Checker, Option, ConfigFile);
- if (Config)
- Checker->parseConfiguration(Mgr, Option, std::move(Config.getValue()));
+ Mgr.registerChecker<GenericTaintChecker>();
}
bool ento::shouldRegisterGenericTaintChecker(const CheckerManager &mgr) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 10ed6149528c..57080a84451a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -1643,7 +1643,7 @@ void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call,
ProgramStateRef State =
FreeMemAux(C, Call.getArgExpr(0), Call, C.getState(),
/*Hold=*/true, IsKnownToBeAllocatedMemory, AF_Malloc,
- /*RetNullOnFailure=*/true);
+ /*ReturnsNullOnFailure=*/true);
C.addTransition(State);
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
index 517a5d78271b..aa70db041c76 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
@@ -23,7 +23,6 @@
using namespace clang;
using namespace ento;
-using llvm::APSInt;
namespace {
class MmapWriteExecChecker : public Checker<check::PreCall> {
diff --git a/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp
index cd502241ef61..cf97439a468d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp
@@ -59,7 +59,7 @@ private:
} // namespace
static std::string getName(const CallEvent &Call) {
- std::string Name = "";
+ std::string Name;
if (const auto *MD = dyn_cast<CXXMethodDecl>(Call.getDecl()))
if (const CXXRecordDecl *RD = MD->getParent())
Name += RD->getNameAsString() + "::";
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h
index ec6a7144fa45..e35ea4ef05dd 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h
@@ -17,10 +17,6 @@
#include <utility>
namespace clang {
-class CXXRecordDecl;
-class CXXBaseSpecifier;
-class FunctionDecl;
-class CXXMethodDecl;
class Expr;
/// This function de-facto defines a set of transformations that we consider
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
index 730a59977175..753adea0d14d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
@@ -15,7 +15,6 @@ namespace clang {
class CXXBaseSpecifier;
class CXXMethodDecl;
class CXXRecordDecl;
-class Expr;
class FunctionDecl;
class Type;
diff --git a/clang/lib/StaticAnalyzer/Checkers/Yaml.h b/clang/lib/StaticAnalyzer/Checkers/Yaml.h
index ec612dde3b8b..497189f4c160 100644
--- a/clang/lib/StaticAnalyzer/Checkers/Yaml.h
+++ b/clang/lib/StaticAnalyzer/Checkers/Yaml.h
@@ -57,4 +57,4 @@ llvm::Optional<T> getConfiguration(CheckerManager &Mgr, Checker *Chk,
} // namespace ento
} // namespace clang
-#endif // LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MOVE_H
+#endif // LLVM_CLANG_LIB_STATICANALYZER_CHECKER_YAML_H
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index b957bec7493e..e13387fb1fc8 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -2804,7 +2804,8 @@ bool ConditionBRVisitor::patternMatch(const Expr *Ex,
Out << '\''
<< Lexer::getSourceText(
CharSourceRange::getTokenRange(Ex->getSourceRange()),
- BRC.getSourceManager(), BRC.getASTContext().getLangOpts(), 0)
+ BRC.getSourceManager(), BRC.getASTContext().getLangOpts(),
+ nullptr)
<< '\'';
}
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 637e4edfd778..302a971a15f2 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -416,7 +416,10 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_IntegralCast: {
// Delegate to SValBuilder to process.
SVal V = state->getSVal(Ex, LCtx);
- V = svalBuilder.evalIntegralCast(state, V, T, ExTy);
+ if (AMgr.options.ShouldSupportSymbolicIntegerCasts)
+ V = svalBuilder.evalCast(V, T, ExTy);
+ else
+ V = svalBuilder.evalIntegralCast(state, V, T, ExTy);
state = state->BindExpr(CastE, LCtx, V);
Bldr.generateNode(CastE, Pred, state);
continue;
diff --git a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
index 1ccb0de92fba..8d4e0bbb7dec 100644
--- a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -54,11 +54,7 @@ ProgramState::ProgramState(ProgramStateManager *mgr, const Environment& env,
}
ProgramState::ProgramState(const ProgramState &RHS)
- : llvm::FoldingSetNode(),
- stateMgr(RHS.stateMgr),
- Env(RHS.Env),
- store(RHS.store),
- GDM(RHS.GDM),
+ : stateMgr(RHS.stateMgr), Env(RHS.Env), store(RHS.store), GDM(RHS.GDM),
refCount(0) {
stateMgr->getStoreManager().incrementReferenceCount(store);
}
diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index 8edcef319088..bb3261bae3bf 100644
--- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -980,15 +980,19 @@ SVal SValBuilder::evalCastSubKind(nonloc::SymbolVal V, QualType CastTy,
} else {
// Symbol to integer, float.
QualType T = Context.getCanonicalType(SE->getType());
- // If types are the same or both are integers, ignore the cast.
- // FIXME: Remove this hack when we support symbolic truncation/extension.
- // HACK: If both castTy and T are integers, ignore the cast. This is
- // not a permanent solution. Eventually we want to precisely handle
- // extension/truncation of symbolic integers. This prevents us from losing
- // precision when we assign 'x = y' and 'y' is symbolic and x and y are
- // different integer types.
- if (haveSameType(T, CastTy))
- return V;
+
+ // Produce SymbolCast if CastTy and T are different integers.
+ // NOTE: In the end the type of SymbolCast shall be equal to CastTy.
+ if (T->isIntegralOrEnumerationType() &&
+ CastTy->isIntegralOrEnumerationType()) {
+ AnalyzerOptions &Opts =
+ StateMgr.getOwningEngine().getAnalysisManager().getAnalyzerOptions();
+ // If appropriate option is disabled, ignore the cast.
+ // NOTE: ShouldSupportSymbolicIntegerCasts is `false` by default.
+ if (!Opts.ShouldSupportSymbolicIntegerCasts)
+ return V;
+ return simplifySymbolCast(V, CastTy);
+ }
if (!Loc::isLocType(CastTy))
if (!IsUnknownOriginalType || !CastTy->isFloatingType() ||
T->isFloatingType())
@@ -1004,3 +1008,75 @@ SVal SValBuilder::evalCastSubKind(nonloc::PointerToMember V, QualType CastTy,
// Member pointer to whatever.
return V;
}
+
+SVal clang::ento::SValBuilder::simplifySymbolCast(nonloc::SymbolVal V,
+ QualType CastTy) {
+ // We use seven conditions to recognize a simplification case.
+ // For the clarity let `CastTy` be `C`, SE->getType() - `T`, root type - `R`,
+ // prefix `u` for unsigned, `s` for signed, no prefix - any sign:
+ // E.g. (char)(short)(uint x)
+ // ( sC )( sT )( uR x)
+ //
+ // C === R (the same type)
+ // (char)(char x) -> (char x)
+ // (long)(long x) -> (long x)
+ // Note: Comparisons operators below are for bit width.
+ // C == T
+ // (short)(short)(int x) -> (short)(int x)
+ // (int)(long)(char x) -> (int)(char x) (sizeof(long) == sizeof(int))
+ // (long)(ullong)(char x) -> (long)(char x) (sizeof(long) == sizeof(ullong))
+ // C < T
+ // (short)(int)(char x) -> (short)(char x)
+ // (char)(int)(short x) -> (char)(short x)
+ // (short)(int)(short x) -> (short x)
+ // C > T > uR
+ // (int)(short)(uchar x) -> (int)(uchar x)
+ // (uint)(short)(uchar x) -> (uint)(uchar x)
+ // (int)(ushort)(uchar x) -> (int)(uchar x)
+ // C > sT > sR
+ // (int)(short)(char x) -> (int)(char x)
+ // (uint)(short)(char x) -> (uint)(char x)
+ // C > sT == sR
+ // (int)(char)(char x) -> (int)(char x)
+ // (uint)(short)(short x) -> (uint)(short x)
+ // C > uT == uR
+ // (int)(uchar)(uchar x) -> (int)(uchar x)
+ // (uint)(ushort)(ushort x) -> (uint)(ushort x)
+ // (llong)(ulong)(uint x) -> (llong)(uint x) (sizeof(ulong) == sizeof(uint))
+
+ SymbolRef SE = V.getSymbol();
+ QualType T = Context.getCanonicalType(SE->getType());
+
+ if (T == CastTy)
+ return V;
+
+ if (!isa<SymbolCast>(SE))
+ return makeNonLoc(SE, T, CastTy);
+
+ SymbolRef RootSym = cast<SymbolCast>(SE)->getOperand();
+ QualType RT = RootSym->getType().getCanonicalType();
+
+ BasicValueFactory &BVF = getBasicValueFactory();
+ APSIntType CTy = BVF.getAPSIntType(CastTy);
+ APSIntType TTy = BVF.getAPSIntType(T);
+
+ const auto WC = CTy.getBitWidth();
+ const auto WT = TTy.getBitWidth();
+
+ if (WC <= WT) {
+ const bool isSameType = (RT == CastTy);
+ if (isSameType)
+ return nonloc::SymbolVal(RootSym);
+ return makeNonLoc(RootSym, RT, CastTy);
+ }
+
+ APSIntType RTy = BVF.getAPSIntType(RT);
+ const auto WR = RTy.getBitWidth();
+ const bool UT = TTy.isUnsigned();
+ const bool UR = RTy.isUnsigned();
+
+ if (((WT > WR) && (UR || !UT)) || ((WT == WR) && (UT == UR)))
+ return makeNonLoc(RootSym, RT, CastTy);
+
+ return makeNonLoc(SE, T, CastTy);
+}
diff --git a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index dad8a7b3caae..0bd47ced15a5 100644
--- a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -432,7 +432,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
return evalCast(lhs, resultTy, QualType{});
}
- while (1) {
+ while (true) {
switch (lhs.getSubKind()) {
default:
return makeSymExprValNN(op, lhs, rhs, resultTy);
diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index f6ddcb763f9d..b152f9d80ef5 100644
--- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -143,7 +143,7 @@ public:
}
if (Opts->PrintStats || Opts->ShouldSerializeStats) {
- llvm::EnableStatistics(/* PrintOnExit= */ false);
+ llvm::EnableStatistics(/* DoPrintOnExit= */ false);
}
if (Opts->ShouldDisplayMacroExpansions)
diff --git a/clang/lib/StaticAnalyzer/Frontend/ModelInjector.h b/clang/lib/StaticAnalyzer/Frontend/ModelInjector.h
index d2016c3b112c..4db26028362f 100644
--- a/clang/lib/StaticAnalyzer/Frontend/ModelInjector.h
+++ b/clang/lib/StaticAnalyzer/Frontend/ModelInjector.h
@@ -29,10 +29,7 @@
namespace clang {
class CompilerInstance;
-class ASTUnit;
-class ASTReader;
class NamedDecl;
-class Module;
namespace ento {
class ModelInjector : public CodeInjector {
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp
index acceec690c11..80a70252721d 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp
@@ -16,10 +16,10 @@ using namespace clang;
using namespace tooling;
using namespace dependencies;
-llvm::ErrorOr<llvm::vfs::Status>
-CachedFileSystemEntry::initFile(StringRef Filename, llvm::vfs::FileSystem &FS) {
+llvm::ErrorOr<DependencyScanningWorkerFilesystem::TentativeEntry>
+DependencyScanningWorkerFilesystem::readFile(StringRef Filename) {
// Load the file and its content from the file system.
- auto MaybeFile = FS.openFileForRead(Filename);
+ auto MaybeFile = getUnderlyingFS().openFileForRead(Filename);
if (!MaybeFile)
return MaybeFile.getError();
auto File = std::move(*MaybeFile);
@@ -34,24 +34,43 @@ CachedFileSystemEntry::initFile(StringRef Filename, llvm::vfs::FileSystem &FS) {
return MaybeBuffer.getError();
auto Buffer = std::move(*MaybeBuffer);
- OriginalContents = std::move(Buffer);
- return Stat;
+ // If the file size changed between read and stat, pretend it didn't.
+ if (Stat.getSize() != Buffer->getBufferSize())
+ Stat = llvm::vfs::Status::copyWithNewSize(Stat, Buffer->getBufferSize());
+
+ return TentativeEntry(Stat, std::move(Buffer));
}
-void CachedFileSystemEntry::minimizeFile() {
- assert(OriginalContents && "minimizing missing contents");
+EntryRef DependencyScanningWorkerFilesystem::minimizeIfNecessary(
+ const CachedFileSystemEntry &Entry, StringRef Filename, bool Disable) {
+ if (Entry.isError() || Entry.isDirectory() || Disable ||
+ !shouldMinimize(Filename, Entry.getUniqueID()))
+ return EntryRef(/*Minimized=*/false, Filename, Entry);
+
+ CachedFileContents *Contents = Entry.getContents();
+ assert(Contents && "contents not initialized");
+
+ // Double-checked locking.
+ if (Contents->MinimizedAccess.load())
+ return EntryRef(/*Minimized=*/true, Filename, Entry);
+
+ std::lock_guard<std::mutex> GuardLock(Contents->ValueLock);
+
+ // Double-checked locking.
+ if (Contents->MinimizedAccess.load())
+ return EntryRef(/*Minimized=*/true, Filename, Entry);
llvm::SmallString<1024> MinimizedFileContents;
// Minimize the file down to directives that might affect the dependencies.
SmallVector<minimize_source_to_dependency_directives::Token, 64> Tokens;
- if (minimizeSourceToDependencyDirectives(OriginalContents->getBuffer(),
+ if (minimizeSourceToDependencyDirectives(Contents->Original->getBuffer(),
MinimizedFileContents, Tokens)) {
// FIXME: Propagate the diagnostic if desired by the client.
// Use the original file if the minimization failed.
- MinimizedContentsStorage =
- llvm::MemoryBuffer::getMemBuffer(*OriginalContents);
- MinimizedContentsAccess.store(MinimizedContentsStorage.get());
- return;
+ Contents->MinimizedStorage =
+ llvm::MemoryBuffer::getMemBuffer(*Contents->Original);
+ Contents->MinimizedAccess.store(Contents->MinimizedStorage.get());
+ return EntryRef(/*Minimized=*/true, Filename, Entry);
}
// The contents produced by the minimizer must be null terminated.
@@ -74,16 +93,17 @@ void CachedFileSystemEntry::minimizeFile() {
}
Mapping[Range.Offset] = Range.Length;
}
- PPSkippedRangeMapping = std::move(Mapping);
+ Contents->PPSkippedRangeMapping = std::move(Mapping);
- MinimizedContentsStorage = std::make_unique<llvm::SmallVectorMemoryBuffer>(
+ Contents->MinimizedStorage = std::make_unique<llvm::SmallVectorMemoryBuffer>(
std::move(MinimizedFileContents));
- // The algorithm in `getOrCreateFileSystemEntry` uses the presence of
- // minimized contents to decide whether an entry is up-to-date or not.
- // If it is up-to-date, the skipped range mappings must be already computed.
- // This is why we need to store the minimized contents **after** storing the
- // skipped range mappings. Failing to do so would lead to a data race.
- MinimizedContentsAccess.store(MinimizedContentsStorage.get());
+ // This function performed double-checked locking using `MinimizedAccess`.
+ // Assigning it must be the last thing this function does. If we were to
+ // assign it before `PPSkippedRangeMapping`, other threads may skip the
+ // critical section (`MinimizedAccess != nullptr`) and access the mappings
+ // that are about to be initialized, leading to a data race.
+ Contents->MinimizedAccess.store(Contents->MinimizedStorage.get());
+ return EntryRef(/*Minimized=*/true, Filename, Entry);
}
DependencyScanningFilesystemSharedCache::
@@ -98,12 +118,70 @@ DependencyScanningFilesystemSharedCache::
CacheShards = std::make_unique<CacheShard[]>(NumShards);
}
-DependencyScanningFilesystemSharedCache::SharedFileSystemEntry &
-DependencyScanningFilesystemSharedCache::get(StringRef Key) {
- CacheShard &Shard = CacheShards[llvm::hash_value(Key) % NumShards];
- std::lock_guard<std::mutex> LockGuard(Shard.CacheLock);
- auto It = Shard.Cache.try_emplace(Key);
- return It.first->getValue();
+DependencyScanningFilesystemSharedCache::CacheShard &
+DependencyScanningFilesystemSharedCache::getShardForFilename(
+ StringRef Filename) const {
+ return CacheShards[llvm::hash_value(Filename) % NumShards];
+}
+
+DependencyScanningFilesystemSharedCache::CacheShard &
+DependencyScanningFilesystemSharedCache::getShardForUID(
+ llvm::sys::fs::UniqueID UID) const {
+ auto Hash = llvm::hash_combine(UID.getDevice(), UID.getFile());
+ return CacheShards[Hash % NumShards];
+}
+
+const CachedFileSystemEntry *
+DependencyScanningFilesystemSharedCache::CacheShard::findEntryByFilename(
+ StringRef Filename) const {
+ std::lock_guard<std::mutex> LockGuard(CacheLock);
+ auto It = EntriesByFilename.find(Filename);
+ return It == EntriesByFilename.end() ? nullptr : It->getValue();
+}
+
+const CachedFileSystemEntry *
+DependencyScanningFilesystemSharedCache::CacheShard::findEntryByUID(
+ llvm::sys::fs::UniqueID UID) const {
+ std::lock_guard<std::mutex> LockGuard(CacheLock);
+ auto It = EntriesByUID.find(UID);
+ return It == EntriesByUID.end() ? nullptr : It->getSecond();
+}
+
+const CachedFileSystemEntry &
+DependencyScanningFilesystemSharedCache::CacheShard::
+ getOrEmplaceEntryForFilename(StringRef Filename,
+ llvm::ErrorOr<llvm::vfs::Status> Stat) {
+ std::lock_guard<std::mutex> LockGuard(CacheLock);
+ auto Insertion = EntriesByFilename.insert({Filename, nullptr});
+ if (Insertion.second)
+ Insertion.first->second =
+ new (EntryStorage.Allocate()) CachedFileSystemEntry(std::move(Stat));
+ return *Insertion.first->second;
+}
+
+const CachedFileSystemEntry &
+DependencyScanningFilesystemSharedCache::CacheShard::getOrEmplaceEntryForUID(
+ llvm::sys::fs::UniqueID UID, llvm::vfs::Status Stat,
+ std::unique_ptr<llvm::MemoryBuffer> Contents) {
+ std::lock_guard<std::mutex> LockGuard(CacheLock);
+ auto Insertion = EntriesByUID.insert({UID, nullptr});
+ if (Insertion.second) {
+ CachedFileContents *StoredContents = nullptr;
+ if (Contents)
+ StoredContents = new (ContentsStorage.Allocate())
+ CachedFileContents(std::move(Contents));
+ Insertion.first->second = new (EntryStorage.Allocate())
+ CachedFileSystemEntry(std::move(Stat), StoredContents);
+ }
+ return *Insertion.first->second;
+}
+
+const CachedFileSystemEntry &
+DependencyScanningFilesystemSharedCache::CacheShard::
+ getOrInsertEntryForFilename(StringRef Filename,
+ const CachedFileSystemEntry &Entry) {
+ std::lock_guard<std::mutex> LockGuard(CacheLock);
+ return *EntriesByFilename.insert({Filename, &Entry}).first->getValue();
}
/// Whitelist file extensions that should be minimized, treating no extension as
@@ -133,68 +211,79 @@ static bool shouldCacheStatFailures(StringRef Filename) {
}
void DependencyScanningWorkerFilesystem::disableMinimization(
- StringRef RawFilename) {
- llvm::SmallString<256> Filename;
- llvm::sys::path::native(RawFilename, Filename);
- NotToBeMinimized.insert(Filename);
+ StringRef Filename) {
+ // Since we're not done setting up `NotToBeMinimized` yet, we need to disable
+ // minimization explicitly.
+ if (llvm::ErrorOr<EntryRef> Result =
+ getOrCreateFileSystemEntry(Filename, /*DisableMinimization=*/true))
+ NotToBeMinimized.insert(Result->getStatus().getUniqueID());
}
-bool DependencyScanningWorkerFilesystem::shouldMinimize(StringRef RawFilename) {
- if (!shouldMinimizeBasedOnExtension(RawFilename))
- return false;
-
- llvm::SmallString<256> Filename;
- llvm::sys::path::native(RawFilename, Filename);
- return !NotToBeMinimized.contains(Filename);
+bool DependencyScanningWorkerFilesystem::shouldMinimize(
+ StringRef Filename, llvm::sys::fs::UniqueID UID) {
+ return shouldMinimizeBasedOnExtension(Filename) &&
+ !NotToBeMinimized.contains(UID);
}
-void CachedFileSystemEntry::init(llvm::ErrorOr<llvm::vfs::Status> &&MaybeStatus,
- StringRef Filename,
- llvm::vfs::FileSystem &FS) {
- if (!MaybeStatus || MaybeStatus->isDirectory())
- MaybeStat = std::move(MaybeStatus);
- else
- MaybeStat = initFile(Filename, FS);
+const CachedFileSystemEntry &
+DependencyScanningWorkerFilesystem::getOrEmplaceSharedEntryForUID(
+ TentativeEntry TEntry) {
+ auto &Shard = SharedCache.getShardForUID(TEntry.Status.getUniqueID());
+ return Shard.getOrEmplaceEntryForUID(TEntry.Status.getUniqueID(),
+ std::move(TEntry.Status),
+ std::move(TEntry.Contents));
}
-llvm::ErrorOr<EntryRef>
-DependencyScanningWorkerFilesystem::getOrCreateFileSystemEntry(
+const CachedFileSystemEntry *
+DependencyScanningWorkerFilesystem::findEntryByFilenameWithWriteThrough(
StringRef Filename) {
- bool ShouldBeMinimized = shouldMinimize(Filename);
+ if (const auto *Entry = LocalCache.findEntryByFilename(Filename))
+ return Entry;
+ auto &Shard = SharedCache.getShardForFilename(Filename);
+ if (const auto *Entry = Shard.findEntryByFilename(Filename))
+ return &LocalCache.insertEntryForFilename(Filename, *Entry);
+ return nullptr;
+}
- const auto *Entry = LocalCache.getCachedEntry(Filename);
- if (Entry && !Entry->needsUpdate(ShouldBeMinimized))
- return EntryRef(ShouldBeMinimized, *Entry);
+llvm::ErrorOr<const CachedFileSystemEntry &>
+DependencyScanningWorkerFilesystem::computeAndStoreResult(StringRef Filename) {
+ llvm::ErrorOr<llvm::vfs::Status> Stat = getUnderlyingFS().status(Filename);
+ if (!Stat) {
+ if (!shouldCacheStatFailures(Filename))
+ return Stat.getError();
+ const auto &Entry =
+ getOrEmplaceSharedEntryForFilename(Filename, Stat.getError());
+ return insertLocalEntryForFilename(Filename, Entry);
+ }
- // FIXME: Handle PCM/PCH files.
- // FIXME: Handle module map files.
+ if (const auto *Entry = findSharedEntryByUID(*Stat))
+ return insertLocalEntryForFilename(Filename, *Entry);
- auto &SharedCacheEntry = SharedCache.get(Filename);
- {
- std::lock_guard<std::mutex> LockGuard(SharedCacheEntry.ValueLock);
- CachedFileSystemEntry &CacheEntry = SharedCacheEntry.Value;
+ auto TEntry =
+ Stat->isDirectory() ? TentativeEntry(*Stat) : readFile(Filename);
- if (!CacheEntry.isInitialized()) {
- auto MaybeStatus = getUnderlyingFS().status(Filename);
- if (!MaybeStatus && !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();
- CacheEntry.init(std::move(MaybeStatus), Filename, getUnderlyingFS());
+ const CachedFileSystemEntry *SharedEntry = [&]() {
+ if (TEntry) {
+ const auto &UIDEntry = getOrEmplaceSharedEntryForUID(std::move(*TEntry));
+ return &getOrInsertSharedEntryForFilename(Filename, UIDEntry);
}
+ return &getOrEmplaceSharedEntryForFilename(Filename, TEntry.getError());
+ }();
- // Checking `needsUpdate` verifies the entry represents an opened file.
- // Only checking `needsMinimization` could lead to minimization of files
- // that we failed to load (such files don't have `OriginalContents`).
- if (CacheEntry.needsUpdate(ShouldBeMinimized))
- CacheEntry.minimizeFile();
- }
+ return insertLocalEntryForFilename(Filename, *SharedEntry);
+}
- // Store the result in the local cache.
- Entry = &SharedCacheEntry.Value;
- return EntryRef(ShouldBeMinimized, *Entry);
+llvm::ErrorOr<EntryRef>
+DependencyScanningWorkerFilesystem::getOrCreateFileSystemEntry(
+ StringRef Filename, bool DisableMinimization) {
+ if (const auto *Entry = findEntryByFilenameWithWriteThrough(Filename))
+ return minimizeIfNecessary(*Entry, Filename, DisableMinimization)
+ .unwrapError();
+ auto MaybeEntry = computeAndStoreResult(Filename);
+ if (!MaybeEntry)
+ return MaybeEntry.getError();
+ return minimizeIfNecessary(*MaybeEntry, Filename, DisableMinimization)
+ .unwrapError();
}
llvm::ErrorOr<llvm::vfs::Status>
@@ -241,16 +330,16 @@ private:
llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>> MinimizedVFSFile::create(
EntryRef Entry, ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings) {
+ assert(!Entry.isError() && "error");
+
if (Entry.isDirectory())
return std::make_error_code(std::errc::is_a_directory);
- llvm::ErrorOr<StringRef> Contents = Entry.getContents();
- if (!Contents)
- return Contents.getError();
auto Result = std::make_unique<MinimizedVFSFile>(
- llvm::MemoryBuffer::getMemBuffer(*Contents, Entry.getName(),
+ llvm::MemoryBuffer::getMemBuffer(Entry.getContents(),
+ Entry.getStatus().getName(),
/*RequiresNullTerminator=*/false),
- *Entry.getStatus());
+ Entry.getStatus());
const auto *EntrySkipMappings = Entry.getPPSkippedRangeMapping();
if (EntrySkipMappings && !EntrySkipMappings->empty() && PPSkipMappings)
diff --git a/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp b/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp
index 29787b8a8894..75d0d50d851f 100644
--- a/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp
+++ b/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp
@@ -61,7 +61,7 @@ private:
continue;
llvm::BumpPtrAllocator Alloc;
llvm::StringSaver Saver(Alloc);
- llvm::cl::ExpandResponseFiles(Saver, Tokenizer, Argv, false, false,
+ llvm::cl::ExpandResponseFiles(Saver, Tokenizer, Argv, false, false, false,
llvm::StringRef(Cmd.Directory), *FS);
// Don't assign directly, Argv aliases CommandLine.
std::vector<std::string> ExpandedArgv(Argv.begin(), Argv.end());
diff --git a/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp b/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
index c1e25c41f719..51e8439b6b79 100644
--- a/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
+++ b/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
@@ -243,8 +243,7 @@ struct TransferableCommand {
llvm::Twine(ClangCLMode ? "/std:" : "-std=") +
LangStandard::getLangStandardForKind(Std).getName()).str());
}
- if (Filename.startswith("-") || (ClangCLMode && Filename.startswith("/")))
- Result.CommandLine.push_back("--");
+ Result.CommandLine.push_back("--");
Result.CommandLine.push_back(std::string(Filename));
return Result;
}
diff --git a/clang/lib/Tooling/Syntax/Tree.cpp b/clang/lib/Tooling/Syntax/Tree.cpp
index c813865e95cd..981bac508f73 100644
--- a/clang/lib/Tooling/Syntax/Tree.cpp
+++ b/clang/lib/Tooling/Syntax/Tree.cpp
@@ -9,6 +9,7 @@
#include "clang/Basic/TokenKinds.h"
#include "clang/Tooling/Syntax/Nodes.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Casting.h"
#include <cassert>
@@ -202,7 +203,7 @@ static void dumpLeaf(raw_ostream &OS, const syntax::Leaf *L,
}
static void dumpNode(raw_ostream &OS, const syntax::Node *N,
- const SourceManager &SM, std::vector<bool> IndentMask) {
+ const SourceManager &SM, llvm::BitVector IndentMask) {
auto DumpExtraInfo = [&OS](const syntax::Node *N) {
if (N->getRole() != syntax::NodeRole::Unknown)
OS << " " << N->getRole();
@@ -228,8 +229,8 @@ static void dumpNode(raw_ostream &OS, const syntax::Node *N,
OS << "\n";
for (const syntax::Node &It : T->getChildren()) {
- for (bool Filled : IndentMask) {
- if (Filled)
+ for (unsigned Idx = 0; Idx < IndentMask.size(); ++Idx) {
+ if (IndentMask[Idx])
OS << "| ";
else
OS << " ";
diff --git a/clang/lib/Tooling/Transformer/Parsing.cpp b/clang/lib/Tooling/Transformer/Parsing.cpp
index 242db2a16b43..4f41e2e90def 100644
--- a/clang/lib/Tooling/Transformer/Parsing.cpp
+++ b/clang/lib/Tooling/Transformer/Parsing.cpp
@@ -33,7 +33,6 @@ using namespace transformer;
// much as possible with the AST Matchers parsing.
namespace {
-using llvm::Error;
using llvm::Expected;
template <typename... Ts> using RangeSelectorOp = RangeSelector (*)(Ts...);
diff --git a/clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp b/clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp
index a1c99b60216b..7496e968469c 100644
--- a/clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp
+++ b/clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp
@@ -10,6 +10,8 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Tooling/Transformer/SourceCode.h"
#include "llvm/ADT/Twine.h"
#include <string>
@@ -60,6 +62,16 @@ bool tooling::needParensAfterUnaryOperator(const Expr &E) {
return false;
}
+bool tooling::isKnownPointerLikeType(QualType Ty, ASTContext &Context) {
+ using namespace ast_matchers;
+ const auto PointerLikeTy = type(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(cxxRecordDecl(hasAnyName(
+ "::std::unique_ptr", "::std::shared_ptr", "::std::weak_ptr",
+ "::std::optional", "::absl::optional", "::llvm::Optional",
+ "absl::StatusOr", "::llvm::Expected"))))));
+ return match(PointerLikeTy, Ty, Context).size() > 0;
+}
+
llvm::Optional<std::string> tooling::buildParens(const Expr &E,
const ASTContext &Context) {
StringRef Text = getText(E, Context);
@@ -114,8 +126,10 @@ llvm::Optional<std::string> tooling::buildAddressOf(const Expr &E,
return ("&" + Text).str();
}
-llvm::Optional<std::string> tooling::buildDot(const Expr &E,
- const ASTContext &Context) {
+// Append the appropriate access operation (syntactically) to `E`, assuming `E`
+// is a non-pointer value.
+static llvm::Optional<std::string>
+buildAccessForValue(const Expr &E, const ASTContext &Context) {
if (const auto *Op = llvm::dyn_cast<UnaryOperator>(&E))
if (Op->getOpcode() == UO_Deref) {
// Strip leading '*', add following '->'.
@@ -138,8 +152,10 @@ llvm::Optional<std::string> tooling::buildDot(const Expr &E,
return (Text + ".").str();
}
-llvm::Optional<std::string> tooling::buildArrow(const Expr &E,
- const ASTContext &Context) {
+// Append the appropriate access operation (syntactically) to `E`, assuming `E`
+// is a pointer value.
+static llvm::Optional<std::string>
+buildAccessForPointer(const Expr &E, const ASTContext &Context) {
if (const auto *Op = llvm::dyn_cast<UnaryOperator>(&E))
if (Op->getOpcode() == UO_AddrOf) {
// Strip leading '&', add following '.'.
@@ -160,3 +176,63 @@ llvm::Optional<std::string> tooling::buildArrow(const Expr &E,
return ("(" + Text + ")->").str();
return (Text + "->").str();
}
+
+llvm::Optional<std::string> tooling::buildDot(const Expr &E,
+ const ASTContext &Context) {
+ return buildAccessForValue(E, Context);
+}
+
+llvm::Optional<std::string> tooling::buildArrow(const Expr &E,
+ const ASTContext &Context) {
+ return buildAccessForPointer(E, Context);
+}
+
+// If `E` is an overloaded-operator call of kind `K` on an object `O`, returns
+// `O`. Otherwise, returns `nullptr`.
+static const Expr *maybeGetOperatorObjectArg(const Expr &E,
+ OverloadedOperatorKind K) {
+ if (const auto *OpCall = dyn_cast<clang::CXXOperatorCallExpr>(&E)) {
+ if (OpCall->getOperator() == K && OpCall->getNumArgs() == 1)
+ return OpCall->getArg(0);
+ }
+ return nullptr;
+}
+
+static bool treatLikePointer(QualType Ty, PLTClass C, ASTContext &Context) {
+ switch (C) {
+ case PLTClass::Value:
+ return false;
+ case PLTClass::Pointer:
+ return isKnownPointerLikeType(Ty, Context);
+ }
+ llvm_unreachable("Unknown PLTClass enum");
+}
+
+// FIXME: move over the other `maybe` functionality from Stencil. Should all be
+// in one place.
+llvm::Optional<std::string> tooling::buildAccess(const Expr &RawExpression,
+ ASTContext &Context,
+ PLTClass Classification) {
+ if (RawExpression.isImplicitCXXThis())
+ // Return the empty string, because `None` signifies some sort of failure.
+ return std::string();
+
+ const Expr *E = RawExpression.IgnoreImplicitAsWritten();
+
+ if (E->getType()->isAnyPointerType() ||
+ treatLikePointer(E->getType(), Classification, Context)) {
+ // Strip off operator-> calls. They can only occur inside an actual arrow
+ // member access, so we treat them as equivalent to an actual object
+ // expression.
+ if (const auto *Obj = maybeGetOperatorObjectArg(*E, clang::OO_Arrow))
+ E = Obj;
+ return buildAccessForPointer(*E, Context);
+ }
+
+ if (const auto *Obj = maybeGetOperatorObjectArg(*E, clang::OO_Star)) {
+ if (treatLikePointer(Obj->getType(), Classification, Context))
+ return buildAccessForPointer(*Obj, Context);
+ };
+
+ return buildAccessForValue(*E, Context);
+}
diff --git a/clang/lib/Tooling/Transformer/Stencil.cpp b/clang/lib/Tooling/Transformer/Stencil.cpp
index 8b20ef34c3ff..348d04dbaf4a 100644
--- a/clang/lib/Tooling/Transformer/Stencil.cpp
+++ b/clang/lib/Tooling/Transformer/Stencil.cpp
@@ -11,7 +11,6 @@
#include "clang/AST/ASTTypeTraits.h"
#include "clang/AST/Expr.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Lex/Lexer.h"
#include "clang/Tooling/Transformer/SourceCode.h"
@@ -56,39 +55,6 @@ static Error printNode(StringRef Id, const MatchFinder::MatchResult &Match,
return Error::success();
}
-// FIXME: Consider memoizing this function using the `ASTContext`.
-static bool isSmartPointerType(QualType Ty, ASTContext &Context) {
- using namespace ::clang::ast_matchers;
-
- // Optimization: hard-code common smart-pointer types. This can/should be
- // removed if we start caching the results of this function.
- auto KnownSmartPointer =
- cxxRecordDecl(hasAnyName("::std::unique_ptr", "::std::shared_ptr"));
- const auto QuacksLikeASmartPointer = cxxRecordDecl(
- hasMethod(cxxMethodDecl(hasOverloadedOperatorName("->"),
- returns(qualType(pointsTo(type()))))),
- hasMethod(cxxMethodDecl(hasOverloadedOperatorName("*"),
- returns(qualType(references(type()))))));
- const auto SmartPointer = qualType(hasDeclaration(
- cxxRecordDecl(anyOf(KnownSmartPointer, QuacksLikeASmartPointer))));
- return match(SmartPointer, Ty, Context).size() > 0;
-}
-
-// Identifies use of `operator*` on smart pointers, and returns the underlying
-// smart-pointer expression; otherwise, returns null.
-static const Expr *isSmartDereference(const Expr &E, ASTContext &Context) {
- using namespace ::clang::ast_matchers;
-
- const auto HasOverloadedArrow = cxxRecordDecl(hasMethod(cxxMethodDecl(
- hasOverloadedOperatorName("->"), returns(qualType(pointsTo(type()))))));
- // Verify it is a smart pointer by finding `operator->` in the class
- // declaration.
- auto Deref = cxxOperatorCallExpr(
- hasOverloadedOperatorName("*"), hasUnaryOperand(expr().bind("arg")),
- callee(cxxMethodDecl(ofClass(HasOverloadedArrow))));
- return selectFirst<Expr>("arg", match(Deref, E, Context));
-}
-
namespace {
// An arbitrary fragment of code within a stencil.
class RawTextStencil : public StencilInterface {
@@ -196,7 +162,7 @@ public:
break;
case UnaryNodeOperator::MaybeDeref:
if (E->getType()->isAnyPointerType() ||
- isSmartPointerType(E->getType(), *Match.Context)) {
+ tooling::isKnownPointerLikeType(E->getType(), *Match.Context)) {
// Strip off any operator->. This can only occur inside an actual arrow
// member access, so we treat it as equivalent to an actual object
// expression.
@@ -216,7 +182,7 @@ public:
break;
case UnaryNodeOperator::MaybeAddressOf:
if (E->getType()->isAnyPointerType() ||
- isSmartPointerType(E->getType(), *Match.Context)) {
+ tooling::isKnownPointerLikeType(E->getType(), *Match.Context)) {
// Strip off any operator->. This can only occur inside an actual arrow
// member access, so we treat it as equivalent to an actual object
// expression.
@@ -311,34 +277,12 @@ public:
if (E == nullptr)
return llvm::make_error<StringError>(errc::invalid_argument,
"Id not bound: " + BaseId);
- if (!E->isImplicitCXXThis()) {
- llvm::Optional<std::string> S;
- if (E->getType()->isAnyPointerType() ||
- isSmartPointerType(E->getType(), *Match.Context)) {
- // Strip off any operator->. This can only occur inside an actual arrow
- // member access, so we treat it as equivalent to an actual object
- // expression.
- if (const auto *OpCall = dyn_cast<clang::CXXOperatorCallExpr>(E)) {
- if (OpCall->getOperator() == clang::OO_Arrow &&
- OpCall->getNumArgs() == 1) {
- E = OpCall->getArg(0);
- }
- }
- S = tooling::buildArrow(*E, *Match.Context);
- } else if (const auto *Operand = isSmartDereference(*E, *Match.Context)) {
- // `buildDot` already handles the built-in dereference operator, so we
- // only need to catch overloaded `operator*`.
- S = tooling::buildArrow(*Operand, *Match.Context);
- } else {
- S = tooling::buildDot(*E, *Match.Context);
- }
- if (S.hasValue())
- *Result += *S;
- else
- return llvm::make_error<StringError>(
- errc::invalid_argument,
- "Could not construct object text from ID: " + BaseId);
- }
+ llvm::Optional<std::string> S = tooling::buildAccess(*E, *Match.Context);
+ if (!S.hasValue())
+ return llvm::make_error<StringError>(
+ errc::invalid_argument,
+ "Could not construct object text from ID: " + BaseId);
+ *Result += *S;
return Member->eval(Match, Result);
}
};