[clang] D41416: [modules] [pch] Do not deserialize all lazy template specializations when looking for one. (PR #83108)
Chuanqi Xu via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 8 01:07:15 PST 2024
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.yd at 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.vassilev at 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 at second.h:* {{'PointersAndReferences::S5::x' from module 'SecondModule' is not present in definition of 'PointersAndReferences::S5' in module 'FirstModule'}}
-// expected-note at first.h:* {{declaration of 'x' does not match}}
+// expected-error at first.h:* {{'PointersAndReferences::S5::x' from module 'FirstModule' is not present in definition of 'PointersAndReferences::S5' in module 'SecondModule'}}
+// expected-note at second.h:* {{declaration of 'x' does not match}}
#endif
#if defined(FIRST)
More information about the cfe-commits
mailing list