diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td index a183ac0479c6a8..b582395c44a642 100644 --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -484,8 +484,12 @@ let Class = TagType in { let Read = [{ node->isDependentType() }]; } def : Property<"declaration", DeclRef> { - // Serializing a reference to the canonical declaration is apparently - // necessary to make module-merging work. + // We don't know which declaration was originally referenced here, and we + // cannot reference a declaration that follows the use (because that can + // introduce deserialization cycles), so conservatively generate a + // reference to the first declaration. + // FIXME: If this is a reference to a class template specialization, that + // can still introduce a deserialization cycle. let Read = [{ node->getDecl()->getCanonicalDecl() }]; } } diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 54c451291a0777..77ca0f21cc8a14 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1350,11 +1350,16 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) { void TypePrinter::printRecordBefore(const RecordType *T, raw_ostream &OS) { // Print the preferred name if we have one for this type. - for (const auto *PNA : T->getDecl()->specific_attrs()) { - if (declaresSameEntity(PNA->getTypedefType()->getAsCXXRecordDecl(), - T->getDecl())) - return printTypeSpec( - PNA->getTypedefType()->castAs()->getDecl(), OS); + if (const auto *Spec = + dyn_cast(T->getDecl())) { + for (const auto *PNA : Spec->getSpecializedTemplate() + ->getTemplatedDecl() + ->getMostRecentDecl() + ->specific_attrs()) { + if (declaresSameEntity(PNA->getTypedefType()->getAsCXXRecordDecl(), Spec)) + return printTypeSpec( + PNA->getTypedefType()->castAs()->getDecl(), OS); + } } printTag(T->getDecl(), OS); diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 9db4f23d729673..7403d31c884ae1 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -552,20 +552,10 @@ static void instantiateDependentAMDGPUWavesPerEUAttr( /// If not, we can skip instantiating it. The attribute may or may not have /// been instantiated yet. static bool isRelevantAttr(Sema &S, const Decl *D, const Attr *A) { - // 'preferred_name' is only relevant to the matching specialization of the + // Never instantiate preferred_name attributes; they're relevant only on the // template. - if (const auto *PNA = dyn_cast(A)) { - QualType T = PNA->getTypedefType(); - const auto *RD = cast(D); - if (!T->isDependentType() && !RD->isDependentContext() && - !declaresSameEntity(T->getAsCXXRecordDecl(), RD)) - return false; - for (const auto *ExistingPNA : D->specific_attrs()) - if (S.Context.hasSameType(ExistingPNA->getTypedefType(), - PNA->getTypedefType())) - return false; - return true; - } + if (const auto *PNA = dyn_cast(A)) + return false; return true; } diff --git a/clang/test/PCH/decl-attrs.cpp b/clang/test/PCH/decl-attrs.cpp new file mode 100644 index 00000000000000..c89354d0c5de5a --- /dev/null +++ b/clang/test/PCH/decl-attrs.cpp @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -std=c++20 -emit-pch -o %t.a %s +// RUN: %clang_cc1 -std=c++20 -include-pch %t.a %s -verify + +#ifndef HEADER +#define HEADER + +namespace preferred_name { + template struct X; + using Y = X; + using Z = X; + template struct [[using clang: preferred_name(Y), preferred_name(Z)]] X {}; + Y y; +} + +#else + +namespace preferred_name { + Z z; + + template T forget(T t) { return t; } + void f() { + forget(y).foo(); // expected-error {{no member named 'foo' in 'preferred_name::Y'}} + forget(z).foo(); // expected-error {{no member named 'foo' in 'preferred_name::Z'}} + } +} + +#endif diff --git a/clang/test/SemaTemplate/attributes.cpp b/clang/test/SemaTemplate/attributes.cpp index 3f52412a23acb6..2411a2e831c9fd 100644 --- a/clang/test/SemaTemplate/attributes.cpp +++ b/clang/test/SemaTemplate/attributes.cpp @@ -83,14 +83,10 @@ namespace preferred_name { // CHECK: ClassTemplateSpecializationDecl {{.*}} struct C definition // CHECK: TemplateArgument type 'int' // CHECK-NOT: PreferredNameAttr - // CHECK: PreferredNameAttr {{.*}} preferred_name::X - // CHECK-NOT: PreferredNameAttr // CHECK: CXXRecordDecl // CHECK: ClassTemplateSpecializationDecl {{.*}} struct C definition // CHECK: TemplateArgument type 'float' // CHECK-NOT: PreferredNameAttr - // CHECK: PreferredNameAttr {{.*}} preferred_name::Y - // CHECK-NOT: PreferredNameAttr // CHECK: CXXRecordDecl // CHECK: ClassTemplateSpecializationDecl {{.*}} struct C definition // CHECK: TemplateArgument type 'double' @@ -125,5 +121,5 @@ namespace preferred_name { clang::preferred_name(const_iterator)]] Iter {}; }; auto it = MemberTemplate::Iter(); - int n = it; // expected-error {{no viable conversion from 'preferred_name::MemberTemplate::const_iterator' to 'int'}} + int n = it; // expected-error {{no viable conversion from 'preferred_name::MemberTemplate::Iter' to 'int'}} } diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index a5a599e206d383..ec436df15e65c1 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -3330,12 +3330,13 @@ void EmitClangAttrTemplateInstantiateHelper(const std::vector &Attrs, for (auto const &ai : Args) ai->writeTemplateInstantiation(OS); - OS << " return new (C) " << R.getName() << "Attr(C, *A"; + OS << " return new (C) " << R.getName() << "Attr(C, *A"; for (auto const &ai : Args) { OS << ", "; ai->writeTemplateInstantiationArgs(OS); } - OS << ");\n }\n"; + OS << ");\n" + << " }\n"; } OS << " } // end switch\n" << " llvm_unreachable(\"Unknown attribute!\");\n"