[PATCH] Generalized attribute support

Alp Toker alp at nuanti.com
Wed Jan 15 07:10:19 PST 2014


On 15/01/2014 01:50, Richard Smith wrote:
> On Tue, Jan 14, 2014 at 5:47 PM, Richard Smith <richard at metafoo.co.uk 
> <mailto:richard at metafoo.co.uk>> wrote:
>
>     On Tue, Jan 14, 2014 at 5:23 PM, Alp Toker <alp at nuanti.com
>     <mailto:alp at nuanti.com>> wrote:
>
>         This patch generalizes C++11 attributes for use in C and
>         C-like dialects, and additionally enables the new syntax as an
>         extension to C11.
>
>
>     Why do you allow this by default in C11? And conversely, why not
>     in C90 / C99?
>
>
> I think maybe this was unclear. I'd prefer one of these two options:
>
> 1) A -fcxx-attributes argument (or similar) to enable C++ attribute 
> syntax outside C++ (and either do or don't allow them by default in 
> C++98), or

Already considered this. The feature doesn't change the meaning of 
existing code and doesn't introduce lexical ambiguity so an f-group flag 
doesn't make much sense to me.

Support for the new attribute syntax can be legitimately detected with 
configure-time or feature detection macros. There's no need to introduce 
an f flag just to state that "we might be using attributes in C in our 
code, or some of the headers we include might be using them".

We also don't want users to enable the syntax in modes that we haven't 
tested much yet like pre-C11 Objective-C and historical C modes, yet an 
f-flag would be expected to do that.

As a thought experiment, consider the case where third party user 
libraries start using this facility and your project includes their 
public headers, either intentionally or as secondary dependencies. 
Without a compiler flag, things "just work", but with a flag you have to 
go and switch it on. It's not obvious when users should do that or 
practical to document it in a way that'll be heard.

Keep in mind also that we're introducing a strongly-worded extension 
warning in C. That should be more informative than a parse failure 
because it explains what's going on and offers a recovery. We'd miss out 
on that with a -f(cxx|generalized)-attributes option.

> 2) C++ attributes available by default in all language modes.
>
> I'd prefer the first option (defaulting to following the language 
> standard more strictly) -- I think this would be the first time we 
> enabled a C++ language feature in C modes, if we went with the second 
> option.


I have a preference for tying this to C++11 / C11, at the very least for 
the initial rollout.

The justification here is human rather than technical: Nearly all 
has_feature() and has_extension() checks are for C++11 / C11 so there's 
a higher likelihood that developers explicitly enabling the new 
standards will have done the background research to use new feature 
portably.

It's also reasonable to assume that C++11 / C11 will be the baseline for 
upcoming ISO C, OpenMP and other standards. The intention of this 
proposal is to support standardisation and investigate new uses rather 
than bringing 'fun' into older language standards.


>     If we're going to allow these anywhere by default, C++98 would
>     seem like a good place to start. I don't believe they introduce
>     any ambiguities outside of Objective-C(++), and we already
>     disambiguate those cases. (There's an ambiguity with lambdas, but
>     we don't need to address that until/unless we allow lambdas in C++98.)
>


Indeed. I've given it a spin locally with the feature hard-coded and 
enabled in all language standards supported by clang. The full test 
suite passes with no change in diagnostics or output so that's an 
indicator of viability.


>         All features are carried forward from C++11, including usage
>         on declarations, attributed statements, scoped attribute
>         names, GNU attribute aliases and the clang-specific attribute
>         namespace.
>
>         A new feature detection macro is provided, breaking from the
>         usual c/cxx prefix convention in order to facilitate portable
>         detection in C++ and C modes:
>
>         __has_feature(attributes) - 1 in C++11, otherwise 0.
>         __has_extension(attributes) - 1 in C++11 and C11, otherwise 0.
>
>
>     This is already available as __has_feature(cxx_attributes); using
>     __has_extension(cxx_attributes) in C would seem to be the right
>     approach here (we're allowing C++ attributes as an extension in
>     C). This is what we already do for C99 and C11 features which we
>     accept in C++.
>
>         The new warning flag -W(no-)generalized-attributes suppresses
>         the new extension warning in C. The same flag can also be used
>         to selectively disable attribute compatibility warnings
>         produced by the pre-existing -Wc++98-compat option.
>
>
>     OK, so this is why you wanted us to pick a name for this feature;
>     you're going to use it as a diagnostic name. I think this should
>     be called -Wc++-attributes, to match our existing
>     compatible-for-all-time feature name cxx_attributes. We can add an
>     alias to a better name if we ever need one, but for now, we're
>     pretty clearly allowing a C++ feature in C, so calling it
>     "c++-something" makes sense to me.
>
>         Newly added tests have been shared with C++11 where possible
>         to ensure consistency between language modes.
>
>
>     Does this do the right thing for (for instance)
>
>       struct S {
>         [[ gnu::aligned(8) ]] int n;
>       };
>
>     ? (Structs use different parsing code in C and C++. )
>

I'm opposed to naming them "C++ attributes" or "C++11 attributes" 
because we've always taken care not to talk about C++ features in C, 
Objective-C, OpenMP etc.

The intention here is to offer a reference implementation that C 
dialects can adopt as their own, hopefully saving us the headache of an 
additional four new syntaxes to support a few years down the line in 
addition to the three existing. Tagging them as a loan feature from C++ 
would be an own goal.

Rationale: I wouldn't expect "C++ Attributes" to appear in the next ISO 
C any more than I'd have expected "Microsoft C++/CLI attributes" to 
appear in the C++11 standard even though that's presumably whence Herb 
Sutter et al. brought the feature. As someone on the C++ committee I'm 
sure you can appreciate that :-)

Overall I think this is only worth moving forward with if we present it 
as first-class feature that C-like languages are encouraged converge upon.

I've attached a patch addressing your other points of review and making 
the two feature detection names synonymous.

Alp.

-- 
http://www.nuanti.com
the browser experts

-------------- next part --------------
diff --git a/docs/LanguageExtensions.rst b/docs/LanguageExtensions.rst
index 5618805..ea2d955 100644
--- a/docs/LanguageExtensions.rst
+++ b/docs/LanguageExtensions.rst
@@ -924,6 +924,13 @@ C11 ``_Thread_local``
 Use ``__has_feature(c_thread_local)`` or ``__has_extension(c_thread_local)``
 to determine if support for ``_Thread_local`` variables is enabled.
 
+Generalized attributes
+^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(attributes)`` or ``__has_extension(attributes)`` to
+determine support for parsing and handling attributes with the C++11-style
+square bracket notation. Available as an extension in C11.
+
 Checks for Type Traits
 ======================
 
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index bf77259..edafbc7 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -115,6 +115,10 @@ def CXXPre1yCompat : DiagGroup<"c++98-c++11-compat">;
 def CXXPre1yCompatPedantic : DiagGroup<"c++98-c++11-compat-pedantic",
                                        [CXXPre1yCompat]>;
 
+// A group for warnings about use of C++11-style generalized attributes as an
+// extension in C and earlier C++ versions.
+def CXXAttributes : DiagGroup<"generalized-attributes">;
+
 def CXX98CompatBindToTemporaryCopy :
   DiagGroup<"c++98-compat-bind-to-temporary-copy">;
 def CXX98CompatLocalTypeTemplateArgs :
@@ -126,6 +130,7 @@ def CXX98Compat : DiagGroup<"c++98-compat",
                             [CXX98CompatBindToTemporaryCopy,
                              CXX98CompatLocalTypeTemplateArgs,
                              CXX98CompatUnnamedTypeTemplateArgs,
+                             CXXAttributes,
                              CXXPre1yCompat]>;
 // Warnings for C++11 features which are Extensions in C++98 mode.
 def CXX98CompatPedantic : DiagGroup<"c++98-compat-pedantic",
@@ -553,7 +558,7 @@ def NonGCC : DiagGroup<"non-gcc",
 
 // A warning group for warnings about using C++11 features as extensions in
 // earlier C++ versions.
-def CXX11 : DiagGroup<"c++11-extensions", [CXX11ExtraSemi, CXX11LongLong]>;
+def CXX11 : DiagGroup<"c++11-extensions", [CXX11ExtraSemi, CXX11LongLong, CXXAttributes]>;
 
 // A warning group for warnings about using C++1y features as extensions in
 // earlier C++ versions.
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 79e1aeb..a8ae884 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -518,7 +518,9 @@ def warn_cxx98_compat_alignas : Warning<"'alignas' is incompatible with C++98">,
   InGroup<CXX98Compat>, DefaultIgnore;
 def warn_cxx98_compat_attribute : Warning<
   "generalized attributes are incompatible with C++98">,
-  InGroup<CXX98Compat>, DefaultIgnore;
+  InGroup<CXXAttributes>, DefaultIgnore;
+def ext_cxx11_attribute_in_c : ExtWarn<
+  "generalized attributes are a non-standard C extension">, InGroup<CXXAttributes>;
 def err_cxx11_attribute_forbids_arguments : Error<
   "attribute '%0' cannot have an argument list">;
 def err_cxx11_attribute_forbids_ellipsis : Error<
diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def
index 34dfea2..b5d63b8 100644
--- a/include/clang/Basic/LangOptions.def
+++ b/include/clang/Basic/LangOptions.def
@@ -62,6 +62,7 @@ LANGOPT(Trigraphs         , 1, 0,"trigraphs")
 LANGOPT(LineComment       , 1, 0, "'//' comments")
 LANGOPT(Bool              , 1, 0, "bool, true, and false keywords")
 LANGOPT(WChar             , 1, CPlusPlus, "wchar_t keyword")
+LANGOPT(CXXAttributes     , 1, 0, "generalized attributes")
 BENIGN_LANGOPT(DollarIdents   , 1, 1, "'$' in identifiers")
 BENIGN_LANGOPT(AsmPreprocessor, 1, 0, "preprocessor in asm mode")
 BENIGN_LANGOPT(GNUMode        , 1, 1, "GNU extensions")
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index aa7aca3..8efe508 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -1941,14 +1941,14 @@ private:
   // an attribute is not allowed.
   bool CheckProhibitedCXX11Attribute() {
     assert(Tok.is(tok::l_square));
-    if (!getLangOpts().CPlusPlus11 || NextToken().isNot(tok::l_square))
+    if (!getLangOpts().CXXAttributes || NextToken().isNot(tok::l_square))
       return false;
     return DiagnoseProhibitedCXX11Attribute();
   }
   bool DiagnoseProhibitedCXX11Attribute();
   void CheckMisplacedCXX11Attribute(ParsedAttributesWithRange &Attrs,
                                     SourceLocation CorrectLocation) {
-    if (!getLangOpts().CPlusPlus11)
+    if (!getLangOpts().CXXAttributes)
       return;
     if ((Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) &&
         Tok.isNot(tok::kw_alignas))
@@ -2004,7 +2004,7 @@ private:
   IdentifierLoc *ParseIdentifierLoc();
 
   void MaybeParseCXX11Attributes(Declarator &D) {
-    if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) {
+    if (getLangOpts().CXXAttributes && isCXX11AttributeSpecifier()) {
       ParsedAttributesWithRange attrs(AttrFactory);
       SourceLocation endLoc;
       ParseCXX11Attributes(attrs, &endLoc);
@@ -2013,7 +2013,7 @@ private:
   }
   void MaybeParseCXX11Attributes(ParsedAttributes &attrs,
                                  SourceLocation *endLoc = 0) {
-    if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) {
+    if (getLangOpts().CXXAttributes && isCXX11AttributeSpecifier()) {
       ParsedAttributesWithRange attrsWithRange(AttrFactory);
       ParseCXX11Attributes(attrsWithRange, endLoc);
       attrs.takeAllFrom(attrsWithRange);
@@ -2022,7 +2022,7 @@ private:
   void MaybeParseCXX11Attributes(ParsedAttributesWithRange &attrs,
                                  SourceLocation *endLoc = 0,
                                  bool OuterMightBeMessageSend = false) {
-    if (getLangOpts().CPlusPlus11 &&
+    if (getLangOpts().CXXAttributes &&
         isCXX11AttributeSpecifier(false, OuterMightBeMessageSend))
       ParseCXX11Attributes(attrs, endLoc);
   }
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index bb20ae7..987225f 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -1106,6 +1106,9 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
   // C++ has wchar_t keyword.
   Opts.WChar = Opts.CPlusPlus;
 
+  // C++11 generalized attributes, also available as a C11 extension.
+  Opts.CXXAttributes = Opts.CPlusPlus11 || Opts.C11;
+
   Opts.GNUKeywords = Opts.GNUMode;
   Opts.CXXOperatorNames = Opts.CPlusPlus;
 
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index 721760a..9ac41b3 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -920,7 +920,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
            .Case("cxx_alias_templates", LangOpts.CPlusPlus11)
            .Case("cxx_alignas", LangOpts.CPlusPlus11)
            .Case("cxx_atomic", LangOpts.CPlusPlus11)
-           .Case("cxx_attributes", LangOpts.CPlusPlus11)
+           .Cases("cxx_attributes", "attributes", LangOpts.CPlusPlus11)
            .Case("cxx_auto_type", LangOpts.CPlusPlus11)
            .Case("cxx_constexpr", LangOpts.CPlusPlus11)
            .Case("cxx_decltype", LangOpts.CPlusPlus11)
@@ -1036,6 +1036,7 @@ static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) {
            .Case("cxx_range_for", LangOpts.CPlusPlus)
            .Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus)
            .Case("cxx_rvalue_references", LangOpts.CPlusPlus)
+           .Cases("cxx_attributes", "attributes", LangOpts.CXXAttributes)
            // C++1y features supported by other languages as extensions.
            .Case("cxx_binary_literals", true)
            .Case("cxx_init_captures", LangOpts.CPlusPlus11)
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index abed17a..ad314d5 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1289,8 +1289,7 @@ bool Parser::DiagnoseProhibitedCXX11Attribute() {
 /// provide a fixit moving them to the right place.
 void Parser::DiagnoseMisplacedCXX11Attribute(ParsedAttributesWithRange &Attrs,
                                              SourceLocation CorrectLocation) {
-  assert((Tok.is(tok::l_square) && NextToken().is(tok::l_square)) ||
-         Tok.is(tok::kw_alignas));
+  assert(isCXX11AttributeSpecifier());
 
   // Consume the attributes.
   SourceLocation Loc = Tok.getLocation();
@@ -1455,8 +1454,8 @@ bool Parser::MightBeDeclarator(unsigned Context) {
     return getLangOpts().CPlusPlus;
 
   case tok::l_square: // Might be an attribute on an unnamed bit-field.
-    return Context == Declarator::MemberContext && getLangOpts().CPlusPlus11 &&
-           NextToken().is(tok::l_square);
+    return Context == Declarator::MemberContext &&
+           getLangOpts().CXXAttributes && NextToken().is(tok::l_square);
 
   case tok::colon: // Might be a typo for '::' or an unnamed bit-field.
     return Context == Declarator::MemberContext || getLangOpts().CPlusPlus;
@@ -2512,7 +2511,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
 
     case tok::l_square:
     case tok::kw_alignas:
-      if (!getLangOpts().CPlusPlus11 || !isCXX11AttributeSpecifier())
+      if (!getLangOpts().CXXAttributes || !isCXX11AttributeSpecifier())
         goto DoneWithDeclSpec;
 
       ProhibitAttributes(attrs);
@@ -3260,6 +3259,9 @@ ParseStructDeclaration(ParsingDeclSpec &DS, FieldCallback &Fields) {
     return ParseStructDeclaration(DS, Fields);
   }
 
+  // Optional C++11 attribute-specifier
+  MaybeParseCXX11Attributes(DS.getAttributes());
+
   // Parse the common specifier-qualifiers-list piece.
   ParseSpecifierQualifierList(DS);
 
@@ -4305,7 +4307,7 @@ bool Parser::isConstructorDeclarator() {
 
   // A C++11 attribute here signals that we have a constructor, and is an
   // attribute on the first constructor parameter.
-  if (getLangOpts().CPlusPlus11 &&
+  if (getLangOpts().CXXAttributes &&
       isCXX11AttributeSpecifier(/*Disambiguate*/ false,
                                 /*OuterMightBeMessageSend*/ true)) {
     TPA.Revert();
@@ -4382,7 +4384,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
                                        bool CXX11AttributesAllowed,
                                        bool AtomicAllowed,
                                        bool IdentifierRequired) {
-  if (getLangOpts().CPlusPlus11 && CXX11AttributesAllowed &&
+  if (getLangOpts().CXXAttributes && CXX11AttributesAllowed &&
       isCXX11AttributeSpecifier()) {
     ParsedAttributesWithRange attrs(AttrFactory);
     ParseCXX11Attributes(attrs);
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 2361bc1..641529f 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -1079,7 +1079,7 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) {
     // C++11 attributes
   case tok::l_square: // enum E [[]] x
     // Note, no tok::kw_alignas here; alignas cannot appertain to a type.
-    return getLangOpts().CPlusPlus11 && NextToken().is(tok::l_square);
+    return getLangOpts().CXXAttributes && NextToken().is(tok::l_square);
   case tok::greater:
     // template<class T = class X>
     return getLangOpts().CPlusPlus;
@@ -3206,7 +3206,9 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
   assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square)
       && "Not a C++11 attribute list");
 
-  Diag(Tok.getLocation(), diag::warn_cxx98_compat_attribute);
+  Diag(Tok.getLocation(), getLangOpts().CPlusPlus
+                              ? diag::warn_cxx98_compat_attribute
+                              : diag::ext_cxx11_attribute_in_c);
 
   ConsumeBracket();
   ConsumeBracket();
@@ -3226,6 +3228,15 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
       // Break out to the "expected ']'" diagnostic.
       break;
 
+    // In C, contextually convert two adjacent ':' tokens to '::'.
+    if (!getLangOpts().CPlusPlus && Tok.is(tok::colon) &&
+        NextToken().is(tok::colon) && areTokensAdjacent(Tok, NextToken())) {
+      SourceLocation ColonLoc = ConsumeToken();
+      Tok.setKind(tok::coloncolon);
+      Tok.setLocation(ColonLoc);
+      Tok.setLength(2);
+    }
+
     // scoped attribute
     if (TryConsumeToken(tok::coloncolon)) {
       ScopeName = AttrName;
@@ -3289,7 +3300,7 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
 ///       attribute-specifier-seq[opt] attribute-specifier
 void Parser::ParseCXX11Attributes(ParsedAttributesWithRange &attrs,
                                   SourceLocation *endLoc) {
-  assert(getLangOpts().CPlusPlus11);
+  assert(getLangOpts().CXXAttributes);
 
   SourceLocation StartLoc = Tok.getLocation(), Loc;
   if (!endLoc)
diff --git a/test/Lexer/has_feature_c1x.c b/test/Lexer/has_feature_c1x.c
index e26e309..a6e6204 100644
--- a/test/Lexer/has_feature_c1x.c
+++ b/test/Lexer/has_feature_c1x.c
@@ -46,6 +46,15 @@ int no_thread_local();
 // CHECK-1X: has_thread_local
 // CHECK-NO-1X: no_thread_local
 
+#if __has_extension(attributes)
+int has_attributes();
+#else
+int no_attributes();
+#endif
+
+// CHECK-1X: has_attributes
+// CHECK-NO-1X: no_attributes
+
 #if __STDC_VERSION__ > 199901L
 int is_c1x();
 #else
diff --git a/test/Lexer/has_feature_cxx0x.cpp b/test/Lexer/has_feature_cxx0x.cpp
index b2fe842..36a17b8 100644
--- a/test/Lexer/has_feature_cxx0x.cpp
+++ b/test/Lexer/has_feature_cxx0x.cpp
@@ -78,8 +78,17 @@ int no_trailing_return();
 // CHECK-11: has_trailing_return
 // CHECK-NO-11: no_trailing_return
 
-
 #if __has_feature(cxx_attributes)
+int has_cxx_attributes();
+#else
+int no_cxx_attributes();
+#endif
+
+// CHECK-1Y: has_cxx_attributes
+// CHECK-11: has_cxx_attributes
+// CHECK-NO-11: no_cxx_attributes
+
+#if __has_feature(attributes)
 int has_attributes();
 #else
 int no_attributes();
@@ -89,7 +98,6 @@ int no_attributes();
 // CHECK-11: has_attributes
 // CHECK-NO-11: no_attributes
 
-
 #if __has_feature(cxx_static_assert)
 int has_static_assert();
 #else
diff --git a/test/Parser/cxx11-stmt-attributes.cpp b/test/Parser/cxx11-stmt-attributes.cpp
index 9374b58..962abcb 100644
--- a/test/Parser/cxx11-stmt-attributes.cpp
+++ b/test/Parser/cxx11-stmt-attributes.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c11 -Wno-generalized-attributes -x c %s
 
 void foo(int i) {
 
@@ -20,14 +21,16 @@ void foo(int i) {
   [[unknown_attribute]] goto here; // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
   [[unknown_attribute]] here: // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
 
+  [[unknown_attribute]] return; // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
+
+#ifdef __cplusplus
   [[unknown_attribute]] try { // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
   } catch (...) {
   }
 
-  [[unknown_attribute]] return; // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
-	 
-
   alignas(8) ; // expected-error {{'alignas' attribute cannot be applied to a statement}}
+#endif
+
   [[noreturn]] { } // expected-error {{'noreturn' attribute cannot be applied to a statement}}
   [[noreturn]] if (0) { } // expected-error {{'noreturn' attribute cannot be applied to a statement}}
   [[noreturn]] for (;;); // expected-error {{'noreturn' attribute cannot be applied to a statement}}
@@ -48,9 +51,11 @@ void foo(int i) {
   [[fastcall]] goto there; // expected-warning {{unknown attribute 'fastcall' ignored}}
   [[noinline]] there: // expected-warning {{unknown attribute 'noinline' ignored}}
 
+#ifdef __cplusplus
   [[lock_returned]] try { // expected-warning {{unknown attribute 'lock_returned' ignored}}
   } catch (...) {
   }
+#endif
 
   [[weakref]] return; // expected-warning {{unknown attribute 'weakref' ignored}}
 
@@ -71,9 +76,11 @@ void foo(int i) {
 
   [[carries_dependency]] goto here; // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
 
+#ifdef __cplusplus
   [[carries_dependency]] try { // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
   } catch (...) {
   }
+#endif
 
   [[carries_dependency]] return; // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
 
diff --git a/test/Parser/generalized-attributes.c b/test/Parser/generalized-attributes.c
new file mode 100644
index 0000000..ce95dcc
--- /dev/null
+++ b/test/Parser/generalized-attributes.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c11 -Wno-generalized-attributes -Werror %s
+// RUN: %clang_cc1 -fsyntax-only -std=c11 -Wno-c++11-extensions -Werror %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c11 %s
+
+[[noreturn]] void f4(); // expected-warning {{generalized attributes are a non-standard C extension}}
diff --git a/test/Parser/generalized-attributes.cpp b/test/Parser/generalized-attributes.cpp
new file mode 100644
index 0000000..ca681a6
--- /dev/null
+++ b/test/Parser/generalized-attributes.cpp
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -Wno-generalized-attributes -Werror %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -Wno-c++11-extensions -Werror %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -verify %s
+
+int with_attribute [[ ]]; // expected-warning {{generalized attributes are incompatible with C++98}}
diff --git a/test/SemaCXX/cxx11-attr-print.cpp b/test/SemaCXX/cxx11-attr-print.cpp
index 01325d3..e3e8334 100644
--- a/test/SemaCXX/cxx11-attr-print.cpp
+++ b/test/SemaCXX/cxx11-attr-print.cpp
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 -std=c++11 -ast-print -fms-extensions %s | FileCheck %s
-//
+// RUN: %clang_cc1 -ast-print -fms-extensions -std=c++11  %s | FileCheck -check-prefix=CHECK -check-prefix=CHECK-CXX %s
+// RUN: %clang_cc1 -ast-print -fms-extensions -std=c11 -Wno-generalized-attributes -x c %s | FileCheck -check-prefix=CHECK -check-prefix=CHECK-C %s
+
 // CHECK: int x __attribute__((aligned(4)));
 int x __attribute__((aligned(4)));
 
@@ -16,11 +17,16 @@ int a __attribute__((deprecated("warning")));
 // CHECK: int b {{\[}}[gnu::deprecated("warning")]];
 int b [[gnu::deprecated("warning")]];
 
-// CHECK: int cxx11_alignas alignas(4);
+#ifdef __cplusplus
+// CHECK-CXX: int cxx11_alignas alignas(4);
 alignas(4) int cxx11_alignas;
 
-// CHECK: int c11_alignas _Alignas(alignof(int));
+// CHECK-CXX: int c11_alignas _Alignas(alignof(int));
+_Alignas(int) int c11_alignas;
+#else
+// CHECK-C: int c11_alignas _Alignas(_Alignof(int));
 _Alignas(int) int c11_alignas;
+#endif
 
 // CHECK: void foo() __attribute__((const));
 void foo() __attribute__((const));
@@ -55,10 +61,21 @@ inline void f7 [[gnu::gnu_inline]] ();
 // CHECK: __attribute__((format(printf, 2, 3)));
 void f8 (void *, const char *, ...) __attribute__ ((format (printf, 2, 3)));
 
-// CHECK: int m __attribute__((aligned(4
-// CHECK: int n alignas(4
-// CHECK: static int f() __attribute__((pure))
-// CHECK: static int g() {{\[}}[gnu::pure]]
+// CHECK: struct T {
+// CHECK: int n1 {{\[}}[gnu::aligned(16)]];
+// CHECK: int n2 {{\[}}[gnu::aligned(8)]];
+// CHECK: };
+struct T {
+  [[gnu::aligned(16)]] int n1;
+  int n2[[gnu::aligned(8)]];
+};
+
+#ifdef __cplusplus
+
+// CHECK-CXX: int m __attribute__((aligned(4
+// CHECK-CXX: int n alignas(4
+// CHECK-CXX: static int f() __attribute__((pure))
+// CHECK-CXX: static int g() {{\[}}[gnu::pure]]
 template <typename T> struct S {
   __attribute__((aligned(4))) int m;
   alignas(4) int n;
@@ -70,11 +87,13 @@ template <typename T> struct S {
   }
 };
 
-// CHECK: int m __attribute__((aligned(4
-// CHECK: int n alignas(4
-// CHECK: static int f() __attribute__((pure))
-// CHECK: static int g() {{\[}}[gnu::pure]]
+// CHECK-CXX: int m __attribute__((aligned(4
+// CHECK-CXX: int n alignas(4
+// CHECK-CXX: static int f() __attribute__((pure))
+// CHECK-CXX: static int g() {{\[}}[gnu::pure]]
 template struct S<int>;
 
-// CHECK: using Small2 {{\[}}[gnu::mode(byte)]] = int;
+// CHECK-CXX: using Small2 {{\[}}[gnu::mode(byte)]] = int;
 using Small2 [[gnu::mode(byte)]] = int;
+
+#endif


More information about the cfe-commits mailing list