erichkeane updated this revision to Diff 82909.
erichkeane added a comment.

Updated based on Richard Smith's suggestion, all tests pass with no alteration, 
and the initial incorrect behavior was corrected in an existing test.


https://reviews.llvm.org/D27486

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
@@ -1882,6 +1882,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
@@ -2401,6 +2401,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
@@ -7385,6 +7385,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,9 @@
   // Set to true if this attribute can be duplicated on a subject when merging
   // attributes. By default, attributes are not merged.
   bit DuplicatesAllowedWhileMerging = 0;
+  // Set to true if this attribute should apply to template declaration,
+  // remains false if this should only be applied on definition.
+  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 +768,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