string Namespace = namespace;
int Version = version;
}
+class C2x<string namespace, string name> : Spelling<name, "C2x"> {
+ string Namespace = namespace;
+}
+
class Keyword<string name> : Spelling<name, "Keyword">;
class Pragma<string namespace, string name> : Spelling<name, "Pragma"> {
string Namespace = namespace;
def Deprecated : InheritableAttr {
let Spellings = [GCC<"deprecated">, Declspec<"deprecated">,
- CXX11<"","deprecated", 201309>];
+ CXX11<"","deprecated", 201309>, C2x<"", "deprecated">];
let Args = [StringArgument<"Message", 1>,
// An optional string argument that enables us to provide a
// Fix-It.
Microsoft,
// Is the identifier known as a C++-style attribute?
CXX,
+ // Is the identifier known as a C-style attribute?
+ C,
// Is the identifier known as a pragma attribute?
Pragma
};
LANGOPT(CoroutinesTS , 1, 0, "C++ coroutines TS")
LANGOPT(RelaxedTemplateTemplateArgs, 1, 0, "C++17 relaxed matching of template template arguments")
+LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes")
+
BENIGN_LANGOPT(ThreadsafeStatics , 1, 1, "thread-safe static initializers")
LANGOPT(POSIXThreads , 1, 0, "POSIX thread support")
LANGOPT(Blocks , 1, 0, "blocks extension to C")
def fast : Flag<["-"], "fast">, Group<f_Group>;
def fasynchronous_unwind_tables : Flag<["-"], "fasynchronous-unwind-tables">, Group<f_Group>;
+def fdouble_square_bracket_attributes : Flag<[ "-" ], "fdouble-square-bracket-attributes">,
+ Group<f_Group>, Flags<[DriverOption, CC1Option]>,
+ HelpText<"Enable '[[]]' attributes in all C and C++ language modes">;
+def fno_double_square_bracket_attributes : Flag<[ "-" ], "fno-fdouble-square-bracket-attributes">,
+ Group<f_Group>, Flags<[DriverOption]>,
+ HelpText<"Disable '[[]]' attributes in all C and C++ language modes">;
+
def fautolink : Flag <["-"], "fautolink">, Group<f_Group>;
def fno_autolink : Flag <["-"], "fno-autolink">, Group<f_Group>,
Flags<[DriverOption, CC1Option]>,
private:
void ParseBlockId(SourceLocation CaretLoc);
- // Check for the start of a C++11 attribute-specifier-seq in a context where
- // an attribute is not allowed.
+ /// Are [[]] attributes enabled?
+ bool standardAttributesAllowed() const {
+ const LangOptions &LO = getLangOpts();
+ return LO.DoubleSquareBracketAttributes;
+ }
+
+ // Check for the start of an attribute-specifier-seq in a context where an
+ // attribute is not allowed.
bool CheckProhibitedCXX11Attribute() {
assert(Tok.is(tok::l_square));
- if (!getLangOpts().CPlusPlus11 || NextToken().isNot(tok::l_square))
+ if (!standardAttributesAllowed() || NextToken().isNot(tok::l_square))
return false;
return DiagnoseProhibitedCXX11Attribute();
}
+
bool DiagnoseProhibitedCXX11Attribute();
void CheckMisplacedCXX11Attribute(ParsedAttributesWithRange &Attrs,
SourceLocation CorrectLocation) {
- if (!getLangOpts().CPlusPlus11)
+ if (!standardAttributesAllowed())
return;
if ((Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) &&
Tok.isNot(tok::kw_alignas))
}
void DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs);
- // Forbid C++11 attributes that appear on certain syntactic
- // locations which standard permits but we don't supported yet,
- // for example, attributes appertain to decl specifiers.
+ // Forbid C++11 and C2x attributes that appear on certain syntactic locations
+ // which standard permits but we don't supported yet, for example, attributes
+ // appertain to decl specifiers.
void ProhibitCXX11Attributes(ParsedAttributesWithRange &Attrs,
unsigned DiagID);
- /// \brief Skip C++11 attributes and return the end location of the last one.
+ /// \brief Skip C++11 and C2x attributes and return the end location of the
+ /// last one.
/// \returns SourceLocation() if there are no attributes.
SourceLocation SkipCXX11Attributes();
- /// \brief Diagnose and skip C++11 attributes that appear in syntactic
+ /// \brief Diagnose and skip C++11 and C2x attributes that appear in syntactic
/// locations where attributes are not allowed.
void DiagnoseAndSkipCXX11Attributes();
AttributeList::Syntax Syntax);
void MaybeParseCXX11Attributes(Declarator &D) {
- if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) {
+ if (standardAttributesAllowed() && isCXX11AttributeSpecifier()) {
ParsedAttributesWithRange attrs(AttrFactory);
SourceLocation endLoc;
ParseCXX11Attributes(attrs, &endLoc);
}
void MaybeParseCXX11Attributes(ParsedAttributes &attrs,
SourceLocation *endLoc = nullptr) {
- if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) {
+ if (standardAttributesAllowed() && isCXX11AttributeSpecifier()) {
ParsedAttributesWithRange attrsWithRange(AttrFactory);
ParseCXX11Attributes(attrsWithRange, endLoc);
attrs.takeAllFrom(attrsWithRange);
void MaybeParseCXX11Attributes(ParsedAttributesWithRange &attrs,
SourceLocation *endLoc = nullptr,
bool OuterMightBeMessageSend = false) {
- if (getLangOpts().CPlusPlus11 &&
- isCXX11AttributeSpecifier(false, OuterMightBeMessageSend))
+ if (standardAttributesAllowed() &&
+ isCXX11AttributeSpecifier(false, OuterMightBeMessageSend))
ParseCXX11Attributes(attrs, endLoc);
}
SourceLocation *EndLoc = nullptr);
void ParseCXX11Attributes(ParsedAttributesWithRange &attrs,
SourceLocation *EndLoc = nullptr);
- /// \brief Parses a C++-style attribute argument list. Returns true if this
- /// results in adding an attribute to the ParsedAttributes list.
+ /// \brief Parses a C++11 (or C2x)-style attribute argument list. Returns true
+ /// if this results in adding an attribute to the ParsedAttributes list.
bool ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs, SourceLocation *EndLoc,
AS_GNU,
/// [[...]]
AS_CXX11,
+ /// [[...]]
+ AS_C2x,
/// __declspec(...)
AS_Declspec,
/// [uuid("...")] class Foo
bool isCXX11Attribute() const {
return SyntaxUsed == AS_CXX11 || isAlignasAttribute();
}
+ bool isC2xAttribute() const {
+ return SyntaxUsed == AS_C2x;
+ }
bool isKeywordAttribute() const {
return SyntaxUsed == AS_Keyword || SyntaxUsed == AS_ContextSensitiveKeyword;
}
&& Opts.OpenCLVersion >= 200);
Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional);
Opts.CoroutinesTS = Args.hasArg(OPT_fcoroutines_ts);
+
+ // Enable [[]] attributes in C++11 by default.
+ Opts.DoubleSquareBracketAttributes =
+ Args.hasFlag(OPT_fdouble_square_bracket_attributes,
+ OPT_fno_double_square_bracket_attributes, Opts.CPlusPlus11);
+
Opts.ModulesTS = Args.hasArg(OPT_fmodules_ts);
Opts.Modules = Args.hasArg(OPT_fmodules) || Opts.ModulesTS;
Opts.ModulesStrictDeclUse = Args.hasArg(OPT_fmodules_strict_decluse);
if (LangOpts.Digraphs && Char == '>') {
Kind = tok::r_square; // ':>' -> ']'
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
- } else if (LangOpts.CPlusPlus && Char == ':') {
+ } else if ((LangOpts.CPlusPlus ||
+ LangOpts.DoubleSquareBracketAttributes) &&
+ Char == ':') {
Kind = tok::coloncolon;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else {
void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &Attrs,
unsigned DiagID) {
for (AttributeList *Attr = Attrs.getList(); Attr; Attr = Attr->getNext()) {
- if (!Attr->isCXX11Attribute())
+ if (!Attr->isCXX11Attribute() && !Attr->isC2xAttribute())
continue;
if (Attr->getKind() == AttributeList::UnknownAttribute)
Diag(Attr->getLoc(), diag::warn_unknown_attribute_ignored)
case tok::l_square:
case tok::kw_alignas:
- if (!getLangOpts().CPlusPlus11 || !isCXX11AttributeSpecifier())
+ if (!standardAttributesAllowed() || !isCXX11AttributeSpecifier())
goto DoneWithDeclSpec;
ProhibitAttributes(attrs);
/// semicolon.
///
/// struct-declaration:
-/// specifier-qualifier-list struct-declarator-list
+/// [C2x] attributes-specifier-seq[opt]
+/// specifier-qualifier-list struct-declarator-list
/// [GNU] __extension__ struct-declaration
/// [GNU] specifier-qualifier-list
/// struct-declarator-list:
return ParseStructDeclaration(DS, FieldsCallback);
}
+ // Parse leading attributes.
+ ParsedAttributesWithRange Attrs(AttrFactory);
+ MaybeParseCXX11Attributes(Attrs);
+ DS.takeAttributesFrom(Attrs);
+
// Parse the common specifier-qualifiers-list piece.
ParseSpecifierQualifierList(DS);
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseGNUAttributes(attrs);
ProhibitAttributes(attrs); // GNU-style attributes are prohibited.
- if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) {
- Diag(Tok.getLocation(), getLangOpts().CPlusPlus1z
- ? diag::warn_cxx14_compat_ns_enum_attribute
- : diag::ext_ns_enum_attribute)
- << 1 /*enumerator*/;
+ if (standardAttributesAllowed() && isCXX11AttributeSpecifier()) {
+ if (getLangOpts().CPlusPlus)
+ Diag(Tok.getLocation(), getLangOpts().CPlusPlus1z
+ ? diag::warn_cxx14_compat_ns_enum_attribute
+ : diag::ext_ns_enum_attribute)
+ << 1 /*enumerator*/;
ParseCXX11Attributes(attrs);
}
DeclSpec &DS, unsigned AttrReqs, bool AtomicAllowed,
bool IdentifierRequired,
Optional<llvm::function_ref<void()>> CodeCompletionHandler) {
- if (getLangOpts().CPlusPlus11 && (AttrReqs & AR_CXX11AttributesParsed) &&
+ if (standardAttributesAllowed() && (AttrReqs & AR_CXX11AttributesParsed) &&
isCXX11AttributeSpecifier()) {
ParsedAttributesWithRange attrs(AttrFactory);
ParseCXX11Attributes(attrs);
SmallVector<SourceRange, 2> DynamicExceptionRanges;
ExprResult NoexceptExpr;
CachedTokens *ExceptionSpecTokens = nullptr;
- ParsedAttributes FnAttrs(AttrFactory);
+ ParsedAttributesWithRange FnAttrs(AttrFactory);
TypeResult TrailingReturnType;
/* LocalEndLoc is the end location for the local FunctionTypeLoc.
RParenLoc = Tracker.getCloseLocation();
LocalEndLoc = RParenLoc;
EndLoc = RParenLoc;
+
+ // If there are attributes following the identifier list, parse them and
+ // prohibit them.
+ MaybeParseCXX11Attributes(FnAttrs);
+ ProhibitAttributes(FnAttrs);
} else {
if (Tok.isNot(tok::r_paren))
ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo,
TrailingReturnType = ParseTrailingReturnType(Range);
EndLoc = Range.getEnd();
}
+ } else if (standardAttributesAllowed()) {
+ MaybeParseCXX11Attributes(FnAttrs);
}
}
}
static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName,
- IdentifierInfo *ScopeName) {
+ IdentifierInfo *ScopeName) {
switch (AttributeList::getKind(AttrName, ScopeName,
AttributeList::AS_CXX11)) {
case AttributeList::AT_CarriesDependency:
SourceLocation ScopeLoc) {
assert(Tok.is(tok::l_paren) && "Not a C++11 attribute argument list");
SourceLocation LParenLoc = Tok.getLocation();
+ const LangOptions &LO = getLangOpts();
+ AttributeList::Syntax Syntax =
+ LO.CPlusPlus ? AttributeList::AS_CXX11 : AttributeList::AS_C2x;
// If the attribute isn't known, we will not attempt to parse any
// arguments.
- if (!hasAttribute(AttrSyntax::CXX, ScopeName, AttrName,
- getTargetInfo(), getLangOpts())) {
+ if (!hasAttribute(LO.CPlusPlus ? AttrSyntax::CXX : AttrSyntax::C, ScopeName,
+ AttrName, getTargetInfo(), getLangOpts())) {
// Eat the left paren, then skip to the ending right paren.
ConsumeParen();
SkipUntil(tok::r_paren);
// GNU-scoped attributes have some special cases to handle GNU-specific
// behaviors.
ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
- ScopeLoc, AttributeList::AS_CXX11, nullptr);
+ ScopeLoc, Syntax, nullptr);
return true;
}
if (ScopeName && ScopeName->getName() == "clang")
NumArgs =
ParseClangAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
- ScopeLoc, AttributeList::AS_CXX11);
+ ScopeLoc, Syntax);
else
NumArgs =
ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, EndLoc,
- ScopeName, ScopeLoc, AttributeList::AS_CXX11);
+ ScopeName, ScopeLoc, Syntax);
const AttributeList *Attr = Attrs.getList();
if (Attr && IsBuiltInOrStandardCXX11Attribute(AttrName, ScopeName)) {
return true;
}
-/// ParseCXX11AttributeSpecifier - Parse a C++11 attribute-specifier.
+/// ParseCXX11AttributeSpecifier - Parse a C++11 or C2x attribute-specifier.
///
/// [C++11] attribute-specifier:
/// '[' '[' attribute-list ']' ']'
return;
}
- assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square)
- && "Not a C++11 attribute list");
+ assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square) &&
+ "Not a double square bracket attribute list");
Diag(Tok.getLocation(), diag::warn_cxx98_compat_attribute);
ScopeName, ScopeLoc);
if (!AttrParsed)
- attrs.addNew(AttrName,
- SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc,
- AttrLoc),
- ScopeName, ScopeLoc, nullptr, 0, AttributeList::AS_CXX11);
+ attrs.addNew(
+ AttrName,
+ SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc, AttrLoc),
+ ScopeName, ScopeLoc, nullptr, 0,
+ getLangOpts().CPlusPlus ? AttributeList::AS_CXX11
+ : AttributeList::AS_C2x);
if (TryConsumeToken(tok::ellipsis))
Diag(Tok, diag::err_cxx11_attribute_forbids_ellipsis)
SkipUntil(tok::r_square);
}
-/// ParseCXX11Attributes - Parse a C++11 attribute-specifier-seq.
+/// ParseCXX11Attributes - Parse a C++11 or C2x attribute-specifier-seq.
///
/// attribute-specifier-seq:
/// attribute-specifier-seq[opt] attribute-specifier
void Parser::ParseCXX11Attributes(ParsedAttributesWithRange &attrs,
SourceLocation *endLoc) {
- assert(getLangOpts().CPlusPlus11);
+ assert(standardAttributesAllowed());
SourceLocation StartLoc = Tok.getLocation(), Loc;
if (!endLoc)
// Normalize the attribute name, __foo__ becomes foo. This is only allowable
// for GNU attributes.
bool IsGNU = SyntaxUsed == AttributeList::AS_GNU ||
- (SyntaxUsed == AttributeList::AS_CXX11 && ScopeName == "gnu");
+ ((SyntaxUsed == AttributeList::AS_CXX11 ||
+ SyntaxUsed == AttributeList::AS_C2x) && ScopeName == "gnu");
if (IsGNU && AttrName.size() >= 4 && AttrName.startswith("__") &&
AttrName.endswith("__"))
AttrName = AttrName.slice(2, AttrName.size() - 2);
// Ensure that in the case of C++11 attributes, we look for '::foo' if it is
// unscoped.
- if (ScopeName || SyntaxUsed == AS_CXX11)
+ if (ScopeName || SyntaxUsed == AS_CXX11 || SyntaxUsed == AS_C2x)
FullName += "::";
FullName += AttrName;
--- /dev/null
+// RUN: %clang_cc1 -triple x86_64-pc-linux -fdouble-square-bracket-attributes -Wno-deprecated-declarations -ast-dump -ast-dump-filter Test %s | FileCheck --strict-whitespace %s\r
+\r
+int Test1 [[deprecated]];\r
+// CHECK: VarDecl{{.*}}Test1\r
+// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:13> "" ""\r
+\r
+enum [[deprecated("Frobble")]] Test2 {\r
+ Test3 [[deprecated]]\r
+};\r
+// CHECK: EnumDecl{{.*}}Test2\r
+// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:8, col:28> "Frobble" ""\r
+// CHECK-NEXT: EnumConstantDecl{{.*}}Test3\r
+// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:11> "" ""\r
+\r
+struct [[deprecated]] Test4 {\r
+ [[deprecated("Frobble")]] int Test5, Test6;\r
+ int Test7 [[deprecated]] : 12;\r
+};\r
+// CHECK: RecordDecl{{.*}}Test4\r
+// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:10> "" ""\r
+// CHECK-NEXT: FieldDecl{{.*}}Test5\r
+// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:5, col:25> "Frobble" ""\r
+// CHECK-NEXT: FieldDecl{{.*}}Test6\r
+// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:5, col:25> "Frobble" ""\r
+// CHECK-NEXT: FieldDecl{{.*}}Test7\r
+// CHECK-NEXT: IntegerLiteral{{.*}}'int' 12\r
+// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:15> "" ""\r
+\r
+struct [[deprecated]] Test8;\r
+// CHECK: RecordDecl{{.*}}Test8\r
+// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:10> "" ""\r
+\r
+[[deprecated]] void Test9(int Test10 [[deprecated]]);\r
+// CHECK: FunctionDecl{{.*}}Test9\r
+// CHECK-NEXT: ParmVarDecl{{.*}}Test10\r
+// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:40> "" ""\r
+// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:3> "" ""\r
+\r
+void Test11 [[deprecated]](void);\r
+// CHECK: FunctionDecl{{.*}}Test11\r
+// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:15> "" ""\r
+\r
+void Test12(void) [[deprecated]] {}\r
+// CHECK: FunctionDecl{{.*}}Test12\r
+// CHECK-NEXT: CompoundStmt\r
+// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:21> "" ""\r
--- /dev/null
+// RUN: %clang_cc1 -fsyntax-only -fdouble-square-bracket-attributes -verify %s
+
+enum [[]] E {
+ One [[]],
+ Two,
+ Three [[]]
+};
+
+enum [[]] { Four };
+[[]] enum E2 { Five }; // expected-error {{an attribute list cannot appear here}}
+
+// FIXME: this diagnostic can be improved.
+enum { [[]] Six }; // expected-error {{expected identifier}}
+
+// FIXME: this diagnostic can be improved.
+enum E3 [[]] { Seven }; // expected-error {{expected identifier or '('}}
+
+struct [[]] S1 {
+ int i [[]];
+ int [[]] j;
+ int k[10] [[]];
+ int l[[]][10];
+ [[]] int m, n;
+ int o [[]] : 12;
+};
+
+[[]] struct S2 { int a; }; // expected-error {{an attribute list cannot appear here}}
+struct S3 [[]] { int a; }; // expected-error {{an attribute list cannot appear here}}
+
+union [[]] U {
+ double d [[]];
+ [[]] int i;
+};
+
+[[]] union U2 { double d; }; // expected-error {{an attribute list cannot appear here}}
+union U3 [[]] { double d; }; // expected-error {{an attribute list cannot appear here}}
+
+struct [[]] IncompleteStruct;
+union [[]] IncompleteUnion;
+enum [[]] IncompleteEnum;
+enum __attribute__((deprecated)) IncompleteEnum2;
+
+[[]] void f1(void);
+void [[]] f2(void);
+void f3 [[]] (void);
+void f4(void) [[]];
+
+void f5(int i [[]], [[]] int j, int [[]] k);
+
+void f6(a, b) [[]] int a; int b; { // expected-error {{an attribute list cannot appear here}}
+}
+
+// FIXME: technically, an attribute list cannot appear here, but we currently
+// parse it as part of the return type of the function, which is reasonable
+// behavior given that we *don't* want to parse it as part of the K&R parameter
+// declarations. It is disallowed to avoid a parsing ambiguity we already
+// handle well.
+int (*f7(a, b))(int, int) [[]] int a; int b; {
+ return 0;
+}
+
+[[]] int a, b;
+int c [[]], d [[]];
+
+void f8(void) [[]] {
+ [[]] int i, j;
+ int k, l [[]];
+}
+
+[[]] void f9(void) {
+ int i[10] [[]];
+ int (*fp1)(void)[[]];
+ int (*fp2 [[]])(void);
+
+ int * [[]] *ipp;
+}
+
+void f10(int j[static 10] [[]], int k[*] [[]]);
+
+void f11(void) {
+ [[]] {}
+ [[]] if (1) {}
+
+ [[]] switch (1) {
+ [[]] case 1: [[]] break;
+ [[]] default: break;
+ }
+
+ goto foo;
+ [[]] foo: (void)1;
+
+ [[]] for (;;);
+ [[]] while (1);
+ [[]] do [[]] { } while(1);
+
+ [[]] (void)1;
+
+ [[]];
+
+ (void)sizeof(int [4][[]]);
+ (void)sizeof(struct [[]] S3 { int a [[]]; });
+
+ [[]] return;
+}
+
+[[attr]] void f12(void); // expected-warning {{unknown attribute 'attr' ignored}}
+[[vendor::attr]] void f13(void); // expected-warning {{unknown attribute 'attr' ignored}}
+
+// Ensure that asm statements properly handle double colons.
+void test_asm(void) {
+ asm("ret" :::);
+ asm("foo" :: "r" (xx)); // expected-error {{use of undeclared identifier 'xx'}}
+}
+
+// Do not allow 'using' to introduce vendor attribute namespaces.
+[[using vendor: attr1, attr2]] void f14(void); // expected-error {{expected ']'}} \
+ // expected-warning {{unknown attribute 'vendor' ignored}} \
+ // expected-warning {{unknown attribute 'using' ignored}}
+
+struct [[]] S4 *s; // expected-error {{an attribute list cannot appear here}}
+struct S5 {};
+int c = sizeof(struct [[]] S5); // expected-error {{an attribute list cannot appear here}}
--- /dev/null
+// RUN: %clang_cc1 -fsyntax-only -fdouble-square-bracket-attributes -verify %s
+// expected-no-diagnostics
+
+enum __attribute__((deprecated)) E1 : int; // ok
+enum [[deprecated]] E2 : int;
+
+@interface Base
+@end
+
+@interface S : Base
+- (void) bar;
+@end
+
+@interface T : Base
+- (S *) foo;
+@end
+
+
+void f(T *t) {
+ [[]][[t foo] bar];
+}
--- /dev/null
+// RUN: %clang_cc1 %s -verify -fsyntax-only -fdouble-square-bracket-attributes
+
+int f() [[deprecated]]; // expected-note 2 {{'f' has been explicitly marked deprecated here}}
+void g() [[deprecated]];// expected-note {{'g' has been explicitly marked deprecated here}}
+void g();
+
+extern int var [[deprecated]]; // expected-note 2 {{'var' has been explicitly marked deprecated here}}
+
+int a() {
+ int (*ptr)() = f; // expected-warning {{'f' is deprecated}}
+ f(); // expected-warning {{'f' is deprecated}}
+
+ // test if attributes propagate to functions
+ g(); // expected-warning {{'g' is deprecated}}
+
+ return var; // expected-warning {{'var' is deprecated}}
+}
+
+// test if attributes propagate to variables
+extern int var;
+int w() {
+ return var; // expected-warning {{'var' is deprecated}}
+}
+
+int old_fn() [[deprecated]];// expected-note {{'old_fn' has been explicitly marked deprecated here}}
+int old_fn();
+int (*fn_ptr)() = old_fn; // expected-warning {{'old_fn' is deprecated}}
+
+int old_fn() {
+ return old_fn()+1; // no warning, deprecated functions can use deprecated symbols.
+}
+
+struct foo {
+ int x [[deprecated]]; // expected-note 3 {{'x' has been explicitly marked deprecated here}}
+};
+
+void test1(struct foo *F) {
+ ++F->x; // expected-warning {{'x' is deprecated}}
+ struct foo f1 = { .x = 17 }; // expected-warning {{'x' is deprecated}}
+ struct foo f2 = { 17 }; // expected-warning {{'x' is deprecated}}
+}
+
+typedef struct foo foo_dep [[deprecated]]; // expected-note {{'foo_dep' has been explicitly marked deprecated here}}
+foo_dep *test2; // expected-warning {{'foo_dep' is deprecated}}
+
+struct [[deprecated, // expected-note {{'bar_dep' has been explicitly marked deprecated here}}
+ invalid_attribute]] bar_dep ; // expected-warning {{unknown attribute 'invalid_attribute' ignored}}
+
+struct bar_dep *test3; // expected-warning {{'bar_dep' is deprecated}}
+
+[[deprecated("this is the message")]] int i; // expected-note {{'i' has been explicitly marked deprecated here}}
+void test4(void) {
+ i = 12; // expected-warning {{'i' is deprecated: this is the message}}
+}
assert(V != "GCC" && "Given a GCC spelling, which means this hasn't been"
"flattened!");
- if (V == "CXX11" || V == "Pragma")
+ if (V == "CXX11" || V == "C2x" || V == "Pragma")
NS = Spelling.getValueAsString("Namespace");
bool Unset;
K = Spelling.getValueAsBitOrUnset("KnownToGCC", Unset);
if (Variety == "GNU") {
Prefix = " __attribute__((";
Suffix = "))";
- } else if (Variety == "CXX11") {
+ } else if (Variety == "CXX11" || Variety == "C2x") {
Prefix = " [[";
Suffix = "]]";
std::string Namespace = Spellings[I].nameSpace();
// If this is the C++11 variety, also add in the LangOpts test.
if (Variety == "CXX11")
Test += " && LangOpts.CPlusPlus11";
+ else if (Variety == "C2x")
+ Test += " && LangOpts.DoubleSquareBracketAttributes";
} else if (Variety == "CXX11")
// C++11 mode should be checked against LangOpts, which is presumed to be
// present in the caller.
Test = "LangOpts.CPlusPlus11";
+ else if (Variety == "C2x")
+ Test = "LangOpts.DoubleSquareBracketAttributes";
std::string TestStr =
!Test.empty() ? Test + " ? " + llvm::itostr(Version) + " : 0" : "1";
// and declspecs. Then generate a big switch statement for each of them.
std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
std::vector<Record *> Declspec, Microsoft, GNU, Pragma;
- std::map<std::string, std::vector<Record *>> CXX;
+ std::map<std::string, std::vector<Record *>> CXX, C2x;
// Walk over the list of all attributes, and split them out based on the
// spelling variety.
Microsoft.push_back(R);
else if (Variety == "CXX11")
CXX[SI.nameSpace()].push_back(R);
+ else if (Variety == "C2x")
+ C2x[SI.nameSpace()].push_back(R);
else if (Variety == "Pragma")
Pragma.push_back(R);
}
OS << "case AttrSyntax::Pragma:\n";
OS << " return llvm::StringSwitch<int>(Name)\n";
GenerateHasAttrSpellingStringSwitch(Pragma, OS, "Pragma");
- OS << "case AttrSyntax::CXX: {\n";
- // C++11-style attributes are further split out based on the Scope.
- for (auto I = CXX.cbegin(), E = CXX.cend(); I != E; ++I) {
- if (I != CXX.begin())
- OS << " else ";
- if (I->first.empty())
- OS << "if (!Scope || Scope->getName() == \"\") {\n";
- else
- OS << "if (Scope->getName() == \"" << I->first << "\") {\n";
- OS << " return llvm::StringSwitch<int>(Name)\n";
- GenerateHasAttrSpellingStringSwitch(I->second, OS, "CXX11", I->first);
- OS << "}";
- }
- OS << "\n}\n";
+ auto fn = [&OS](const char *Spelling, const char *Variety,
+ const std::map<std::string, std::vector<Record *>> &List) {
+ OS << "case AttrSyntax::" << Variety << ": {\n";
+ // C++11-style attributes are further split out based on the Scope.
+ for (auto I = List.cbegin(), E = List.cend(); I != E; ++I) {
+ if (I != List.cbegin())
+ OS << " else ";
+ if (I->first.empty())
+ OS << "if (!Scope || Scope->getName() == \"\") {\n";
+ else
+ OS << "if (Scope->getName() == \"" << I->first << "\") {\n";
+ OS << " return llvm::StringSwitch<int>(Name)\n";
+ GenerateHasAttrSpellingStringSwitch(I->second, OS, Spelling, I->first);
+ OS << "}";
+ }
+ OS << "\n}\n";
+ };
+ fn("CXX11", "CXX", CXX);
+ fn("C2x", "C", C2x);
OS << "}\n";
}
<< StringSwitch<unsigned>(Spellings[I].variety())
.Case("GNU", 0)
.Case("CXX11", 1)
- .Case("Declspec", 2)
- .Case("Microsoft", 3)
- .Case("Keyword", 4)
- .Case("Pragma", 5)
+ .Case("C2x", 2)
+ .Case("Declspec", 3)
+ .Case("Microsoft", 4)
+ .Case("Keyword", 5)
+ .Case("Pragma", 6)
.Default(0)
<< " && Scope == \"" << Spellings[I].nameSpace() << "\")\n"
<< " return " << I << ";\n";
std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
std::vector<StringMatcher::StringPair> GNU, Declspec, Microsoft, CXX11,
- Keywords, Pragma;
+ Keywords, Pragma, C2x;
std::set<std::string> Seen;
for (const auto *A : Attrs) {
const Record &Attr = *A;
Matches = &CXX11;
Spelling += S.nameSpace();
Spelling += "::";
+ } else if (Variety == "C2x") {
+ Matches = &C2x;
+ Spelling += S.nameSpace();
+ Spelling += "::";
} else if (Variety == "GNU")
Matches = &GNU;
else if (Variety == "Declspec")
StringMatcher("Name", Microsoft, OS).Emit();
OS << " } else if (AttributeList::AS_CXX11 == Syntax) {\n";
StringMatcher("Name", CXX11, OS).Emit();
+ OS << " } else if (AttributeList::AS_C2x == Syntax) {\n";
+ StringMatcher("Name", C2x, OS).Emit();
OS << " } else if (AttributeList::AS_Keyword == Syntax || ";
OS << "AttributeList::AS_ContextSensitiveKeyword == Syntax) {\n";
StringMatcher("Name", Keywords, OS).Emit();
enum SpellingKind {
GNU = 1 << 0,
CXX11 = 1 << 1,
- Declspec = 1 << 2,
- Microsoft = 1 << 3,
- Keyword = 1 << 4,
- Pragma = 1 << 5
+ C2x = 1 << 2,
+ Declspec = 1 << 3,
+ Microsoft = 1 << 4,
+ Keyword = 1 << 5,
+ Pragma = 1 << 6
};
static void WriteDocumentation(RecordKeeper &Records,
SpellingKind Kind = StringSwitch<SpellingKind>(I.variety())
.Case("GNU", GNU)
.Case("CXX11", CXX11)
+ .Case("C2x", C2x)
.Case("Declspec", Declspec)
.Case("Microsoft", Microsoft)
.Case("Keyword", Keyword)
SupportedSpellings |= Kind;
std::string Name;
- if (Kind == CXX11 && !I.nameSpace().empty())
+ if ((Kind == CXX11 || Kind == C2x) && !I.nameSpace().empty())
Name = I.nameSpace() + "::";
Name += I.name();
// List what spelling syntaxes the attribute supports.
OS << ".. csv-table:: Supported Syntaxes\n";
- OS << " :header: \"GNU\", \"C++11\", \"__declspec\", \"Keyword\",";
+ OS << " :header: \"GNU\", \"C++11\", \"C2x\", \"__declspec\", \"Keyword\",";
OS << " \"Pragma\", \"Pragma clang attribute\"\n\n";
OS << " \"";
if (SupportedSpellings & GNU) OS << "X";
OS << "\",\"";
if (SupportedSpellings & CXX11) OS << "X";
OS << "\",\"";
+ if (SupportedSpellings & C2x) OS << "X";
+ OS << "\",\"";
if (SupportedSpellings & Declspec) OS << "X";
OS << "\",\"";
if (SupportedSpellings & Keyword) OS << "X";