Skip to content

Commit a64c26a

Browse files
committed
Fix deserialization cycle in preferred_name attribute.
This is really just a workaround for a more fundamental issue in the way we deserialize attributes. See PR48434 for details. Also fix tablegen code generator to produce more correct indentation to resolve buildbot issues with -Werror=misleading-indentation firing inside the generated code.
1 parent 0b81d9a commit a64c26a

File tree

6 files changed

+50
-27
lines changed

6 files changed

+50
-27
lines changed

clang/include/clang/AST/TypeProperties.td

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -484,8 +484,12 @@ let Class = TagType in {
484484
let Read = [{ node->isDependentType() }];
485485
}
486486
def : Property<"declaration", DeclRef> {
487-
// Serializing a reference to the canonical declaration is apparently
488-
// necessary to make module-merging work.
487+
// We don't know which declaration was originally referenced here, and we
488+
// cannot reference a declaration that follows the use (because that can
489+
// introduce deserialization cycles), so conservatively generate a
490+
// reference to the first declaration.
491+
// FIXME: If this is a reference to a class template specialization, that
492+
// can still introduce a deserialization cycle.
489493
let Read = [{ node->getDecl()->getCanonicalDecl() }];
490494
}
491495
}

clang/lib/AST/TypePrinter.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,11 +1350,16 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) {
13501350

13511351
void TypePrinter::printRecordBefore(const RecordType *T, raw_ostream &OS) {
13521352
// Print the preferred name if we have one for this type.
1353-
for (const auto *PNA : T->getDecl()->specific_attrs<PreferredNameAttr>()) {
1354-
if (declaresSameEntity(PNA->getTypedefType()->getAsCXXRecordDecl(),
1355-
T->getDecl()))
1356-
return printTypeSpec(
1357-
PNA->getTypedefType()->castAs<TypedefType>()->getDecl(), OS);
1353+
if (const auto *Spec =
1354+
dyn_cast<ClassTemplateSpecializationDecl>(T->getDecl())) {
1355+
for (const auto *PNA : Spec->getSpecializedTemplate()
1356+
->getTemplatedDecl()
1357+
->getMostRecentDecl()
1358+
->specific_attrs<PreferredNameAttr>()) {
1359+
if (declaresSameEntity(PNA->getTypedefType()->getAsCXXRecordDecl(), Spec))
1360+
return printTypeSpec(
1361+
PNA->getTypedefType()->castAs<TypedefType>()->getDecl(), OS);
1362+
}
13581363
}
13591364

13601365
printTag(T->getDecl(), OS);

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -552,20 +552,10 @@ static void instantiateDependentAMDGPUWavesPerEUAttr(
552552
/// If not, we can skip instantiating it. The attribute may or may not have
553553
/// been instantiated yet.
554554
static bool isRelevantAttr(Sema &S, const Decl *D, const Attr *A) {
555-
// 'preferred_name' is only relevant to the matching specialization of the
555+
// Never instantiate preferred_name attributes; they're relevant only on the
556556
// template.
557-
if (const auto *PNA = dyn_cast<PreferredNameAttr>(A)) {
558-
QualType T = PNA->getTypedefType();
559-
const auto *RD = cast<CXXRecordDecl>(D);
560-
if (!T->isDependentType() && !RD->isDependentContext() &&
561-
!declaresSameEntity(T->getAsCXXRecordDecl(), RD))
562-
return false;
563-
for (const auto *ExistingPNA : D->specific_attrs<PreferredNameAttr>())
564-
if (S.Context.hasSameType(ExistingPNA->getTypedefType(),
565-
PNA->getTypedefType()))
566-
return false;
567-
return true;
568-
}
557+
if (const auto *PNA = dyn_cast<PreferredNameAttr>(A))
558+
return false;
569559

570560
return true;
571561
}

clang/test/PCH/decl-attrs.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %clang_cc1 -std=c++20 -emit-pch -o %t.a %s
2+
// RUN: %clang_cc1 -std=c++20 -include-pch %t.a %s -verify
3+
4+
#ifndef HEADER
5+
#define HEADER
6+
7+
namespace preferred_name {
8+
template<typename T> struct X;
9+
using Y = X<int>;
10+
using Z = X<float>;
11+
template<typename T> struct [[using clang: preferred_name(Y), preferred_name(Z)]] X {};
12+
Y y;
13+
}
14+
15+
#else
16+
17+
namespace preferred_name {
18+
Z z;
19+
20+
template<typename T> T forget(T t) { return t; }
21+
void f() {
22+
forget(y).foo(); // expected-error {{no member named 'foo' in 'preferred_name::Y'}}
23+
forget(z).foo(); // expected-error {{no member named 'foo' in 'preferred_name::Z'}}
24+
}
25+
}
26+
27+
#endif

clang/test/SemaTemplate/attributes.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,10 @@ namespace preferred_name {
8383
// CHECK: ClassTemplateSpecializationDecl {{.*}} struct C definition
8484
// CHECK: TemplateArgument type 'int'
8585
// CHECK-NOT: PreferredNameAttr
86-
// CHECK: PreferredNameAttr {{.*}} preferred_name::X
87-
// CHECK-NOT: PreferredNameAttr
8886
// CHECK: CXXRecordDecl
8987
// CHECK: ClassTemplateSpecializationDecl {{.*}} struct C definition
9088
// CHECK: TemplateArgument type 'float'
9189
// CHECK-NOT: PreferredNameAttr
92-
// CHECK: PreferredNameAttr {{.*}} preferred_name::Y
93-
// CHECK-NOT: PreferredNameAttr
9490
// CHECK: CXXRecordDecl
9591
// CHECK: ClassTemplateSpecializationDecl {{.*}} struct C definition
9692
// CHECK: TemplateArgument type 'double'
@@ -125,5 +121,5 @@ namespace preferred_name {
125121
clang::preferred_name(const_iterator)]] Iter {};
126122
};
127123
auto it = MemberTemplate<int>::Iter<const int>();
128-
int n = it; // expected-error {{no viable conversion from 'preferred_name::MemberTemplate<int>::const_iterator' to 'int'}}
124+
int n = it; // expected-error {{no viable conversion from 'preferred_name::MemberTemplate<int>::Iter<const int>' to 'int'}}
129125
}

clang/utils/TableGen/ClangAttrEmitter.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3330,12 +3330,13 @@ void EmitClangAttrTemplateInstantiateHelper(const std::vector<Record *> &Attrs,
33303330
for (auto const &ai : Args)
33313331
ai->writeTemplateInstantiation(OS);
33323332

3333-
OS << " return new (C) " << R.getName() << "Attr(C, *A";
3333+
OS << " return new (C) " << R.getName() << "Attr(C, *A";
33343334
for (auto const &ai : Args) {
33353335
OS << ", ";
33363336
ai->writeTemplateInstantiationArgs(OS);
33373337
}
3338-
OS << ");\n }\n";
3338+
OS << ");\n"
3339+
<< " }\n";
33393340
}
33403341
OS << " } // end switch\n"
33413342
<< " llvm_unreachable(\"Unknown attribute!\");\n"

0 commit comments

Comments
 (0)