[llvm-branch-commits] [clang] 44ce1f8 - Commit to a primary definition for a class when we load its first
Tobias Hieta via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Aug 7 00:06:43 PDT 2023
Author: Richard Smith
Date: 2023-08-07T09:04:02+02:00
New Revision: 44ce1f829921b63712ed43ad743680a75befcf6d
URL: https://github.com/llvm/llvm-project/commit/44ce1f829921b63712ed43ad743680a75befcf6d
DIFF: https://github.com/llvm/llvm-project/commit/44ce1f829921b63712ed43ad743680a75befcf6d.diff
LOG: Commit to a primary definition for a class when we load its first
member.
Previously, we wouldn't do this if the first member loaded is within a
definition that's added to a class via an update record, which happens
when template instantiation adds a class definition to a declaration
that was imported from an AST file.
This would lead to classes having member functions whose getParent
returned a class declaration that wasn't the primary definition, which
in turn caused the vtable builder to build broken vtables.
I don't yet have a reduced testcase for the wrong-code bug here, because
the setup required to get us into the broken state is very subtle, but
have confirmed that this fixes it.
(cherry picked from commit 61c7a9140becb19c5b1bc644e54452c6f782f5d5)
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/lib/Serialization/ASTReaderDecl.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 3f97372116d2b9..46b6b06d27b0e8 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -477,6 +477,10 @@ Improvements to Clang's diagnostics
Bug Fixes in This Version
-------------------------
+- Fixed an issue where a class template specialization whose declaration is
+ instantiated in one module and whose definition is instantiated in another
+ module may end up with members associated with the wrong declaration of the
+ class, which can result in miscompiles in some cases.
- Added a new diagnostic warning group
``-Wdeprecated-redundant-constexpr-static-def``, under the existing
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 10c92f8d214941..c8cbee14be4f02 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -181,6 +181,13 @@ namespace clang {
static void setAnonymousDeclForMerging(ASTReader &Reader, DeclContext *DC,
unsigned Index, NamedDecl *D);
+ /// Commit to a primary definition of the class RD, which is known to be
+ /// a definition of the class. We might not have read the definition data
+ /// for it yet. If we haven't then allocate placeholder definition data
+ /// now too.
+ static CXXRecordDecl *getOrFakePrimaryClassDefinition(ASTReader &Reader,
+ CXXRecordDecl *RD);
+
/// Results from loading a RedeclarableDecl.
class RedeclarableResult {
Decl *MergeWith;
@@ -598,7 +605,13 @@ void ASTDeclReader::VisitDecl(Decl *D) {
auto *LexicalDC = readDeclAs<DeclContext>();
if (!LexicalDC)
LexicalDC = SemaDC;
- DeclContext *MergedSemaDC = Reader.MergedDeclContexts.lookup(SemaDC);
+ // If the context is a class, we might not have actually merged it yet, in
+ // the case where the definition comes from an update record.
+ DeclContext *MergedSemaDC;
+ if (auto *RD = dyn_cast<CXXRecordDecl>(SemaDC))
+ MergedSemaDC = getOrFakePrimaryClassDefinition(Reader, RD);
+ else
+ MergedSemaDC = Reader.MergedDeclContexts.lookup(SemaDC);
// Avoid calling setLexicalDeclContext() directly because it uses
// Decl::getASTContext() internally which is unsafe during derialization.
D->setDeclContextsImpl(MergedSemaDC ? MergedSemaDC : SemaDC, LexicalDC,
@@ -3198,6 +3211,32 @@ uint64_t ASTReader::getGlobalBitOffset(ModuleFile &M, uint64_t LocalOffset) {
return LocalOffset + M.GlobalBitOffset;
}
+CXXRecordDecl *
+ASTDeclReader::getOrFakePrimaryClassDefinition(ASTReader &Reader,
+ CXXRecordDecl *RD) {
+ // Try to dig out the definition.
+ auto *DD = RD->DefinitionData;
+ if (!DD)
+ DD = RD->getCanonicalDecl()->DefinitionData;
+
+ // If there's no definition yet, then DC's definition is added by an update
+ // record, but we've not yet loaded that update record. In this case, we
+ // commit to DC being the canonical definition now, and will fix this when
+ // we load the update record.
+ if (!DD) {
+ DD = new (Reader.getContext()) struct CXXRecordDecl::DefinitionData(RD);
+ RD->setCompleteDefinition(true);
+ RD->DefinitionData = DD;
+ RD->getCanonicalDecl()->DefinitionData = DD;
+
+ // Track that we did this horrible thing so that we can fix it later.
+ Reader.PendingFakeDefinitionData.insert(
+ std::make_pair(DD, ASTReader::PendingFakeDefinitionKind::Fake));
+ }
+
+ return DD->Definition;
+}
+
/// Find the context in which we should search for previous declarations when
/// looking for declarations to merge.
DeclContext *ASTDeclReader::getPrimaryContextForMerging(ASTReader &Reader,
@@ -3205,29 +3244,8 @@ DeclContext *ASTDeclReader::getPrimaryContextForMerging(ASTReader &Reader,
if (auto *ND = dyn_cast<NamespaceDecl>(DC))
return ND->getOriginalNamespace();
- if (auto *RD = dyn_cast<CXXRecordDecl>(DC)) {
- // Try to dig out the definition.
- auto *DD = RD->DefinitionData;
- if (!DD)
- DD = RD->getCanonicalDecl()->DefinitionData;
-
- // If there's no definition yet, then DC's definition is added by an update
- // record, but we've not yet loaded that update record. In this case, we
- // commit to DC being the canonical definition now, and will fix this when
- // we load the update record.
- if (!DD) {
- DD = new (Reader.getContext()) struct CXXRecordDecl::DefinitionData(RD);
- RD->setCompleteDefinition(true);
- RD->DefinitionData = DD;
- RD->getCanonicalDecl()->DefinitionData = DD;
-
- // Track that we did this horrible thing so that we can fix it later.
- Reader.PendingFakeDefinitionData.insert(
- std::make_pair(DD, ASTReader::PendingFakeDefinitionKind::Fake));
- }
-
- return DD->Definition;
- }
+ if (auto *RD = dyn_cast<CXXRecordDecl>(DC))
+ return getOrFakePrimaryClassDefinition(Reader, RD);
if (auto *RD = dyn_cast<RecordDecl>(DC))
return RD->getDefinition();
More information about the llvm-branch-commits
mailing list