erichkeane updated this revision to Diff 80913.
erichkeane marked an inline comment as done.
erichkeane added a comment.

Based on the tests, I was able to track down the 2 locations that stopped 
working.  I've updated them appropriately.

It seems though that this Template Decl Instantiation is the ONLY time that the 
attributes aren't just initialized immediately.  This gets me wondering if I 
should just create a pair of functions for it specifically?  It would likely be 
a little bit of re-work on InstatiateAttrs (perhaps separate the implementation 
to take the instantiateTemplateAttrribute 'function' as a parameter), but would 
that be preferential?


https://reviews.llvm.org/D27529

Files:
  include/clang/Basic/Attr.td
  include/clang/Sema/Sema.h
  lib/Sema/SemaTemplate.cpp
  lib/Sema/SemaTemplateInstantiate.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp
  utils/TableGen/ClangAttrEmitter.cpp

Index: lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiate.cpp
+++ lib/Sema/SemaTemplateInstantiate.cpp
@@ -1858,6 +1858,8 @@
   namespace sema {
     Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, Sema &S,
                             const MultiLevelTemplateArgumentList &TemplateArgs);
+    Attr *instantiateTemplateAttributeForDecl(const Attr *At, ASTContext &C, Sema &S,
+                            const MultiLevelTemplateArgumentList &TemplateArgs);
   }
 }
 
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -2352,6 +2352,10 @@
                                                 ClassTemplate->getLocation(),
                                                      ClassTemplate,
                                                      Converted, nullptr);
+      MultiLevelTemplateArgumentList TemplateArgLists;
+      TemplateArgLists.addOuterTemplateArguments(Converted);
+      InstantiateAttrsForDecl(TemplateArgLists,
+                              ClassTemplate->getTemplatedDecl(), Decl);
       ClassTemplate->AddSpecialization(Decl, InsertPos);
       if (ClassTemplate->isOutOfLine())
         Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext());
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -308,6 +308,26 @@
       Attr.getRange());
 }
 
+void Sema::InstantiateAttrsForDecl(
+    const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Tmpl,
+    Decl *New, LateInstantiatedAttrVec *LateAttrs,
+    LocalInstantiationScope *OuterMostScope) {
+  for (const auto *TmplAttr : Tmpl->attrs()) {
+    // FIXME: If any of the special case versions from InstantiateAttrs become
+    // applicable to template declaration, we'll need to add them here.
+    NamedDecl *ND = dyn_cast<NamedDecl>(New);
+    CXXRecordDecl *ThisContext =
+        dyn_cast_or_null<CXXRecordDecl>(ND->getDeclContext());
+    CXXThisScopeRAII ThisScope(*this, ThisContext, /*TypeQuals*/ 0,
+                               ND && ND->isCXXInstanceMember());
+
+    Attr *NewAttr = sema::instantiateTemplateAttributeForDecl(TmplAttr, Context, *this,
+                                                       TemplateArgs);
+    if (NewAttr)
+      New->addAttr(NewAttr);
+  }
+}
+
 void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
                             const Decl *Tmpl, Decl *New,
                             LateInstantiatedAttrVec *LateAttrs,
@@ -945,6 +965,7 @@
     }
   }
 
+  SemaRef.InstantiateAttrsForDecl(TemplateArgs, D, Enum);
   SemaRef.InstantiateAttrs(TemplateArgs, D, Enum);
 
   Enum->setInstantiationOfMemberEnum(D, TSK_ImplicitInstantiation);
@@ -1033,6 +1054,7 @@
     }
 
     if (EnumConst) {
+      SemaRef.InstantiateAttrsForDecl(TemplateArgs, EC, EnumConst);
       SemaRef.InstantiateAttrs(TemplateArgs, EC, EnumConst);
 
       EnumConst->setAccess(Enum->getAccess());
Index: utils/TableGen/ClangAttrEmitter.cpp
===================================================================
--- utils/TableGen/ClangAttrEmitter.cpp
+++ utils/TableGen/ClangAttrEmitter.cpp
@@ -2452,26 +2452,20 @@
   OS << "#endif  // ATTR_VISITOR_DECLS_ONLY\n";
 }
 
-// Emits code to instantiate dependent attributes on templates.
-void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) {
-  emitSourceFileHeader("Template instantiation code for attributes", OS);
-
-  std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
-
-  OS << "namespace clang {\n"
-     << "namespace sema {\n\n"
-     << "Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, "
-     << "Sema &S,\n"
-     << "        const MultiLevelTemplateArgumentList &TemplateArgs) {\n"
-     << "  switch (At->getKind()) {\n";
+void EmitClangAttrTemplateInstantiateHelper(const std::vector<Record *> &Attrs,
+                                            raw_ostream &OS, bool DeclTime) {
+     OS << "  switch (At->getKind()) {\n";
 
   for (const auto *Attr : Attrs) {
     const Record &R = *Attr;
     if (!R.getValueAsBit("ASTNode"))
       continue;
 
     OS << "    case attr::" << R.getName() << ": {\n";
-    bool ShouldClone = R.getValueAsBit("Clone");
+
+    bool ShouldClone =
+        R.getValueAsBit("Clone") &&
+        R.getValueAsBit("AppliesToTemplateDeclaration") == DeclTime;
 
     if (!ShouldClone) {
       OS << "      return nullptr;\n";
@@ -2508,8 +2502,27 @@
   }
   OS << "  } // end switch\n"
      << "  llvm_unreachable(\"Unknown attribute!\");\n"
-     << "  return nullptr;\n"
-     << "}\n\n"
+     << "  return nullptr;\n";
+}
+// Emits code to instantiate dependent attributes on templates.
+void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) {
+  emitSourceFileHeader("Template instantiation code for attributes", OS);
+
+  std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
+
+  OS << "namespace clang {\n"
+     << "namespace sema {\n\n"
+     << "Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, "
+     << "Sema &S,\n"
+     << "        const MultiLevelTemplateArgumentList &TemplateArgs) {\n";
+  EmitClangAttrTemplateInstantiateHelper(Attrs, OS, /*DeclTime=*/false);
+  OS << "}\n\n"
+     << "Attr *instantiateTemplateAttributeForDecl(const Attr *At,\n"
+     << "        ASTContext &C, Sema &S,\n"
+     << "        const MultiLevelTemplateArgumentList &TemplateArgs) {\n";
+  EmitClangAttrTemplateInstantiateHelper(Attrs, OS, /*DeclTime=*/true);
+
+  OS << "}\n\n"
      << "} // end namespace sema\n"
      << "} // end namespace clang\n";
 }
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -7352,6 +7352,11 @@
                         LateInstantiatedAttrVec *LateAttrs = nullptr,
                         LocalInstantiationScope *OuterMostScope = nullptr);
 
+  void InstantiateAttrsForDecl(const MultiLevelTemplateArgumentList &TemplateArgs,
+                        const Decl *Pattern, Decl *Inst,
+                        LateInstantiatedAttrVec *LateAttrs = nullptr,
+                        LocalInstantiationScope *OuterMostScope = nullptr);
+
   bool
   InstantiateClassTemplateSpecialization(SourceLocation PointOfInstantiation,
                            ClassTemplateSpecializationDecl *ClassTemplateSpec,
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -298,6 +298,8 @@
   // Set to true if this attribute can be duplicated on a subject when merging
   // attributes. By default, attributes are not merged.
   bit DuplicatesAllowedWhileMerging = 0;
+  // TODO
+  bit AppliesToTemplateDeclaration = 0;
   // Lists language options, one of which is required to be true for the
   // attribute to be applicable. If empty, no language options are required.
   list<LangOpt> LangOpts = [];
@@ -765,6 +767,7 @@
               // Fix-It.
               StringArgument<"Replacement", 1>];
   let Documentation = [DeprecatedDocs];
+  let AppliesToTemplateDeclaration = 1;
 }
 
 def Destructor : InheritableAttr {
Index: test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp
===================================================================
--- test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp
+++ test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp
@@ -23,7 +23,8 @@
 X<char> x1;
 X<int> x2; // expected-warning {{'X<int>' is deprecated}}
 
-template <typename T> class [[deprecated]] X2 {};
+template <typename T> class [[deprecated]] X2 {}; //expected-note {{'X2<char>' has been explicitly marked deprecated here}}
 template <> class X2<int> {};
-X2<char> x3; // FIXME: no warning!
-X2<int> x4;
+X2<char> x3; // expected-warning {{'X2<char>' is deprecated}}
+X2<int> x4; // No warning, the specialization removes it.
+
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to