https://github.com/ChuanqiXu9 updated https://github.com/llvm/llvm-project/pull/83108
>From 6e0716367fc369f6e57ffd2b20b7a4c49230bac2 Mon Sep 17 00:00:00 2001 From: Chuanqi Xu <yedeng...@linux.alibaba.com> Date: Fri, 8 Nov 2024 10:56:44 +0800 Subject: [PATCH 1/2] [Serialization] Downgrade inconsistent flags from erros to warnings --- clang/docs/ReleaseNotes.rst | 2 + clang/include/clang/Basic/DiagnosticGroups.td | 1 + .../Basic/DiagnosticSerializationKinds.td | 10 ++-- clang/lib/Serialization/ASTReader.cpp | 39 +++++-------- .../Modules/explicit-build-missing-files.cpp | 2 +- clang/test/Modules/load_failure.c | 6 +- clang/test/Modules/mismatch-diagnostics.cpp | 56 +++++++++++++------ clang/test/Modules/module-feature.m | 6 +- clang/test/Modules/pr62359.cppm | 9 ++- .../test/Modules/prebuilt-implicit-modules.m | 2 +- clang/test/PCH/arc.m | 6 +- clang/test/PCH/no-validate-pch.cl | 2 +- clang/test/PCH/pch-dir.c | 10 ++-- 13 files changed, 86 insertions(+), 65 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 30bcb6313b6ade..65aa8acd7b8263 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -511,6 +511,8 @@ Improvements to Clang's diagnostics - Clang now diagnoses ``[[deprecated]]`` attribute usage on local variables (#GH90073). +- Clang now downgrades the inconsistent language options between modules to warnings instead of errors. + Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 72eada50a56cc9..ba42ddfc37f35a 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -555,6 +555,7 @@ def ModuleLock : DiagGroup<"module-lock">; def ModuleBuild : DiagGroup<"module-build">; def ModuleImport : DiagGroup<"module-import">; def ModuleConflict : DiagGroup<"module-conflict">; +def ModuleMismatchedOption : DiagGroup<"module-mismatched-option">; def ModuleFileExtension : DiagGroup<"module-file-extension">; def ModuleIncludeDirectiveTranslation : DiagGroup<"module-include-translation">; def RoundTripCC1Args : DiagGroup<"round-trip-cc1-args">; diff --git a/clang/include/clang/Basic/DiagnosticSerializationKinds.td b/clang/include/clang/Basic/DiagnosticSerializationKinds.td index 3914d3930bec79..4e1aff20617963 100644 --- a/clang/include/clang/Basic/DiagnosticSerializationKinds.td +++ b/clang/include/clang/Basic/DiagnosticSerializationKinds.td @@ -36,10 +36,12 @@ def err_ast_file_targetopt_feature_mismatch : Error< "%select{AST file '%1' was|current translation unit is}0 compiled with the target " "feature '%2' but the %select{current translation unit is|AST file '%1' was}0 " "not">; -def err_ast_file_langopt_mismatch : Error<"%0 was %select{disabled|enabled}1 in " - "AST file '%3' but is currently %select{disabled|enabled}2">; -def err_ast_file_langopt_value_mismatch : Error< - "%0 differs in AST file '%1' vs. current file">; +def warn_ast_file_langopt_mismatch : Warning<"%0 was %select{disabled|enabled}1 in " + "AST file '%3' but is currently %select{disabled|enabled}2">, + InGroup<ModuleMismatchedOption>; +def warn_ast_file_langopt_value_mismatch : Warning< + "%0 differs in AST file '%1' vs. current file">, + InGroup<ModuleMismatchedOption>; def err_ast_file_diagopt_mismatch : Error<"%0 is currently enabled, but was not in " "the AST file '%1'">; def err_ast_file_modulecache_mismatch : Error<"AST file '%2' was compiled with module cache " diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 79615dc3c018ea..1c94e8e9a212a9 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -279,9 +279,7 @@ ASTReaderListener::~ASTReaderListener() = default; /// \param Diags If non-NULL, diagnostics will be emitted via this engine. /// \param AllowCompatibleDifferences If true, differences between compatible /// language options will be permitted. -/// -/// \returns true if the languagae options mis-match, false otherwise. -static bool checkLanguageOptions(const LangOptions &LangOpts, +static void checkLanguageOptions(const LangOptions &LangOpts, const LangOptions &ExistingLangOpts, StringRef ModuleFilename, DiagnosticsEngine *Diags, @@ -290,30 +288,27 @@ static bool checkLanguageOptions(const LangOptions &LangOpts, if (ExistingLangOpts.Name != LangOpts.Name) { \ if (Diags) { \ if (Bits == 1) \ - Diags->Report(diag::err_ast_file_langopt_mismatch) \ + Diags->Report(diag::warn_ast_file_langopt_mismatch) \ << Description << LangOpts.Name << ExistingLangOpts.Name \ << ModuleFilename; \ else \ - Diags->Report(diag::err_ast_file_langopt_value_mismatch) \ + Diags->Report(diag::warn_ast_file_langopt_value_mismatch) \ << Description << ModuleFilename; \ } \ - return true; \ } #define VALUE_LANGOPT(Name, Bits, Default, Description) \ if (ExistingLangOpts.Name != LangOpts.Name) { \ if (Diags) \ - Diags->Report(diag::err_ast_file_langopt_value_mismatch) \ + Diags->Report(diag::warn_ast_file_langopt_value_mismatch) \ << Description << ModuleFilename; \ - return true; \ } #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ if (ExistingLangOpts.get##Name() != LangOpts.get##Name()) { \ if (Diags) \ - Diags->Report(diag::err_ast_file_langopt_value_mismatch) \ + Diags->Report(diag::warn_ast_file_langopt_value_mismatch) \ << Description << ModuleFilename; \ - return true; \ } #define COMPATIBLE_LANGOPT(Name, Bits, Default, Description) \ @@ -335,24 +330,21 @@ static bool checkLanguageOptions(const LangOptions &LangOpts, if (ExistingLangOpts.ModuleFeatures != LangOpts.ModuleFeatures) { if (Diags) - Diags->Report(diag::err_ast_file_langopt_value_mismatch) + Diags->Report(diag::warn_ast_file_langopt_value_mismatch) << "module features" << ModuleFilename; - return true; } if (ExistingLangOpts.ObjCRuntime != LangOpts.ObjCRuntime) { if (Diags) - Diags->Report(diag::err_ast_file_langopt_value_mismatch) + Diags->Report(diag::warn_ast_file_langopt_value_mismatch) << "target Objective-C runtime" << ModuleFilename; - return true; } if (ExistingLangOpts.CommentOpts.BlockCommandNames != LangOpts.CommentOpts.BlockCommandNames) { if (Diags) - Diags->Report(diag::err_ast_file_langopt_value_mismatch) + Diags->Report(diag::warn_ast_file_langopt_value_mismatch) << "block command names" << ModuleFilename; - return true; } // Sanitizer feature mismatches are treated as compatible differences. If @@ -378,11 +370,8 @@ static bool checkLanguageOptions(const LangOptions &LangOpts, } #include "clang/Basic/Sanitizers.def" } - return true; } } - - return false; } /// Compare the given set of target options against an existing set of @@ -459,9 +448,10 @@ bool PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts, StringRef ModuleFilename, bool Complain, bool AllowCompatibleDifferences) { const LangOptions &ExistingLangOpts = PP.getLangOpts(); - return checkLanguageOptions(LangOpts, ExistingLangOpts, ModuleFilename, - Complain ? &Reader.Diags : nullptr, - AllowCompatibleDifferences); + checkLanguageOptions(LangOpts, ExistingLangOpts, ModuleFilename, + Complain ? &Reader.Diags : nullptr, + AllowCompatibleDifferences); + return false; } bool PCHValidator::ReadTargetOptions(const TargetOptions &TargetOpts, @@ -5401,8 +5391,9 @@ namespace { bool ReadLanguageOptions(const LangOptions &LangOpts, StringRef ModuleFilename, bool Complain, bool AllowCompatibleDifferences) override { - return checkLanguageOptions(ExistingLangOpts, LangOpts, ModuleFilename, - nullptr, AllowCompatibleDifferences); + checkLanguageOptions(ExistingLangOpts, LangOpts, ModuleFilename, nullptr, + AllowCompatibleDifferences); + return false; } bool ReadTargetOptions(const TargetOptions &TargetOpts, diff --git a/clang/test/Modules/explicit-build-missing-files.cpp b/clang/test/Modules/explicit-build-missing-files.cpp index 3ea881d34c6b28..4682ede5e08089 100644 --- a/clang/test/Modules/explicit-build-missing-files.cpp +++ b/clang/test/Modules/explicit-build-missing-files.cpp @@ -33,7 +33,7 @@ // RUN: %clang_cc1 -fmodules -I %t -fmodule-file=%t/b.pcm %s // RUN: not %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s -DERRORS 2>&1 | FileCheck %s --check-prefix=MISSING-B // RUN: %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm -fmodule-map-file=%t/modulemap.moved %s -// RUN: not %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm -fmodule-map-file=%t/modulemap.moved -std=c++1z %s +// RUN: %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm -fmodule-map-file=%t/modulemap.moved -std=c++1z %s // RUN: %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm -fmodule-map-file=%t/modulemap.moved -std=c++1z -Wno-module-file-config-mismatch %s -Db=a // RUN: rm %t/a.h // RUN: %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s -verify diff --git a/clang/test/Modules/load_failure.c b/clang/test/Modules/load_failure.c index 662b39b6f1874f..bc0abb46bdc2bc 100644 --- a/clang/test/Modules/load_failure.c +++ b/clang/test/Modules/load_failure.c @@ -11,11 +11,11 @@ // RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -x objective-c -fmodules-cache-path=%t -I %S/Inputs -fdisable-module-hash %s -DNONEXISTENT 2>&1 | FileCheck -check-prefix=CHECK-NONEXISTENT %s // CHECK-NONEXISTENT: load_failure.c:2:9: fatal error: module 'load_nonexistent' not found -// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -x objective-c -fmodules-cache-path=%t -I %S/Inputs -fdisable-module-hash %s -DFAILURE 2> %t.out -// RUN: FileCheck -check-prefix=CHECK-FAILURE %s < %t.out +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -x objective-c -fmodules-cache-path=%t -I %S/Inputs -fdisable-module-hash %s -DFAILURE 2> %t.out +// RUN: FileCheck -check-prefix=CHECK-WARN %s < %t.out // FIXME: Clean up diagnostic text below and give it a location -// CHECK-FAILURE: error: C99 was disabled in AST file '{{.*}}load_failure.pcm' but is currently enabled +// CHECK-WARN: warning: C99 was disabled in AST file '{{.*}}load_failure.pcm' but is currently enabled // FIXME: When we have a syntax for modules in C, use that. diff --git a/clang/test/Modules/mismatch-diagnostics.cpp b/clang/test/Modules/mismatch-diagnostics.cpp index dffd4b46a678e5..745d6ee802f8f9 100644 --- a/clang/test/Modules/mismatch-diagnostics.cpp +++ b/clang/test/Modules/mismatch-diagnostics.cpp @@ -3,31 +3,55 @@ // RUN: split-file %s %t // RUN: mkdir -p %t/prebuilt_modules // -// RUN: %clang_cc1 -triple %itanium_abi_triple \ -// RUN: -std=c++20 -fprebuilt-module-path=%t/prebuilt-modules \ -// RUN: -emit-module-interface -pthread -DBUILD_MODULE \ -// RUN: %t/mismatching_module.cppm -o \ +// RUN: %clang_cc1 -triple %itanium_abi_triple \ +// RUN: -std=c++20 -fprebuilt-module-path=%t/prebuilt-modules \ +// RUN: -emit-module-interface -pthread -DBUILD_MODULE \ +// RUN: %t/mismatching_module.cppm -o \ // RUN: %t/prebuilt_modules/mismatching_module.pcm // -// RUN: not %clang_cc1 -triple %itanium_abi_triple -std=c++20 \ -// RUN: -fprebuilt-module-path=%t/prebuilt_modules -DCHECK_MISMATCH \ -// RUN: %t/use.cpp 2>&1 | FileCheck %s +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 \ +// RUN: -fprebuilt-module-path=%t/prebuilt_modules -DCHECK_MISMATCH \ +// RUN: %t/use.cpp 2>&1 | FileCheck %t/use.cpp // Test again with reduced BMI. -// RUN: %clang_cc1 -triple %itanium_abi_triple \ -// RUN: -std=c++20 -fprebuilt-module-path=%t/prebuilt-modules \ -// RUN: -emit-reduced-module-interface -pthread -DBUILD_MODULE \ -// RUN: %t/mismatching_module.cppm -o \ +// RUN: %clang_cc1 -triple %itanium_abi_triple \ +// RUN: -std=c++20 -fprebuilt-module-path=%t/prebuilt-modules \ +// RUN: -emit-reduced-module-interface -pthread -DBUILD_MODULE \ +// RUN: %t/mismatching_module.cppm -o \ // RUN: %t/prebuilt_modules/mismatching_module.pcm // -// RUN: not %clang_cc1 -triple %itanium_abi_triple -std=c++20 \ -// RUN: -fprebuilt-module-path=%t/prebuilt_modules -DCHECK_MISMATCH \ -// RUN: %t/use.cpp 2>&1 | FileCheck %s +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 \ +// RUN: -fprebuilt-module-path=%t/prebuilt_modules -DCHECK_MISMATCH \ +// RUN: %t/use.cpp 2>&1 | FileCheck %t/use.cpp +// +// RUN: %clang_cc1 -triple %itanium_abi_triple \ +// RUN: -std=c++20 -fprebuilt-module-path=%t/prebuilt-modules \ +// RUN: -emit-module-interface -pthread -DBUILD_MODULE \ +// RUN: %t/mismatching_module.cppm -o \ +// RUN: %t/prebuilt_modules/mismatching_module.pcm +// +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 \ +// RUN: -fprebuilt-module-path=%t/prebuilt_modules -DCHECK_MISMATCH \ +// RUN: -Wno-module-mismatched-option %t/use.cpp 2>&1 | FileCheck %t/use.cpp \ +// RUN: --check-prefix=NOWARN --allow-empty + +// Test again with reduced BMI. +// RUN: %clang_cc1 -triple %itanium_abi_triple \ +// RUN: -std=c++20 -fprebuilt-module-path=%t/prebuilt-modules \ +// RUN: -emit-reduced-module-interface -pthread -DBUILD_MODULE \ +// RUN: %t/mismatching_module.cppm -o \ +// RUN: %t/prebuilt_modules/mismatching_module.pcm +// +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 \ +// RUN: -fprebuilt-module-path=%t/prebuilt_modules -DCHECK_MISMATCH \ +// RUN: -Wno-module-mismatched-option %t/use.cpp 2>&1 | FileCheck %t/use.cpp \ +// RUN: --check-prefix=NOWARN --allow-empty //--- mismatching_module.cppm export module mismatching_module; //--- use.cpp import mismatching_module; -// CHECK: error: POSIX thread support was enabled in AST file '{{.*[/|\\\\]}}mismatching_module.pcm' but is currently disabled -// CHECK-NEXT: module file {{.*[/|\\\\]}}mismatching_module.pcm cannot be loaded due to a configuration mismatch with the current compilation +// CHECK: warning: POSIX thread support was enabled in AST file '{{.*[/|\\\\]}}mismatching_module.pcm' but is currently disabled + +// NOWARN-NOT: warning diff --git a/clang/test/Modules/module-feature.m b/clang/test/Modules/module-feature.m index 4926d26515f860..bbc9b0220f761c 100644 --- a/clang/test/Modules/module-feature.m +++ b/clang/test/Modules/module-feature.m @@ -6,9 +6,9 @@ // RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -fmodule-feature f2 -fmodule-feature f1 -F %S/Inputs %s -Rmodule-build 2>&1 | FileCheck %s -allow-empty -check-prefix=ALREADY_BUILT // ALREADY_BUILT-NOT: building module -// Errors if we try to force the load. +// Warns if we try to force the load. // RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t.nohash -fimplicit-module-maps -fdisable-module-hash -fmodule-feature f1 -fmodule-feature f2 -F %S/Inputs %s -verify -Rmodule-build -// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t.nohash -fimplicit-module-maps -fdisable-module-hash -fmodule-feature f2 -F %S/Inputs %s 2>&1 | FileCheck %s -check-prefix=DIFFERS -// DIFFERS: error: module features differs +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t.nohash -fimplicit-module-maps -fdisable-module-hash -fmodule-feature f2 -F %S/Inputs %s 2>&1 | FileCheck %s -check-prefix=DIFFERS +// DIFFERS: warning: module features differs @import Module; // expected-remark {{building module 'Module'}} expected-remark {{finished}} diff --git a/clang/test/Modules/pr62359.cppm b/clang/test/Modules/pr62359.cppm index 7d9d3eec26cca7..f459d46f378618 100644 --- a/clang/test/Modules/pr62359.cppm +++ b/clang/test/Modules/pr62359.cppm @@ -3,9 +3,9 @@ // RUN: split-file %s %t // // RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/Hello.cppm -o %t/Hello.pcm -// RUN: not %clang_cc1 -std=c++20 -fopenmp %t/use.cpp -fmodule-file=hello=%t/Hello.pcm -fsyntax-only \ +// RUN: %clang_cc1 -std=c++20 -fopenmp %t/use.cpp -fmodule-file=hello=%t/Hello.pcm -fsyntax-only \ // RUN: 2>&1 | FileCheck %t/use.cpp -// RUN: not %clang_cc1 -std=c++20 -fopenmp %t/use2.cpp -fmodule-file=hello=%t/Hello.pcm -fsyntax-only \ +// RUN: %clang_cc1 -std=c++20 -fopenmp %t/use2.cpp -fmodule-file=hello=%t/Hello.pcm -fsyntax-only \ // RUN: 2>&1 | FileCheck %t/use2.cpp // // RUN: %clang_cc1 -std=c++20 -fopenmp -emit-module-interface %t/Hello.cppm -o %t/Hello.pcm @@ -18,9 +18,9 @@ // RUN: split-file %s %t // // RUN: %clang_cc1 -std=c++20 -emit-reduced-module-interface %t/Hello.cppm -o %t/Hello.pcm -// RUN: not %clang_cc1 -std=c++20 -fopenmp %t/use.cpp -fmodule-file=hello=%t/Hello.pcm -fsyntax-only \ +// RUN: %clang_cc1 -std=c++20 -fopenmp %t/use.cpp -fmodule-file=hello=%t/Hello.pcm -fsyntax-only \ // RUN: 2>&1 | FileCheck %t/use.cpp -// RUN: not %clang_cc1 -std=c++20 -fopenmp %t/use2.cpp -fmodule-file=hello=%t/Hello.pcm -fsyntax-only \ +// RUN: %clang_cc1 -std=c++20 -fopenmp %t/use2.cpp -fmodule-file=hello=%t/Hello.pcm -fsyntax-only \ // RUN: 2>&1 | FileCheck %t/use2.cpp // // RUN: %clang_cc1 -std=c++20 -fopenmp -emit-reduced-module-interface %t/Hello.cppm -o %t/Hello.pcm @@ -56,4 +56,3 @@ int use2() { } // CHECK: OpenMP{{.*}}differs in AST file '{{.*}}Hello.pcm' vs. current file -// CHECK: use of undeclared identifier 'pragma' diff --git a/clang/test/Modules/prebuilt-implicit-modules.m b/clang/test/Modules/prebuilt-implicit-modules.m index dc4fb55cb17a55..1bae214eb901f7 100644 --- a/clang/test/Modules/prebuilt-implicit-modules.m +++ b/clang/test/Modules/prebuilt-implicit-modules.m @@ -25,7 +25,7 @@ // RUN: mkdir -p %t2 // RUN: %clang_cc1 -x objective-c -fmodules %S/Inputs/prebuilt-implicit-module/module.modulemap -emit-module -fmodule-name=module_a -fmodules-cache-path=%t // RUN: %clang_cc1 -x objective-c -fmodules %S/Inputs/prebuilt-implicit-module/module.modulemap -emit-module -fmodule-name=module_a -o %t/module_a.pcm -fno-signed-char -// RUN: not %clang_cc1 -x objective-c %s -I%S/Inputs/prebuilt-implicit-module -fmodules -fmodule-map-file=%S/Inputs/prebuilt-implicit-module/module.modulemap -fprebuilt-implicit-modules -fprebuilt-module-path=%t -fmodules-cache-path=%t2 +// RUN: %clang_cc1 -x objective-c %s -I%S/Inputs/prebuilt-implicit-module -fmodules -fmodule-map-file=%S/Inputs/prebuilt-implicit-module/module.modulemap -fprebuilt-implicit-modules -fprebuilt-module-path=%t -fmodules-cache-path=%t2 // RUN: find %t2 -name "module_a*.pcm" | not grep module_a // expected-no-diagnostics diff --git a/clang/test/PCH/arc.m b/clang/test/PCH/arc.m index e4ad71a469b956..d714512b48d7d7 100644 --- a/clang/test/PCH/arc.m +++ b/clang/test/PCH/arc.m @@ -6,10 +6,10 @@ // RUN: %clang_cc1 -emit-pch -fblocks -triple x86_64-apple-darwin11 -fobjc-arc -x objective-c-header -o %t %S/Inputs/arc.h // RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin11 -fobjc-arc -include-pch %t -emit-llvm-only %s -// Test error when pch's -fobjc-arc state is different. -// RUN: not %clang_cc1 -fblocks -triple x86_64-apple-darwin11 -include-pch %t -emit-llvm-only %s 2>&1 | FileCheck -check-prefix=CHECK-ERR1 %s +// Test warning when pch's -fobjc-arc state is different. +// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin11 -include-pch %t -emit-llvm-only %s 2>&1 | FileCheck -check-prefix=CHECK-ERR1 %s // RUN: %clang_cc1 -emit-pch -fblocks -triple x86_64-apple-darwin11 -x objective-c-header -o %t %S/Inputs/arc.h -// RUN: not %clang_cc1 -fblocks -triple x86_64-apple-darwin11 -fobjc-arc -include-pch %t -emit-llvm-only %s 2>&1 | FileCheck -check-prefix=CHECK-ERR2 %s +// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin11 -fobjc-arc -include-pch %t -emit-llvm-only %s 2>&1 | FileCheck -check-prefix=CHECK-ERR2 %s array0 a0; array1 a1; diff --git a/clang/test/PCH/no-validate-pch.cl b/clang/test/PCH/no-validate-pch.cl index aa228ee2052192..c5a500103091f6 100644 --- a/clang/test/PCH/no-validate-pch.cl +++ b/clang/test/PCH/no-validate-pch.cl @@ -16,7 +16,7 @@ // CHECK: note: previous definition is here // CHECK: #define X 4 -// CHECK-VAL: error: __OPTIMIZE__ predefined macro was enabled in AST file '{{.*}}' but is currently disabled +// CHECK-VAL: warning: __OPTIMIZE__ predefined macro was enabled in AST file '{{.*}}' but is currently disabled // CHECK-VAL: error: definition of macro 'X' differs between the AST file '{{.*}}' ('4') and the command line ('5') void test(void) { diff --git a/clang/test/PCH/pch-dir.c b/clang/test/PCH/pch-dir.c index fd7d24f9f83ff4..e67d28b1e8567e 100644 --- a/clang/test/PCH/pch-dir.c +++ b/clang/test/PCH/pch-dir.c @@ -11,11 +11,11 @@ // RUN: %clang -x c++ -include %t.h -std=c++98 -fsyntax-only %s -Xclang -print-stats 2> %t.cpplog // RUN: FileCheck -check-prefix=CHECK-CPP %s < %t.cpplog -// RUN: not %clang -x c++ -std=c++11 -include %t.h -fsyntax-only %s 2> %t.cpp11log -// RUN: FileCheck -check-prefix=CHECK-NO-SUITABLE %s < %t.cpp11log +// RUN: %clang -x c++ -std=c++11 -include %t.h -fsyntax-only %s 2> %t.cpp11log +// RUN: FileCheck %s --check-prefix=CHECK-OPT-DIFF < %t.cpp11log -// RUN: not %clang -include %t.h -fsyntax-only %s 2> %t.missinglog2 -// RUN: FileCheck -check-prefix=CHECK-NO-SUITABLE %s < %t.missinglog2 +// RUN: %clang -include %t.h -fsyntax-only %s 2> %t.missinglog2 +// RUN: FileCheck --check-prefix=CHECK-OPT-DIFF %s < %t.missinglog2 // RUN: not %clang -include %t.h -DFOO=foo -DBAR=bar -fsyntax-only %s 2> %t.missinglog2 // RUN: FileCheck -check-prefix=CHECK-NO-SUITABLE %s < %t.missinglog2 @@ -41,6 +41,8 @@ int get(void) { #endif } +// CHECK-OPT-DIFF: warning: {{.*}} was disabled in AST file{{.*}} but is currently enabled + // CHECK-NO-SUITABLE: no suitable precompiled header file found in directory // CHECK-IGNORED-DIR: precompiled header directory '{{.*}}pch-dir.c.tmp.x.h.gch' was ignored because it contains no clang PCH files >From a5265801086897dfe0770c9552acd6d70b41bd92 Mon Sep 17 00:00:00 2001 From: Vassil Vassilev <v.g.vassi...@gmail.com> Date: Sun, 7 Jan 2018 15:16:11 +0200 Subject: [PATCH 2/2] D41416: [modules] [pch] Do not deserialize all lazy template specializations when looking for one. --- clang/include/clang/AST/DeclTemplate.h | 36 ++++++++- clang/lib/AST/DeclTemplate.cpp | 98 +++++++++++++++++------ clang/lib/AST/ODRHash.cpp | 15 ++++ clang/lib/Serialization/ASTReader.cpp | 25 ++++-- clang/lib/Serialization/ASTReaderDecl.cpp | 44 ++++++---- clang/lib/Serialization/ASTWriter.cpp | 21 ++++- clang/lib/Serialization/ASTWriterDecl.cpp | 80 ++++++++++++++---- clang/test/Modules/cxx-templates.cpp | 8 +- clang/test/Modules/odr_hash.cpp | 4 +- 9 files changed, 258 insertions(+), 73 deletions(-) diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index e4bf54c3d77b7f..7d707ed45cf5f6 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -262,6 +262,9 @@ class TemplateArgumentList final TemplateArgumentList(const TemplateArgumentList &) = delete; TemplateArgumentList &operator=(const TemplateArgumentList &) = delete; + /// Create hash for the given arguments. + static unsigned ComputeODRHash(ArrayRef<TemplateArgument> Args); + /// Create a new template argument list that copies the given set of /// template arguments. static TemplateArgumentList *CreateCopy(ASTContext &Context, @@ -735,6 +738,26 @@ class RedeclarableTemplateDecl : public TemplateDecl, } void anchor() override; + struct LazySpecializationInfo { + GlobalDeclID DeclID = GlobalDeclID(); + unsigned ODRHash = ~0U; + bool IsPartial = false; + LazySpecializationInfo(GlobalDeclID ID, unsigned Hash = ~0U, + bool Partial = false) + : DeclID(ID), ODRHash(Hash), IsPartial(Partial) {} + LazySpecializationInfo() {} + bool operator<(const LazySpecializationInfo &Other) const { + return DeclID < Other.DeclID; + } + bool operator==(const LazySpecializationInfo &Other) const { + assert((DeclID != Other.DeclID || ODRHash == Other.ODRHash) && + "Hashes differ!"); + assert((DeclID != Other.DeclID || IsPartial == Other.IsPartial) && + "Both must be the same kinds!"); + return DeclID == Other.DeclID; + } + }; + protected: template <typename EntryType> struct SpecEntryTraits { using DeclType = EntryType; @@ -775,7 +798,12 @@ class RedeclarableTemplateDecl : public TemplateDecl, return SpecIterator<EntryType>(isEnd ? Specs.end() : Specs.begin()); } - void loadLazySpecializationsImpl() const; + void loadLazySpecializationsImpl(bool OnlyPartial = false) const; + + void loadLazySpecializationsImpl(llvm::ArrayRef<TemplateArgument> Args, + TemplateParameterList *TPL = nullptr) const; + + Decl *loadLazySpecializationImpl(LazySpecializationInfo &LazySpecInfo) const; template <class EntryType, typename ...ProfileArguments> typename SpecEntryTraits<EntryType>::DeclType* @@ -802,7 +830,7 @@ class RedeclarableTemplateDecl : public TemplateDecl, /// /// The first value in the array is the number of specializations/partial /// specializations that follow. - GlobalDeclID *LazySpecializations = nullptr; + LazySpecializationInfo *LazySpecializations = nullptr; }; /// Pointer to the common data shared by all declarations of this @@ -2283,7 +2311,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl { friend class TemplateDeclInstantiator; /// Load any lazily-loaded specializations from the external source. - void LoadLazySpecializations() const; + void LoadLazySpecializations(bool OnlyPartial = false) const; /// Get the underlying class declarations of the template. CXXRecordDecl *getTemplatedDecl() const { @@ -3033,7 +3061,7 @@ class VarTemplateDecl : public RedeclarableTemplateDecl { friend class ASTDeclWriter; /// Load any lazily-loaded specializations from the external source. - void LoadLazySpecializations() const; + void LoadLazySpecializations(bool OnlyPartial = false) const; /// Get the underlying variable declarations of the template. VarDecl *getTemplatedDecl() const { diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index a221d619672b38..d0e16c30881be2 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -16,7 +16,9 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/ExternalASTSource.h" +#include "clang/AST/ODRHash.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" @@ -351,17 +353,44 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c return Common; } -void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const { +void RedeclarableTemplateDecl::loadLazySpecializationsImpl( + bool OnlyPartial /*=false*/) const { // Grab the most recent declaration to ensure we've loaded any lazy // redeclarations of this template. CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr(); - if (CommonBasePtr->LazySpecializations) { - ASTContext &Context = getASTContext(); - GlobalDeclID *Specs = CommonBasePtr->LazySpecializations; - CommonBasePtr->LazySpecializations = nullptr; - unsigned SpecSize = (*Specs++).getRawValue(); - for (unsigned I = 0; I != SpecSize; ++I) - (void)Context.getExternalSource()->GetExternalDecl(Specs[I]); + if (auto *Specs = CommonBasePtr->LazySpecializations) { + if (!OnlyPartial) + CommonBasePtr->LazySpecializations = nullptr; + unsigned N = Specs[0].DeclID.getRawValue(); + for (unsigned I = 0; I != N; ++I) { + // Skip over already loaded specializations. + if (!Specs[I + 1].ODRHash) + continue; + if (!OnlyPartial || Specs[I + 1].IsPartial) + (void)loadLazySpecializationImpl(Specs[I + 1]); + } + } +} + +Decl *RedeclarableTemplateDecl::loadLazySpecializationImpl( + LazySpecializationInfo &LazySpecInfo) const { + GlobalDeclID ID = LazySpecInfo.DeclID; + assert(ID.isValid() && "Loading already loaded specialization!"); + // Note that we loaded the specialization. + LazySpecInfo.DeclID = GlobalDeclID(); + LazySpecInfo.ODRHash = LazySpecInfo.IsPartial = 0; + return getASTContext().getExternalSource()->GetExternalDecl(ID); +} + +void RedeclarableTemplateDecl::loadLazySpecializationsImpl( + ArrayRef<TemplateArgument> Args, TemplateParameterList *TPL) const { + CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr(); + if (auto *Specs = CommonBasePtr->LazySpecializations) { + unsigned Hash = TemplateArgumentList::ComputeODRHash(Args); + unsigned N = Specs[0].DeclID.getRawValue(); + for (unsigned I = 0; I != N; ++I) + if (Specs[I + 1].ODRHash && Specs[I + 1].ODRHash == Hash) + (void)loadLazySpecializationImpl(Specs[I + 1]); } } @@ -372,6 +401,8 @@ RedeclarableTemplateDecl::findSpecializationImpl( ProfileArguments&&... ProfileArgs) { using SETraits = SpecEntryTraits<EntryType>; + loadLazySpecializationsImpl(std::forward<ProfileArguments>(ProfileArgs)...); + llvm::FoldingSetNodeID ID; EntryType::Profile(ID, std::forward<ProfileArguments>(ProfileArgs)..., getASTContext()); @@ -387,10 +418,14 @@ void RedeclarableTemplateDecl::addSpecializationImpl( if (InsertPos) { #ifndef NDEBUG + auto Args = SETraits::getTemplateArgs(Entry); + // Due to hash collisions, it can happen that we load another template + // specialization with the same hash. This is fine, as long as the next + // call to findSpecializationImpl does not find a matching Decl for the + // template arguments. + loadLazySpecializationsImpl(Args); void *CorrectInsertPos; - assert(!findSpecializationImpl(Specializations, - CorrectInsertPos, - SETraits::getTemplateArgs(Entry)) && + assert(!findSpecializationImpl(Specializations, CorrectInsertPos, Args) && InsertPos == CorrectInsertPos && "given incorrect InsertPos for specialization"); #endif @@ -448,12 +483,14 @@ FunctionTemplateDecl::getSpecializations() const { FunctionDecl * FunctionTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args, void *&InsertPos) { - return findSpecializationImpl(getSpecializations(), InsertPos, Args); + auto *Common = getCommonPtr(); + return findSpecializationImpl(Common->Specializations, InsertPos, Args); } void FunctionTemplateDecl::addSpecialization( FunctionTemplateSpecializationInfo *Info, void *InsertPos) { - addSpecializationImpl<FunctionTemplateDecl>(getSpecializations(), Info, + auto *Common = getCommonPtr(); + addSpecializationImpl<FunctionTemplateDecl>(Common->Specializations, Info, InsertPos); } @@ -513,8 +550,9 @@ ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C, DeclarationName(), nullptr, nullptr); } -void ClassTemplateDecl::LoadLazySpecializations() const { - loadLazySpecializationsImpl(); +void ClassTemplateDecl::LoadLazySpecializations( + bool OnlyPartial /*=false*/) const { + loadLazySpecializationsImpl(OnlyPartial); } llvm::FoldingSetVector<ClassTemplateSpecializationDecl> & @@ -525,7 +563,7 @@ ClassTemplateDecl::getSpecializations() const { llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> & ClassTemplateDecl::getPartialSpecializations() const { - LoadLazySpecializations(); + LoadLazySpecializations(/*PartialOnly = */ true); return getCommonPtr()->PartialSpecializations; } @@ -539,12 +577,15 @@ ClassTemplateDecl::newCommon(ASTContext &C) const { ClassTemplateSpecializationDecl * ClassTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args, void *&InsertPos) { - return findSpecializationImpl(getSpecializations(), InsertPos, Args); + auto *Common = getCommonPtr(); + return findSpecializationImpl(Common->Specializations, InsertPos, Args); } void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D, void *InsertPos) { - addSpecializationImpl<ClassTemplateDecl>(getSpecializations(), D, InsertPos); + auto *Common = getCommonPtr(); + addSpecializationImpl<ClassTemplateDecl>(Common->Specializations, D, + InsertPos); } ClassTemplatePartialSpecializationDecl * @@ -897,6 +938,14 @@ TemplateArgumentList::CreateCopy(ASTContext &Context, return new (Mem) TemplateArgumentList(Args); } +unsigned TemplateArgumentList::ComputeODRHash(ArrayRef<TemplateArgument> Args) { + ODRHash Hasher; + for (TemplateArgument TA : Args) + Hasher.AddTemplateArgument(TA); + + return Hasher.CalculateHash(); +} + FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create( ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template, TemplateSpecializationKind TSK, TemplateArgumentList *TemplateArgs, @@ -1262,8 +1311,9 @@ VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C, DeclarationName(), nullptr, nullptr); } -void VarTemplateDecl::LoadLazySpecializations() const { - loadLazySpecializationsImpl(); +void VarTemplateDecl::LoadLazySpecializations( + bool OnlyPartial /*=false*/) const { + loadLazySpecializationsImpl(OnlyPartial); } llvm::FoldingSetVector<VarTemplateSpecializationDecl> & @@ -1274,7 +1324,7 @@ VarTemplateDecl::getSpecializations() const { llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> & VarTemplateDecl::getPartialSpecializations() const { - LoadLazySpecializations(); + LoadLazySpecializations(/*PartialOnly = */ true); return getCommonPtr()->PartialSpecializations; } @@ -1288,12 +1338,14 @@ VarTemplateDecl::newCommon(ASTContext &C) const { VarTemplateSpecializationDecl * VarTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args, void *&InsertPos) { - return findSpecializationImpl(getSpecializations(), InsertPos, Args); + auto *Common = getCommonPtr(); + return findSpecializationImpl(Common->Specializations, InsertPos, Args); } void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D, void *InsertPos) { - addSpecializationImpl<VarTemplateDecl>(getSpecializations(), D, InsertPos); + auto *Common = getCommonPtr(); + addSpecializationImpl<VarTemplateDecl>(Common->Specializations, D, InsertPos); } VarTemplatePartialSpecializationDecl * diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index 1929314363817a..a8a3a5200d61ed 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -828,6 +828,21 @@ void ODRHash::AddDecl(const Decl *D) { for (const TemplateArgument &TA : List.asArray()) AddTemplateArgument(TA); } + + // If this was a specialization we should take into account its template + // arguments. This helps to reduce collisions coming when visiting template + // specialization types (eg. when processing type template arguments). + ArrayRef<TemplateArgument> Args; + if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) + Args = CTSD->getTemplateArgs().asArray(); + else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) + Args = VTSD->getTemplateArgs().asArray(); + else if (auto *FD = dyn_cast<FunctionDecl>(D)) + if (FD->getTemplateSpecializationArgs()) + Args = FD->getTemplateSpecializationArgs()->asArray(); + + for (auto &TA : Args) + AddTemplateArgument(TA); } namespace { diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 1c94e8e9a212a9..8bba98ef33302b 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -7640,14 +7640,23 @@ void ASTReader::CompleteRedeclChain(const Decl *D) { } } - if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) - CTSD->getSpecializedTemplate()->LoadLazySpecializations(); - if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) - VTSD->getSpecializedTemplate()->LoadLazySpecializations(); - if (auto *FD = dyn_cast<FunctionDecl>(D)) { - if (auto *Template = FD->getPrimaryTemplate()) - Template->LoadLazySpecializations(); - } + RedeclarableTemplateDecl *Template = nullptr; + ArrayRef<TemplateArgument> Args; + if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { + Template = CTSD->getSpecializedTemplate(); + Args = CTSD->getTemplateArgs().asArray(); + } else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) { + Template = VTSD->getSpecializedTemplate(); + Args = VTSD->getTemplateArgs().asArray(); + } else if (auto *FD = dyn_cast<FunctionDecl>(D)) { + if (auto *Tmplt = FD->getPrimaryTemplate()) { + Template = Tmplt; + Args = FD->getTemplateSpecializationArgs()->asArray(); + } + } + + if (Template) + Template->loadLazySpecializationsImpl(Args); } CXXCtorInitializer ** diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 33fcddbbdb2f15..6816bbcd45dcbe 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -187,9 +187,19 @@ class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> { std::string readString() { return Record.readString(); } - void readDeclIDList(SmallVectorImpl<GlobalDeclID> &IDs) { + using LazySpecializationInfo = + RedeclarableTemplateDecl::LazySpecializationInfo; + + LazySpecializationInfo ReadLazySpecializationInfo() { + GlobalDeclID ID = readDeclID(); + unsigned Hash = Record.readInt(); + bool IsPartial = Record.readInt(); + return LazySpecializationInfo(ID, Hash, IsPartial); + } + + void readDeclIDList(SmallVectorImpl<LazySpecializationInfo> &IDs) { for (unsigned I = 0, Size = Record.readInt(); I != Size; ++I) - IDs.push_back(readDeclID()); + IDs.push_back(ReadLazySpecializationInfo()); } Decl *readDecl() { return Record.readDecl(); } @@ -285,7 +295,8 @@ class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> { ThisDeclID(thisDeclID), ThisDeclLoc(ThisDeclLoc) {} template <typename T> - static void AddLazySpecializations(T *D, SmallVectorImpl<GlobalDeclID> &IDs) { + static void + AddLazySpecializations(T *D, SmallVectorImpl<LazySpecializationInfo> &IDs) { if (IDs.empty()) return; @@ -295,14 +306,13 @@ class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> { auto *&LazySpecializations = D->getCommonPtr()->LazySpecializations; if (auto &Old = LazySpecializations) { - IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0].getRawValue()); + IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0].DeclID.getRawValue()); llvm::sort(IDs); IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end()); } - - auto *Result = new (C) GlobalDeclID[1 + IDs.size()]; - *Result = GlobalDeclID(IDs.size()); - + auto *Result = new (C) + RedeclarableTemplateDecl::LazySpecializationInfo[1 + IDs.size()]; + Result->DeclID = GlobalDeclID(IDs.size()); std::copy(IDs.begin(), IDs.end(), Result + 1); LazySpecializations = Result; @@ -335,7 +345,9 @@ class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> { void ReadFunctionDefinition(FunctionDecl *FD); void Visit(Decl *D); - void UpdateDecl(Decl *D, SmallVectorImpl<GlobalDeclID> &); + void UpdateDecl( + Decl *D, + SmallVectorImpl<RedeclarableTemplateDecl::LazySpecializationInfo> &); static void setNextObjCCategory(ObjCCategoryDecl *Cat, ObjCCategoryDecl *Next) { @@ -2456,7 +2468,7 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) { if (ThisDeclID == Redecl.getFirstID()) { // This ClassTemplateDecl owns a CommonPtr; read it to keep track of all of // the specializations. - SmallVector<GlobalDeclID, 32> SpecIDs; + SmallVector<LazySpecializationInfo, 32> SpecIDs; readDeclIDList(SpecIDs); ASTDeclReader::AddLazySpecializations(D, SpecIDs); } @@ -2484,7 +2496,7 @@ void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) { if (ThisDeclID == Redecl.getFirstID()) { // This VarTemplateDecl owns a CommonPtr; read it to keep track of all of // the specializations. - SmallVector<GlobalDeclID, 32> SpecIDs; + SmallVector<LazySpecializationInfo, 32> SpecIDs; readDeclIDList(SpecIDs); ASTDeclReader::AddLazySpecializations(D, SpecIDs); } @@ -2585,7 +2597,7 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { if (ThisDeclID == Redecl.getFirstID()) { // This FunctionTemplateDecl owns a CommonPtr; read it. - SmallVector<GlobalDeclID, 32> SpecIDs; + SmallVector<LazySpecializationInfo, 32> SpecIDs; readDeclIDList(SpecIDs); ASTDeclReader::AddLazySpecializations(D, SpecIDs); } @@ -4286,7 +4298,9 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { ProcessingUpdatesRAIIObj ProcessingUpdates(*this); DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID); - SmallVector<GlobalDeclID, 8> PendingLazySpecializationIDs; + using LazySpecializationInfo = + RedeclarableTemplateDecl::LazySpecializationInfo; + llvm::SmallVector<LazySpecializationInfo, 8> PendingLazySpecializationIDs; if (UpdI != DeclUpdateOffsets.end()) { auto UpdateOffsets = std::move(UpdI->second); @@ -4563,7 +4577,7 @@ static void forAllLaterRedecls(DeclT *D, Fn F) { void ASTDeclReader::UpdateDecl( Decl *D, - llvm::SmallVectorImpl<GlobalDeclID> &PendingLazySpecializationIDs) { + SmallVectorImpl<LazySpecializationInfo> &PendingLazySpecializationIDs) { while (Record.getIdx() < Record.size()) { switch ((DeclUpdateKind)Record.readInt()) { case UPD_CXX_ADDED_IMPLICIT_MEMBER: { @@ -4576,7 +4590,7 @@ void ASTDeclReader::UpdateDecl( case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: // It will be added to the template's lazy specialization set. - PendingLazySpecializationIDs.push_back(readDeclID()); + PendingLazySpecializationIDs.push_back(ReadLazySpecializationInfo()); break; case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: { diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 016d1d4acad137..455e8f0e749435 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -5796,12 +5796,29 @@ void ASTWriter::WriteDeclUpdatesBlocks(ASTContext &Context, switch (Kind) { case UPD_CXX_ADDED_IMPLICIT_MEMBER: - case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: assert(Update.getDecl() && "no decl to add?"); Record.AddDeclRef(Update.getDecl()); break; - + case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: { + const Decl *Spec = Update.getDecl(); + assert(Spec && "no decl to add?"); + Record.AddDeclRef(Spec); + ArrayRef<TemplateArgument> Args; + if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(Spec)) + Args = CTSD->getTemplateArgs().asArray(); + else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(Spec)) + Args = VTSD->getTemplateArgs().asArray(); + else if (auto *FD = dyn_cast<FunctionDecl>(Spec)) + Args = FD->getTemplateSpecializationArgs()->asArray(); + assert(Args.size()); + Record.push_back(TemplateArgumentList::ComputeODRHash(Args)); + bool IsPartialSpecialization = + isa<ClassTemplatePartialSpecializationDecl>(Spec) || + isa<VarTemplatePartialSpecializationDecl>(Spec); + Record.push_back(IsPartialSpecialization); + break; + } case UPD_CXX_ADDED_FUNCTION_DEFINITION: case UPD_CXX_ADDED_VAR_DEFINITION: break; diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index ad357e30d57529..71a9bd1aefade6 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -177,11 +177,12 @@ namespace clang { Record.AddSourceLocation(typeParams->getRAngleLoc()); } - /// Add to the record the first declaration from each module file that - /// provides a declaration of D. The intent is to provide a sufficient - /// set such that reloading this set will load all current redeclarations. - void AddFirstDeclFromEachModule(const Decl *D, bool IncludeLocal) { - llvm::MapVector<ModuleFile*, const Decl*> Firsts; + /// Collect the first declaration from each module file that provides a + /// declaration of D. + void CollectFirstDeclFromEachModule( + const Decl *D, bool IncludeLocal, + llvm::MapVector<ModuleFile *, const Decl *> &Firsts) { + // FIXME: We can skip entries that we know are implied by others. for (const Decl *R = D->getMostRecentDecl(); R; R = R->getPreviousDecl()) { if (R->isFromASTFile()) @@ -189,10 +190,49 @@ namespace clang { else if (IncludeLocal) Firsts[nullptr] = R; } + } + + /// Add to the record the first declaration from each module file that + /// provides a declaration of D. The intent is to provide a sufficient + /// set such that reloading this set will load all current redeclarations. + void AddFirstDeclFromEachModule(const Decl *D, bool IncludeLocal) { + llvm::MapVector<ModuleFile *, const Decl *> Firsts; + CollectFirstDeclFromEachModule(D, IncludeLocal, Firsts); + for (const auto &F : Firsts) Record.AddDeclRef(F.second); } + /// Add to the record the first template specialization from each module + /// file that provides a declaration of D. We store the DeclId and an + /// ODRHash of the template arguments of D which should provide enough + /// information to load D only if the template instantiator needs it. + void AddFirstSpecializationDeclFromEachModule(const Decl *D, + bool IncludeLocal) { + assert(isa<ClassTemplateSpecializationDecl>(D) || + isa<VarTemplateSpecializationDecl>(D) || + isa<FunctionDecl>(D) && "Must not be called with other decls"); + llvm::MapVector<ModuleFile *, const Decl *> Firsts; + CollectFirstDeclFromEachModule(D, IncludeLocal, Firsts); + + for (const auto &F : Firsts) { + Record.AddDeclRef(F.second); + ArrayRef<TemplateArgument> Args; + if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) + Args = CTSD->getTemplateArgs().asArray(); + else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) + Args = VTSD->getTemplateArgs().asArray(); + else if (auto *FD = dyn_cast<FunctionDecl>(D)) + Args = FD->getTemplateSpecializationArgs()->asArray(); + assert(Args.size()); + Record.push_back(TemplateArgumentList::ComputeODRHash(Args)); + bool IsPartialSpecialization = + isa<ClassTemplatePartialSpecializationDecl>(D) || + isa<VarTemplatePartialSpecializationDecl>(D); + Record.push_back(IsPartialSpecialization); + } + } + /// Get the specialization decl from an entry in the specialization list. template <typename EntryType> typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType * @@ -205,8 +245,9 @@ namespace clang { decltype(T::PartialSpecializations) &getPartialSpecializations(T *Common) { return Common->PartialSpecializations; } - ArrayRef<Decl> getPartialSpecializations(FunctionTemplateDecl::Common *) { - return {}; + MutableArrayRef<FunctionTemplateSpecializationInfo> + getPartialSpecializations(FunctionTemplateDecl::Common *) { + return std::nullopt; } template<typename DeclTy> @@ -222,9 +263,12 @@ namespace clang { assert(!Common->LazySpecializations); } - ArrayRef<GlobalDeclID> LazySpecializations; + using LazySpecializationInfo = + RedeclarableTemplateDecl::LazySpecializationInfo; + ArrayRef<LazySpecializationInfo> LazySpecializations; if (auto *LS = Common->LazySpecializations) - LazySpecializations = llvm::ArrayRef(LS + 1, LS[0].getRawValue()); + LazySpecializations = + llvm::ArrayRef(LS + 1, LS[0].DeclID.getRawValue()); // Add a slot to the record for the number of specializations. unsigned I = Record.size(); @@ -240,14 +284,20 @@ namespace clang { for (auto *D : Specs) { assert(D->isCanonicalDecl() && "non-canonical decl in set"); - AddFirstDeclFromEachModule(D, /*IncludeLocal*/true); + AddFirstSpecializationDeclFromEachModule(D, /*IncludeLocal*/ true); + } + for (auto &SpecInfo : LazySpecializations) { + Record.push_back(SpecInfo.DeclID.getRawValue()); + Record.push_back(SpecInfo.ODRHash); + Record.push_back(SpecInfo.IsPartial); } - Record.append( - DeclIDIterator<GlobalDeclID, DeclID>(LazySpecializations.begin()), - DeclIDIterator<GlobalDeclID, DeclID>(LazySpecializations.end())); - // Update the size entry we added earlier. - Record[I] = Record.size() - I - 1; + // Update the size entry we added earlier. We linerized the + // LazySpecializationInfo members and we need to adjust the size as we + // will read them always together. + assert((Record.size() - I - 1) % 3 == 0 && + "Must be divisible by LazySpecializationInfo count!"); + Record[I] = (Record.size() - I - 1) / 3; } /// Ensure that this template specialization is associated with the specified diff --git a/clang/test/Modules/cxx-templates.cpp b/clang/test/Modules/cxx-templates.cpp index b7d5741e69af61..e10ba7c2ac3ef2 100644 --- a/clang/test/Modules/cxx-templates.cpp +++ b/clang/test/Modules/cxx-templates.cpp @@ -251,7 +251,7 @@ namespace Std { // CHECK-DUMP: ClassTemplateDecl {{.*}} <{{.*[/\\]}}cxx-templates-common.h:1:1, {{.*}}> col:{{.*}} in cxx_templates_common SomeTemplate // CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate -// CHECK-DUMP-NEXT: TemplateArgument type 'char[2]' +// CHECK-DUMP-NEXT: TemplateArgument type 'char[1]' // CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} SomeTemplate definition // CHECK-DUMP-NEXT: DefinitionData // CHECK-DUMP-NEXT: DefaultConstructor @@ -260,9 +260,9 @@ namespace Std { // CHECK-DUMP-NEXT: CopyAssignment // CHECK-DUMP-NEXT: MoveAssignment // CHECK-DUMP-NEXT: Destructor -// CHECK-DUMP-NEXT: TemplateArgument type 'char[2]' -// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate // CHECK-DUMP-NEXT: TemplateArgument type 'char[1]' +// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate +// CHECK-DUMP-NEXT: TemplateArgument type 'char[2]' // CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} SomeTemplate definition // CHECK-DUMP-NEXT: DefinitionData // CHECK-DUMP-NEXT: DefaultConstructor @@ -271,4 +271,4 @@ namespace Std { // CHECK-DUMP-NEXT: CopyAssignment // CHECK-DUMP-NEXT: MoveAssignment // CHECK-DUMP-NEXT: Destructor -// CHECK-DUMP-NEXT: TemplateArgument type 'char[1]' +// CHECK-DUMP-NEXT: TemplateArgument type 'char[2]' diff --git a/clang/test/Modules/odr_hash.cpp b/clang/test/Modules/odr_hash.cpp index fa8b2c81ab46e1..7cea3af3f41bdd 100644 --- a/clang/test/Modules/odr_hash.cpp +++ b/clang/test/Modules/odr_hash.cpp @@ -3084,8 +3084,8 @@ struct S5 { }; #else S5 s5; -// expected-error@second.h:* {{'PointersAndReferences::S5::x' from module 'SecondModule' is not present in definition of 'PointersAndReferences::S5' in module 'FirstModule'}} -// expected-note@first.h:* {{declaration of 'x' does not match}} +// expected-error@first.h:* {{'PointersAndReferences::S5::x' from module 'FirstModule' is not present in definition of 'PointersAndReferences::S5' in module 'SecondModule'}} +// expected-note@second.h:* {{declaration of 'x' does not match}} #endif #if defined(FIRST) _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits