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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits