steffenlarsen updated this revision to Diff 391588.
steffenlarsen edited the summary of this revision.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D114439/new/

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
@@ -1164,10 +1164,12 @@
   };
 
   class VariadicExprArgument : public VariadicArgument {
+    bool AllowPack = false;
+
   public:
     VariadicExprArgument(const Record &Arg, StringRef Attr)
-      : VariadicArgument(Arg, Attr, "Expr *")
-    {}
+        : VariadicArgument(Arg, Attr, "Expr *"),
+          AllowPack(Arg.getValueAsBit("AllowPack")) {}
 
     void writeASTVisitorTraversal(raw_ostream &OS) const override {
       OS << "  {\n";
@@ -2264,6 +2266,43 @@
   OS << "#endif // CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST\n\n";
 }
 
+static void emitClangAttrNumArgs(RecordKeeper &Records, raw_ostream &OS) {
+  OS << "#if defined(CLANG_ATTR_NUM_ARGS)\n";
+  std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
+  for (const auto *A : Attrs) {
+    std::vector<Record *> Args = A->getValueAsListOfDefs("Args");
+    forEachUniqueSpelling(*A, [&](const FlattenedSpelling &S) {
+      OS << ".Case(\"" << S.name() << "\", " << Args.size() << ")\n";
+    });
+  }
+  OS << "#endif // CLANG_ATTR_NUM_ARGS\n\n";
+}
+
+static bool argSupportsParmPack(const Record *Arg) {
+  return !Arg->getSuperClasses().empty() &&
+         llvm::StringSwitch<bool>(
+             Arg->getSuperClasses().back().first->getName())
+             .Case("VariadicExprArgument", true)
+             .Default(false) &&
+         Arg->getValueAsBit("AllowPack");
+}
+
+static void emitClangAttrLastArgParmPackSupport(RecordKeeper &Records,
+                                                raw_ostream &OS) {
+  OS << "#if defined(CLANG_ATTR_LAST_ARG_PARM_PACK_SUPPORT)\n";
+  std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
+  for (const auto *A : Attrs) {
+    std::vector<Record *> Args = A->getValueAsListOfDefs("Args");
+    bool LastArgSupportsParmPack =
+        !Args.empty() && argSupportsParmPack(Args.back());
+    forEachUniqueSpelling(*A, [&](const FlattenedSpelling &S) {
+      OS << ".Case(\"" << S.name() << "\", " << LastArgSupportsParmPack
+         << ")\n";
+    });
+  }
+  OS << "#endif // CLANG_ATTR_LAST_ARG_PARM_PACK_SUPPORT\n\n";
+}
+
 static void emitAttributes(RecordKeeper &Records, raw_ostream &OS,
                            bool Header) {
   std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
@@ -4219,6 +4258,8 @@
   emitClangAttrIdentifierArgList(Records, OS);
   emitClangAttrVariadicIdentifierArgList(Records, OS);
   emitClangAttrThisIsaIdentifierArgList(Records, OS);
+  emitClangAttrNumArgs(Records, OS);
+  emitClangAttrLastArgParmPackSupport(Records, OS);
   emitClangAttrTypeArgList(Records, OS);
   emitClangAttrLateParsedList(Records, OS);
 }
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,14 @@
   [[]] return;
 }
 
-template<typename...Ts> void variadic() {
-  void bar [[noreturn...]] (); // expected-error {{attribute 'noreturn' cannot be used as an attribute pack}}
+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 pack expansion in the last argument}}
+  void boz [[clang::annotate(Is...)]] ();           // expected-error {{pack expansion in attributes is restricted to only the last argument}}
+  void bor [[clang::annotate("A", "V" ...)]] ();    // expected-error {{pack expansion does not contain any unexpanded parameter packs}}
+  void boo [[unknown::foo(Is...)]] ();              // expected-warning {{unknown attribute 'foo' ignored}}
+  void faz [[clang::annotate("B", (Is + ...))]] (); // expected-warning {{pack fold expression is a C++17 extension}}
+  void foz [[clang::annotate("C", Is...)]] ();
 }
 
 // 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
@@ -300,6 +300,25 @@
 #undef CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST
 }
 
+/// Determine how many arguments an attribute has. Variadic arguments counts as
+/// a single argument.
+static size_t attributeNumberOfArguments(const IdentifierInfo &II) {
+#define CLANG_ATTR_NUM_ARGS
+  return llvm::StringSwitch<size_t>(normalizeAttrName(II.getName()))
+#include "clang/Parse/AttrParserStringSwitches.inc"
+      .Default(0);
+#undef CLANG_ATTR_NUM_ARGS
+}
+
+/// Determine if the last attribute argument supports pack expansion.
+static bool attributeLastArgParmPackSupport(const IdentifierInfo &II) {
+#define CLANG_ATTR_LAST_ARG_PARM_PACK_SUPPORT
+  return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
+#include "clang/Parse/AttrParserStringSwitches.inc"
+      .Default(false);
+#undef CLANG_ATTR_LAST_ARG_PARM_PACK_SUPPORT
+}
+
 /// Determine whether the given attribute parses a type argument.
 static bool attributeIsTypeArgAttr(const IdentifierInfo &II) {
 #define CLANG_ATTR_TYPE_ARG_LIST
@@ -425,6 +444,29 @@
 
         ExprResult ArgExpr(
             Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()));
+
+        if (Tok.is(tok::ellipsis)) {
+          // Pack expansion is only allowed in the last attribute argument.
+          if (ArgExprs.size() + 1 < attributeNumberOfArguments(*AttrName)) {
+            Diag(Tok.getLocation(),
+                 diag::err_attribute_parm_pack_last_argument_only);
+            SkipUntil(tok::r_paren, StopAtSemi);
+            return 0;
+          }
+
+          // Attribute must explicitly support parameter pack in its last
+          // argument.
+          if (!attributeLastArgParmPackSupport(*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,10 @@
 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 pack expansion in the last argument">;
+def err_attribute_parm_pack_last_argument_only : Error<
+  "pack expansion in attributes is restricted to only the last argument">;
 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
@@ -205,7 +205,12 @@
 class TypeArgument<string name, bit opt = 0> : Argument<name, opt>;
 class UnsignedArgument<string name, bit opt = 0> : Argument<name, opt>;
 class VariadicUnsignedArgument<string name> : Argument<name, 1>;
-class VariadicExprArgument<string name> : Argument<name, 1>;
+class VariadicExprArgument<string name, bit packs = 0> : Argument<name, 1> {
+  // Set to true if variadic expression argument supports parameter pack
+  // expansion. Setting this to true is only allowed if the argument is the last
+  // argument of the attribute.
+  bit AllowPack = packs;
+}
 class VariadicStringArgument<string name> : Argument<name, 1>;
 class VariadicIdentifierArgument<string name> : Argument<name, 1>;
 
@@ -770,7 +775,8 @@
 
 def Annotate : InheritableParamAttr {
   let Spellings = [Clang<"annotate">];
-  let Args = [StringArgument<"Annotation">, VariadicExprArgument<"Args">];
+  let Args = [StringArgument<"Annotation">,
+              VariadicExprArgument<"Args", /*AllowPack*/1>];
   // Ensure that the annotate attribute can be used with
   // '#pragma clang attribute' even though it has no subject list.
   let AdditionalMembers = [{
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to