[PATCH] Generalized attribute support

Alp Toker alp at nuanti.com
Tue Jan 14 17:23:39 PST 2014


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.

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.

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.

Newly added tests have been shared with C++11 where possible to ensure 
consistency between language modes.

Alp.

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

-------------- next part --------------
diff --git a/docs/LanguageExtensions.rst b/docs/LanguageExtensions.rst
index 682cc98..6312d11 100644
--- a/docs/LanguageExtensions.rst
+++ b/docs/LanguageExtensions.rst
@@ -925,6 +925,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 C.
+
 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 9d0d1b6..04f318e 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -1930,14 +1930,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))
@@ -1993,7 +1993,7 @@ private:
   IdentifierLoc *ParseIdentifierLoc();
 
   void MaybeParseCXX11Attributes(Declarator &D) {
-    if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) {
+    if (getLangOpts().CXXAttributes && isCXX11AttributeSpecifier()) {
       ParsedAttributesWithRange attrs(AttrFactory);
       SourceLocation endLoc;
       ParseCXX11Attributes(attrs, &endLoc);
@@ -2002,7 +2002,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);
@@ -2011,7 +2011,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 c6559b4..51317bc 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -921,6 +921,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
            .Case("cxx_alignas", LangOpts.CPlusPlus11)
            .Case("cxx_atomic", LangOpts.CPlusPlus11)
            .Case("cxx_attributes", LangOpts.CPlusPlus11)
+           .Case("attributes", LangOpts.CPlusPlus11)
            .Case("cxx_auto_type", LangOpts.CPlusPlus11)
            .Case("cxx_constexpr", LangOpts.CPlusPlus11)
            .Case("cxx_decltype", LangOpts.CPlusPlus11)
@@ -1027,6 +1028,7 @@ static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) {
            .Case("c_thread_local", PP.getTargetInfo().isTLSSupported())
            // C++11 features supported by other languages as extensions.
            .Case("cxx_atomic", LangOpts.CPlusPlus)
+           .Case("attributes", LangOpts.CXXAttributes)
            .Case("cxx_deleted_functions", LangOpts.CPlusPlus)
            .Case("cxx_explicit_conversions", LangOpts.CPlusPlus)
            .Case("cxx_inline_namespaces", LangOpts.CPlusPlus)
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index febf9e6..18e280b 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1454,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;
@@ -2508,7 +2508,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);
@@ -4299,7 +4299,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();
@@ -4376,7 +4376,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 4968631..8f945ca 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -1075,7 +1075,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;
@@ -3198,7 +3198,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();
@@ -3218,6 +3220,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;
@@ -3281,7 +3292,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..a42c3b2 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,12 @@ 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]]
+#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 +78,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