[llvm-branch-commits] [clang] a64c26a - Fix deserialization cycle in preferred_name attribute.

Richard Smith via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Dec 7 16:07:32 PST 2020


Author: Richard Smith
Date: 2020-12-07T16:02:05-08:00
New Revision: a64c26a47a81b1b44e36d235ff3bc6a74a0bad9f

URL: https://github.com/llvm/llvm-project/commit/a64c26a47a81b1b44e36d235ff3bc6a74a0bad9f
DIFF: https://github.com/llvm/llvm-project/commit/a64c26a47a81b1b44e36d235ff3bc6a74a0bad9f.diff

LOG: 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.

Added: 
    clang/test/PCH/decl-attrs.cpp

Modified: 
    clang/include/clang/AST/TypeProperties.td
    clang/lib/AST/TypePrinter.cpp
    clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
    clang/test/SemaTemplate/attributes.cpp
    clang/utils/TableGen/ClangAttrEmitter.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td
index a183ac0479c6a..b582395c44a64 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 54c451291a077..77ca0f21cc8a1 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<PreferredNameAttr>()) {
-    if (declaresSameEntity(PNA->getTypedefType()->getAsCXXRecordDecl(),
-                           T->getDecl()))
-      return printTypeSpec(
-          PNA->getTypedefType()->castAs<TypedefType>()->getDecl(), OS);
+  if (const auto *Spec =
+          dyn_cast<ClassTemplateSpecializationDecl>(T->getDecl())) {
+    for (const auto *PNA : Spec->getSpecializedTemplate()
+                               ->getTemplatedDecl()
+                               ->getMostRecentDecl()
+                               ->specific_attrs<PreferredNameAttr>()) {
+      if (declaresSameEntity(PNA->getTypedefType()->getAsCXXRecordDecl(), Spec))
+        return printTypeSpec(
+            PNA->getTypedefType()->castAs<TypedefType>()->getDecl(), OS);
+    }
   }
 
   printTag(T->getDecl(), OS);

diff  --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 9db4f23d72967..7403d31c884ae 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<PreferredNameAttr>(A)) {
-    QualType T = PNA->getTypedefType();
-    const auto *RD = cast<CXXRecordDecl>(D);
-    if (!T->isDependentType() && !RD->isDependentContext() &&
-        !declaresSameEntity(T->getAsCXXRecordDecl(), RD))
-      return false;
-    for (const auto *ExistingPNA : D->specific_attrs<PreferredNameAttr>())
-      if (S.Context.hasSameType(ExistingPNA->getTypedefType(),
-                                PNA->getTypedefType()))
-        return false;
-    return true;
-  }
+  if (const auto *PNA = dyn_cast<PreferredNameAttr>(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 0000000000000..c89354d0c5de5
--- /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<typename T> struct X;
+  using Y = X<int>;
+  using Z = X<float>;
+  template<typename T> struct [[using clang: preferred_name(Y), preferred_name(Z)]] X {};
+  Y y;
+}
+
+#else
+
+namespace preferred_name {
+  Z z;
+
+  template<typename T> 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 3f52412a23acb..2411a2e831c9f 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<int>::Iter<const int>();
-  int n = it; // expected-error {{no viable conversion from 'preferred_name::MemberTemplate<int>::const_iterator' to 'int'}}
+  int n = it; // expected-error {{no viable conversion from 'preferred_name::MemberTemplate<int>::Iter<const int>' to 'int'}}
 }

diff  --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp
index a5a599e206d38..ec436df15e65c 100644
--- a/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -3330,12 +3330,13 @@ void EmitClangAttrTemplateInstantiateHelper(const std::vector<Record *> &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"


        


More information about the llvm-branch-commits mailing list