steffenlarsen created this revision.
steffenlarsen added reviewers: erichkeane, aaron.ballman, Tyker, Naghasan.
Herald added a subscriber: jdoerfert.
steffenlarsen requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

These changes make the Clang parser recognize parameter pack expansion in 
attribute arguments and consume them if the attribute is marked as supporting 
parameter pack expansions.
Currently only the `clang::annotate` attribute will support parameter pack 
expansions in its arguments. The parser will issue an error diagnostic if other 
attributes are passed parameter pack expansion arguments.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D114439

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
  clang/test/Parser/cxx0x-attributes.cpp
  clang/test/SemaTemplate/attributes.cpp
  clang/utils/TableGen/ClangAttrEmitter.cpp

Index: clang/utils/TableGen/ClangAttrEmitter.cpp
===================================================================
--- clang/utils/TableGen/ClangAttrEmitter.cpp
+++ clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -1697,6 +1697,22 @@
   OS << "#endif // CLANG_ATTR_LATE_PARSED_LIST\n\n";
 }
 
+// Emits the ParmExpansionArgsSupport property for attributes.
+static void emitClangAttrParmExpansionArgsSupportList(RecordKeeper &Records,
+                                                      raw_ostream &OS) {
+  OS << "#if defined(CLANG_ATTR_PARM_EXPANSION_ARGS_SUPPORT_LIST)\n";
+  std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
+
+  for (const auto *Attr : Attrs) {
+    if (Attr->getValueAsBit("ParmExpansionArgsSupport")) {
+      std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*Attr);
+      for (const auto &I : Spellings)
+        OS << ".Case(\"" << I.name() << "\", true)\n";
+    }
+  }
+  OS << "#endif // CLANG_ATTR_PARM_EXPANSION_ARGS_SUPPORT_LIST\n\n";
+}
+
 static bool hasGNUorCXX11Spelling(const Record &Attribute) {
   std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attribute);
   for (const auto &I : Spellings) {
@@ -4221,6 +4237,7 @@
   emitClangAttrThisIsaIdentifierArgList(Records, OS);
   emitClangAttrTypeArgList(Records, OS);
   emitClangAttrLateParsedList(Records, OS);
+  emitClangAttrParmExpansionArgsSupportList(Records, OS);
 }
 
 void EmitClangAttrSubjectMatchRulesParserStringSwitches(RecordKeeper &Records,
Index: clang/test/SemaTemplate/attributes.cpp
===================================================================
--- clang/test/SemaTemplate/attributes.cpp
+++ clang/test/SemaTemplate/attributes.cpp
@@ -64,6 +64,23 @@
 template<typename T> [[clang::annotate("ANNOTATE_FOO"), clang::annotate("ANNOTATE_BAR")]] void HasAnnotations();
 void UseAnnotations() { HasAnnotations<int>(); }
 
+// CHECK:      FunctionTemplateDecl {{.*}} HasPackAnnotations
+// CHECK:        AnnotateAttr {{.*}} "ANNOTATE_BAZ"
+// CHECK:      FunctionDecl {{.*}} HasPackAnnotations
+// CHECK:        TemplateArgument{{.*}} pack
+// CHECK-NEXT:     TemplateArgument{{.*}} integral 1
+// CHECK-NEXT:     TemplateArgument{{.*}} integral 2
+// CHECK-NEXT:     TemplateArgument{{.*}} integral 3
+// CHECK:        AnnotateAttr {{.*}} "ANNOTATE_BAZ"
+// CHECK:          ConstantExpr {{.*}} 'int'
+// CHECK-NEXT:       value: Int 1
+// CHECK:          ConstantExpr {{.*}} 'int'
+// CHECK-NEXT:       value: Int 2
+// CHECK:          ConstantExpr {{.*}} 'int'
+// CHECK-NEXT:       value: Int 3
+template <int... Is> [[clang::annotate("ANNOTATE_BAZ", Is...)]] void HasPackAnnotations();
+void UsePackAnnotations() { HasPackAnnotations<1, 2, 3>(); }
+
 namespace preferred_name {
   int x [[clang::preferred_name("frank")]]; // expected-error {{expected a type}}
   int y [[clang::preferred_name(int)]]; // expected-warning {{'preferred_name' attribute only applies to class templates}}
Index: clang/test/Parser/cxx0x-attributes.cpp
===================================================================
--- clang/test/Parser/cxx0x-attributes.cpp
+++ clang/test/Parser/cxx0x-attributes.cpp
@@ -258,8 +258,10 @@
   [[]] return;
 }
 
-template<typename...Ts> void variadic() {
+template <int... Is> void variadic() {
   void bar [[noreturn...]] (); // expected-error {{attribute 'noreturn' cannot be used as an attribute pack}}
+  void baz [[clang::no_sanitize(Is...)]] (); // expected-error {{attribute 'no_sanitize' does not support parameter pack expansion in arguments}}
+  void boo [[unknown::foo(Is...)]] ();       // expected-warning {{unknown attribute 'foo' ignored}}
 }
 
 // Expression tests
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -189,13 +189,9 @@
   EnterExpressionEvaluationContext Unevaluated(
       S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
   SmallVector<Expr *, 4> Args;
-  Args.reserve(Attr->args_size());
-  for (auto *E : Attr->args()) {
-    ExprResult Result = S.SubstExpr(E, TemplateArgs);
-    if (!Result.isUsable())
-      return;
-    Args.push_back(Result.get());
-  }
+  if (S.SubstExprs(ArrayRef<Expr *>(Attr->args_begin(), Attr->args_end()),
+                   /*IsCall=*/false, TemplateArgs, Args))
+    return;
   S.AddAnnotationAttr(New, *Attr, Attr->getAnnotation(), Args);
 }
 
Index: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -319,6 +319,16 @@
 #undef CLANG_ATTR_ARG_CONTEXT_LIST
 }
 
+/// attributeParmPackArgsSupport - Return true if the attribute supports
+/// parameter pack expansion in its arguments.
+static bool attributeParmPackArgsSupport(const IdentifierInfo &II) {
+#define CLANG_ATTR_PARM_EXPANSION_ARGS_SUPPORT_LIST
+  return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
+#include "clang/Parse/AttrParserStringSwitches.inc"
+      .Default(false);
+#undef CLANG_ATTR_PARM_EXPANSION_ARGS_SUPPORT_LIST
+}
+
 IdentifierLoc *Parser::ParseIdentifierLoc() {
   assert(Tok.is(tok::identifier) && "expected an identifier");
   IdentifierLoc *IL = IdentifierLoc::create(Actions.Context,
@@ -425,6 +435,18 @@
 
         ExprResult ArgExpr(
             Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()));
+
+        if (Tok.is(tok::ellipsis)) {
+          if (!attributeParmPackArgsSupport(*AttrName)) {
+            Diag(Tok.getLocation(),
+                 diag::err_attribute_argument_parm_pack_not_supported)
+                << AttrName;
+            SkipUntil(tok::r_paren, StopAtSemi);
+            return 0;
+          }
+          ArgExpr = Actions.ActOnPackExpansion(ArgExpr.get(), ConsumeToken());
+        }
+
         if (ArgExpr.isInvalid()) {
           SkipUntil(tok::r_paren, StopAtSemi);
           return 0;
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -719,6 +719,8 @@
 def err_l_square_l_square_not_attribute : Error<
   "C++11 only allows consecutive left square brackets when "
   "introducing an attribute">;
+def err_attribute_argument_parm_pack_not_supported : Error<
+  "attribute %0 does not support parameter pack expansion in arguments">;
 def err_ms_declspec_type : Error<
   "__declspec attributes must be an identifier or string literal">;
 def err_ms_property_no_getter_or_putter : Error<
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -541,6 +541,9 @@
   //   match rules.
   // - It has GNU/CXX11 spelling and doesn't require delayed parsing.
   bit PragmaAttributeSupport;
+  // Set to true for attributes that support parameter pack expansion in its
+  // arguments.
+  bit ParmExpansionArgsSupport = 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 = [];
@@ -784,6 +787,7 @@
   }
   }];
   let PragmaAttributeSupport = 1;
+  let ParmExpansionArgsSupport = 1;
   let Documentation = [Undocumented];
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to