r173779 - Implement C++11 [dcl.align]p1 and C11 6.7.5/2 rules for alignas and _Alignas.

Richard Smith richard-llvm at metafoo.co.uk
Tue Jan 29 01:02:10 PST 2013


Author: rsmith
Date: Tue Jan 29 03:02:09 2013
New Revision: 173779

URL: http://llvm.org/viewvc/llvm-project?rev=173779&view=rev
Log:
Implement C++11 [dcl.align]p1 and C11 6.7.5/2 rules for alignas and _Alignas.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseStmt.cpp
    cfe/trunk/lib/Sema/SemaDeclAttr.cpp
    cfe/trunk/test/Parser/c1x-alignas.c
    cfe/trunk/test/Sema/alignas.c
    cfe/trunk/test/SemaCXX/attr-cxx0x.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=173779&r1=173778&r2=173779&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Jan 29 03:02:09 2013
@@ -1651,6 +1651,10 @@ def err_attribute_argument_not_int : Err
   "'%0' attribute requires integer constant">;
 def err_aligned_attribute_argument_not_int : Error<
   "'aligned' attribute requires integer constant">;
+def err_alignas_attribute_wrong_decl_type : Error<
+  "%0 attribute cannot be applied to a %select{"
+  "function parameter|variable with 'register' storage class|"
+  "'catch' variable|bit-field}1">;
 def err_attribute_first_argument_not_int_or_bool : Error<
   "%0 attribute first argument must be of int or bool type">;
 def err_attribute_argument_outof_range : Error<

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=173779&r1=173778&r2=173779&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Tue Jan 29 03:02:09 2013
@@ -3890,6 +3890,9 @@ bool Parser::isDeclarationSpecifier(bool
   case tok::kw_explicit:
   case tok::kw__Noreturn:
 
+    // alignment-specifier
+  case tok::kw__Alignas:
+
     // friend keyword.
   case tok::kw_friend:
 

Modified: cfe/trunk/lib/Parse/ParseStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=173779&r1=173778&r2=173779&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseStmt.cpp (original)
+++ cfe/trunk/lib/Parse/ParseStmt.cpp Tue Jan 29 03:02:09 2013
@@ -2156,14 +2156,13 @@ StmtResult Parser::ParseCXXTryBlockCommo
 
 /// ParseCXXCatchBlock - Parse a C++ catch block, called handler in the standard
 ///
-///       handler:
-///         'catch' '(' exception-declaration ')' compound-statement
+///   handler:
+///     'catch' '(' exception-declaration ')' compound-statement
 ///
-///       exception-declaration:
-///         type-specifier-seq declarator
-///         type-specifier-seq abstract-declarator
-///         type-specifier-seq
-///         '...'
+///   exception-declaration:
+///     attribute-specifier-seq[opt] type-specifier-seq declarator
+///     attribute-specifier-seq[opt] type-specifier-seq abstract-declarator[opt]
+///     '...'
 ///
 StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) {
   assert(Tok.is(tok::kw_catch) && "Expected 'catch'");
@@ -2184,9 +2183,15 @@ StmtResult Parser::ParseCXXCatchBlock(bo
   // without default arguments.
   Decl *ExceptionDecl = 0;
   if (Tok.isNot(tok::ellipsis)) {
+    ParsedAttributesWithRange Attributes(AttrFactory);
+    MaybeParseCXX11Attributes(Attributes);
+
     DeclSpec DS(AttrFactory);
+    DS.takeAttributesFrom(Attributes);
+
     if (ParseCXXTypeSpecifierSeq(DS))
       return StmtError();
+
     Declarator ExDecl(DS, Declarator::CXXCatchContext);
     ParseDeclarator(ExDecl);
     ExceptionDecl = Actions.ActOnExceptionDeclarator(getCurScope(), ExDecl);

Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=173779&r1=173778&r2=173779&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Tue Jan 29 03:02:09 2013
@@ -3272,9 +3272,47 @@ static void handleAlignedAttr(Sema &S, D
     return;
   }
 
-  //FIXME: The C++0x version of this attribute has more limited applicabilty
-  //       than GNU's, and should error out when it is used to specify a
-  //       weaker alignment, rather than being silently ignored.
+  // C++11 alignas(...) and C11 _Alignas(...) have additional requirements.
+  // FIXME: Use a more reliable mechanism to determine how the attribute was
+  //        spelled.
+  if (Attr.isKeywordAttribute()) {
+    // C++11 [dcl.align]p1:
+    //   An alignment-specifier may be applied to a variable or to a class
+    //   data member, but it shall not be applied to a bit-field, a function
+    //   parameter, the formal parameter of a catch clause, or a variable
+    //   declared with the register storage class specifier. An
+    //   alignment-specifier may also be applied to the declaration of a class
+    //   or enumeration type.
+    // C11 6.7.5/2:
+    //   An alignment attribute shall not be specified in a declaration of
+    //   a typedef, or a bit-field, or a function, or a parameter, or an
+    //   object declared with the register storage-class specifier.
+    int DiagKind = -1;
+    if (isa<ParmVarDecl>(D)) {
+      DiagKind = 0;
+    } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+      if (VD->getStorageClass() == SC_Register)
+        DiagKind = 1;
+      if (VD->isExceptionVariable())
+        DiagKind = 2;
+    } else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
+      if (FD->isBitField())
+        DiagKind = 3;
+    } else if (!isa<TagDecl>(D)) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
+        << Attr.getName() << ExpectedVariableFunctionOrTag;
+      return;
+    }
+    if (DiagKind != -1) {
+      S.Diag(Attr.getLoc(), diag::err_alignas_attribute_wrong_decl_type)
+        << Attr.getName() << DiagKind;
+      return;
+    }
+  }
+
+  // FIXME: The C++11 version of this attribute should error out when it is
+  //        used to specify a weaker alignment, rather than being silently
+  //        ignored.
 
   if (Attr.getNumArgs() == 0) {
     D->addAttr(::new (S.Context) AlignedAttr(Attr.getRange(), S.Context, 

Modified: cfe/trunk/test/Parser/c1x-alignas.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/c1x-alignas.c?rev=173779&r1=173778&r2=173779&view=diff
==============================================================================
--- cfe/trunk/test/Parser/c1x-alignas.c (original)
+++ cfe/trunk/test/Parser/c1x-alignas.c Tue Jan 29 03:02:09 2013
@@ -5,7 +5,7 @@ _Alignas(4) char c1;
 unsigned _Alignas(long) char c2;
 char _Alignas(16) c3;
 
-char c4 _Alignas(32); // expected-error {{expected ';' after top level declarator}}
+char c4 _Alignas(32); // expected-error {{expected ';' after top level declarator}} expected-warning {{declaration does not declare anything}}
 
 char _Alignas(_Alignof(int)) c5;
 

Modified: cfe/trunk/test/Sema/alignas.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/alignas.c?rev=173779&r1=173778&r2=173779&view=diff
==============================================================================
--- cfe/trunk/test/Sema/alignas.c (original)
+++ cfe/trunk/test/Sema/alignas.c Tue Jan 29 03:02:09 2013
@@ -8,13 +8,17 @@ _Alignas(1) unsigned _Alignas(8) int _Al
 
 struct align_member {
   _Alignas(8) int member;
+  _Alignas(1) char bitfield : 1; // expected-error {{'_Alignas' attribute cannot be applied to a bit-field}}
 };
 
-typedef _Alignas(8) char align_typedef; // FIXME: this should be rejected
+typedef _Alignas(8) char align_typedef; // expected-error {{'_Alignas' attribute only applies to variables, functions and tag types}}
+
+void f(_Alignas(1) char c) { // expected-error {{'_Alignas' attribute cannot be applied to a function parameter}}
+  _Alignas(1) register char k; // expected-error {{'_Alignas' attribute cannot be applied to a variable with 'register' storage class}}
+}
 
 _Static_assert(alignof(align_big) == alignof(int), "k's alignment is wrong");
 _Static_assert(alignof(align_small) == 1, "j's alignment is wrong");
 _Static_assert(alignof(align_multiple) == 8, "l's alignment is wrong");
 _Static_assert(alignof(struct align_member) == 8, "quuux's alignment is wrong");
 _Static_assert(sizeof(struct align_member) == 8, "quuux's size is wrong");
-_Static_assert(alignof(align_typedef) == 8, "typedef's alignment is wrong");

Modified: cfe/trunk/test/SemaCXX/attr-cxx0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-cxx0x.cpp?rev=173779&r1=173778&r2=173779&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/attr-cxx0x.cpp (original)
+++ cfe/trunk/test/SemaCXX/attr-cxx0x.cpp Tue Jan 29 03:02:09 2013
@@ -1,32 +1,40 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -std=c++11 %s
 
 int align_illegal alignas(3); //expected-error {{requested alignment is not a power of 2}}
 char align_big alignas(int);
 int align_small alignas(1); // FIXME: this should be rejected
 int align_multiple alignas(1) alignas(8) alignas(1);
+alignas(4) int align_before;
 
 struct align_member {
   int member alignas(8);
+  int bitfield alignas(1) : 1; // expected-error {{}}
 };
 
+void f(alignas(1) char c) { // expected-error {{'alignas' attribute cannot be applied to a function parameter}}
+  alignas(1) register char k; // expected-error {{'alignas' attribute cannot be applied to a variable with 'register' storage class}}
+  try {
+  } catch (alignas(4) int n) { // expected-error {{'alignas' attribute cannot be applied to a 'catch' variable}}
+  }
+}
+
+
 template <unsigned A> struct alignas(A) align_class_template {};
 
 // FIXME: these should not error
 template <typename... T> alignas(T...) struct align_class_temp_pack_type {}; // expected-error{{pack expansions in alignment specifiers are not supported yet}}
 template <unsigned... A> alignas(A...) struct align_class_temp_pack_expr {}; // expected-error{{pack expansions in alignment specifiers are not supported yet}}
 
-typedef char align_typedef alignas(8);
-template<typename T> using align_alias_template = align_typedef;
+typedef char align_typedef alignas(8); // expected-error {{'alignas' attribute only applies to variables, functions and tag types}}
+template<typename T> using align_alias_template = align_typedef alignas(8); // expected-error {{'alignas' attribute ignored when parsing type}};
 
 static_assert(alignof(align_big) == alignof(int), "k's alignment is wrong");
 static_assert(alignof(align_small) == 1, "j's alignment is wrong");
 static_assert(alignof(align_multiple) == 8, "l's alignment is wrong");
 static_assert(alignof(align_member) == 8, "quuux's alignment is wrong");
 static_assert(sizeof(align_member) == 8, "quuux's size is wrong");
-static_assert(alignof(align_typedef) == 8, "typedef's alignment is wrong");
 static_assert(alignof(align_class_template<8>) == 8, "template's alignment is wrong");
 static_assert(alignof(align_class_template<16>) == 16, "template's alignment is wrong");
 // FIXME: enable these tests
 // static_assert(alignof(align_class_temp_pack_type<short, int, long>) == alignof(long), "template's alignment is wrong");
 // static_assert(alignof(align_class_temp_pack_expr<8, 16, 32>) == 32, "template's alignment is wrong");
-static_assert(alignof(align_alias_template<int>) == 8, "alias template's alignment is wrong");





More information about the cfe-commits mailing list