From: Peter Collingbourne Date: Thu, 29 Sep 2011 18:04:28 +0000 (+0000) Subject: Add support for alignment-specifiers in C1X and C++11, remove X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=82d0b0aab9088e977c2a44c4a5a90479c63149fe;p=clang Add support for alignment-specifiers in C1X and C++11, remove support for the C++0x draft [[align]] attribute and add the C1X standard header file stdalign.h git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@140796 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index be43bca9fd..32ebbf9443 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -114,7 +114,7 @@ def Alias : InheritableAttr { } def Aligned : InheritableAttr { - let Spellings = ["align", "aligned"]; + let Spellings = ["aligned"]; let Subjects = [NonBitField, NormalVar, Tag]; let Args = [AlignedArgument<"Alignment">]; let Namespaces = ["", "std"]; diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 7b40eee9ea..77573065ab 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -70,6 +70,9 @@ def err_duplicate_default_assoc : Error< def note_previous_default_assoc : Note< "previous default generic association is here">; +def ext_c1x_alignas : Extension< + "_Alignas is a C1X-specific feature">, InGroup; + def ext_gnu_indirect_goto : Extension< "use of GNU indirect-goto extension">, InGroup; def ext_gnu_address_of_label : Extension< diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index 534aebbf77..1256caabec 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -249,6 +249,7 @@ KEYWORD(unsigned , KEYALL) KEYWORD(void , KEYALL) KEYWORD(volatile , KEYALL) KEYWORD(while , KEYALL) +KEYWORD(_Alignas , KEYALL) KEYWORD(_Bool , KEYNOCXX) KEYWORD(_Complex , KEYALL) KEYWORD(_Generic , KEYALL) @@ -302,6 +303,7 @@ CXX_KEYWORD_OPERATOR(xor , caret) CXX_KEYWORD_OPERATOR(xor_eq , caretequal) // C++0x keywords +KEYWORD(alignas , KEYCXX0X) KEYWORD(alignof , KEYCXX0X) KEYWORD(char16_t , KEYCXX0X) KEYWORD(char32_t , KEYCXX0X) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 4d81abde98..3056819b3a 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1775,7 +1775,9 @@ private: void ParseDecltypeSpecifier(DeclSpec &DS); void ParseUnderlyingTypeSpecifier(DeclSpec &DS); - ExprResult ParseCXX0XAlignArgument(SourceLocation Start); + ExprResult ParseAlignArgument(SourceLocation Start); + void ParseAlignmentSpecifier(ParsedAttributes &Attrs, + SourceLocation *endLoc = 0); VirtSpecifiers::Specifier isCXX0XVirtSpecifier() const; void ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 4bafb2b6e7..0f6df31755 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -705,7 +705,7 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { // *except* on a struct or struct member, where it only increases // alignment unless 'packed' is also specified. // - // It is an error for [[align]] to decrease alignment, so we can + // It is an error for alignas to decrease alignment, so we can // ignore that possibility; Sema should diagnose it. if (isa(D)) { UseAlignAttrOnly = D->hasAttr() || diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt index 78fd6f19f6..1faf92fd19 100644 --- a/lib/Headers/CMakeLists.txt +++ b/lib/Headers/CMakeLists.txt @@ -12,6 +12,7 @@ set(files nmmintrin.h pmmintrin.h smmintrin.h + stdalign.h stdarg.h stdbool.h stddef.h diff --git a/lib/Headers/stdalign.h b/lib/Headers/stdalign.h new file mode 100644 index 0000000000..e7fbfa0499 --- /dev/null +++ b/lib/Headers/stdalign.h @@ -0,0 +1,30 @@ +/*===---- stdalign.h - Standard header for alignment ------------------------=== + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef __STDALIGN_H +#define __STDALIGN_H + +#define alignas _Alignas +#define __alignas_is_defined 1 + +#endif /* __STDALIGN_H */ diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index d904bcc807..e9d3185b9a 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1314,6 +1314,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS) { /// specifier-qualifier-list is a subset of declaration-specifiers. Just /// parse declaration-specifiers and complain about extra stuff. + /// TODO: diagnose attribute-specifiers and alignment-specifiers. ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS); // Validate declspec for type-name. @@ -1497,11 +1498,68 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) { return DSC_normal; } +/// ParseAlignArgument - Parse the argument to an alignment-specifier. +/// +/// FIXME: Simply returns an alignof() expression if the argument is a +/// type. Ideally, the type should be propagated directly into Sema. +/// +/// [C1X/C++0x] type-id +/// [C1X] constant-expression +/// [C++0x] assignment-expression +ExprResult Parser::ParseAlignArgument(SourceLocation Start) { + if (isTypeIdInParens()) { + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); + SourceLocation TypeLoc = Tok.getLocation(); + ParsedType Ty = ParseTypeName().get(); + SourceRange TypeRange(Start, Tok.getLocation()); + return Actions.ActOnUnaryExprOrTypeTraitExpr(TypeLoc, UETT_AlignOf, true, + Ty.getAsOpaquePtr(), TypeRange); + } else + return ParseConstantExpression(); +} + +/// ParseAlignmentSpecifier - Parse an alignment-specifier, and add the +/// attribute to Attrs. +/// +/// alignment-specifier: +/// [C1X] '_Alignas' '(' type-id ')' +/// [C1X] '_Alignas' '(' constant-expression ')' +/// [C++0x] 'alignas' '(' type-id ')' +/// [C++0x] 'alignas' '(' assignment-expression ')' +void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, + SourceLocation *endLoc) { + assert((Tok.is(tok::kw_alignas) || Tok.is(tok::kw__Alignas)) && + "Not an alignment-specifier!"); + + SourceLocation KWLoc = Tok.getLocation(); + ConsumeToken(); + + SourceLocation ParamLoc = Tok.getLocation(); + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen)) + return; + + ExprResult ArgExpr = ParseAlignArgument(ParamLoc); + if (ArgExpr.isInvalid()) { + SkipUntil(tok::r_paren); + return; + } + + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, ParamLoc); + if (endLoc) + *endLoc = RParenLoc; + + ExprVector ArgExprs(Actions); + ArgExprs.push_back(ArgExpr.release()); + Attrs.addNew(PP.getIdentifierInfo("aligned"), KWLoc, 0, KWLoc, + 0, ParamLoc, ArgExprs.take(), 1, false, true); +} + /// ParseDeclarationSpecifiers /// declaration-specifiers: [C99 6.7] /// storage-class-specifier declaration-specifiers[opt] /// type-specifier declaration-specifiers[opt] /// [C99] function-specifier declaration-specifiers[opt] +/// [C1X] alignment-specifier declaration-specifiers[opt] /// [GNU] attributes declaration-specifiers[opt] /// [Clang] '__module_private__' declaration-specifiers[opt] /// @@ -1946,6 +2004,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = DS.SetFunctionSpecExplicit(Loc, PrevSpec, DiagID); break; + // alignment-specifier + case tok::kw__Alignas: + if (!getLang().C1X) + Diag(Tok, diag::ext_c1x_alignas); + ParseAlignmentSpecifier(DS.getAttributes()); + continue; + // friend case tok::kw_friend: if (DSContext == DSC_class) diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index ab953dc9c8..2fd5c0059d 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -2561,6 +2561,7 @@ void Parser::PopParsingClass(Sema::ParsingClassState state) { /// /// [C++0x] attribute-specifier: /// '[' '[' attribute-list ']' ']' +/// alignment-specifier /// /// [C++0x] attribute-list: /// attribute[opt] @@ -2593,6 +2594,11 @@ void Parser::PopParsingClass(Sema::ParsingClassState state) { /// any token but '(', ')', '[', ']', '{', or '}' void Parser::ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs, SourceLocation *endLoc) { + if (Tok.is(tok::kw_alignas)) { + ParseAlignmentSpecifier(attrs, endLoc); + return; + } + assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square) && "Not a C++0x attribute list"); @@ -2652,29 +2658,6 @@ void Parser::ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs, break; } - // One argument; must be a type-id or assignment-expression - case AttributeList::AT_aligned: { - if (Tok.isNot(tok::l_paren)) { - Diag(Tok.getLocation(), diag::err_cxx0x_attribute_requires_arguments) - << AttrName->getName(); - break; - } - SourceLocation ParamLoc = ConsumeParen(); - - ExprResult ArgExpr = ParseCXX0XAlignArgument(ParamLoc); - - MatchRHSPunctuation(tok::r_paren, ParamLoc); - - ExprVector ArgExprs(Actions); - ArgExprs.push_back(ArgExpr.release()); - attrs.addNew(AttrName, AttrLoc, 0, AttrLoc, - 0, ParamLoc, ArgExprs.take(), 1, - false, true); - - AttrParsed = true; - break; - } - // Silence warnings default: break; } @@ -2713,26 +2696,6 @@ void Parser::ParseCXX0XAttributes(ParsedAttributesWithRange &attrs, attrs.Range = SourceRange(StartLoc, *endLoc); } -/// ParseCXX0XAlignArgument - Parse the argument to C++0x's [[align]] -/// attribute. -/// -/// FIXME: Simply returns an alignof() expression if the argument is a -/// type. Ideally, the type should be propagated directly into Sema. -/// -/// [C++0x] 'align' '(' type-id ')' -/// [C++0x] 'align' '(' assignment-expression ')' -ExprResult Parser::ParseCXX0XAlignArgument(SourceLocation Start) { - if (isTypeIdInParens()) { - EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); - SourceLocation TypeLoc = Tok.getLocation(); - ParsedType Ty = ParseTypeName().get(); - SourceRange TypeRange(Start, Tok.getLocation()); - return Actions.ActOnUnaryExprOrTypeTraitExpr(TypeLoc, UETT_AlignOf, true, - Ty.getAsOpaquePtr(), TypeRange); - } else - return ParseConstantExpression(); -} - /// ParseMicrosoftAttributes - Parse a Microsoft attribute [Attr] /// /// [MS] ms-attribute: diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 9b2ea90ba1..210d179db1 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -377,6 +377,7 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { /// /// [C++0x] attribute-specifier: /// '[' '[' attribute-list ']' ']' +/// alignment-specifier /// /// [C++0x] attribute-list: /// attribute[opt] @@ -409,6 +410,9 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { /// any token but '(', ')', '[', ']', '{', or '}' bool Parser::isCXX0XAttributeSpecifier (bool CheckClosing, tok::TokenKind *After) { + if (Tok.is(tok::kw_alignas)) + return true; + if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) return false; diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp index b93e8e35b1..9a2e4ab30c 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp @@ -33,8 +33,7 @@ void f() { void g() throw (struct Ex {}) { // expected-error {{'Ex' can not be defined in a type specifier}} } -// FIXME: this currently gives a strange error because alignas is not recognised as a keyword yet. -int alignas(struct Aa {}) x; // expected-error {{'Aa' can not be defined in a parameter type}} expected-error {{expected function body}} +int alignas(struct Aa {}) x; // expected-error {{'Aa' can not be defined in a type specifier}} int a = sizeof(struct So {}); // expected-error {{'So' can not be defined in a type specifier}} int b = alignof(struct Ao {}); // expected-error {{'Ao' can not be defined in a type specifier}} diff --git a/test/Parser/c1x-alignas.c b/test/Parser/c1x-alignas.c new file mode 100644 index 0000000000..5dccc99035 --- /dev/null +++ b/test/Parser/c1x-alignas.c @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -std=c1x -fsyntax-only -verify %s + +_Alignas(4) char c1; +unsigned _Alignas(long) char c2; +char _Alignas(16) c3; + +char c4 _Alignas(32); // expected-error {{expected ';' after top level declarator}} diff --git a/test/Parser/cxx0x-attributes.cpp b/test/Parser/cxx0x-attributes.cpp index 0b6413cfb2..94ea34d503 100644 --- a/test/Parser/cxx0x-attributes.cpp +++ b/test/Parser/cxx0x-attributes.cpp @@ -6,7 +6,7 @@ int [[]] between_attr; int after_attr [[]]; int * [[]] ptr_attr; int array_attr [1] [[]]; -[[align(8)]] int aligned_attr; +alignas(8) int aligned_attr; [[test::valid(for 42 [very] **** '+' symbols went on a trip; the end.)]] int garbage_attr; void fn_attr () [[]]; @@ -32,8 +32,8 @@ extern "C++" [[]] { } // expected-error {{an attribute list cannot appear here}} [[]] using namespace ns; // Argument tests -[[align]] int aligned_no_params; // expected-error {{C++0x attribute 'align' must have an argument list}} -[[align(i)]] int aligned_nonconst; // expected-error {{'aligned' attribute requires integer constant}} +alignas int aligned_no_params; // expected-error {{expected '('}} +alignas(i) int aligned_nonconst; // expected-error {{'aligned' attribute requires integer constant}} // Statement tests void foo () { diff --git a/test/Sema/alignas.c b/test/Sema/alignas.c new file mode 100644 index 0000000000..5832393e3b --- /dev/null +++ b/test/Sema/alignas.c @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c1x %s + +_Alignas(3) int align_illegal; //expected-error {{requested alignment is not a power of 2}} +_Alignas(int) char align_big; +_Alignas(1) int align_small; // FIXME: this should be rejected +_Alignas(1) unsigned _Alignas(8) int _Alignas(1) align_multiple; + +struct align_member { + _Alignas(8) int member; +}; + +typedef _Alignas(8) char align_typedef; // FIXME: this should be rejected + +_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"); diff --git a/test/Sema/warn-cast-align.c b/test/Sema/warn-cast-align.c index 11e3c41636..93352c253a 100644 --- a/test/Sema/warn-cast-align.c +++ b/test/Sema/warn-cast-align.c @@ -28,7 +28,7 @@ void test1(void *P) { } // Aligned struct. -__attribute__((align(16))) struct A { +__attribute__((aligned(16))) struct A { char buffer[16]; }; void test2(char *P) { diff --git a/test/SemaCXX/attr-cxx0x.cpp b/test/SemaCXX/attr-cxx0x.cpp index 725f0182db..ee5b2e57b5 100644 --- a/test/SemaCXX/attr-cxx0x.cpp +++ b/test/SemaCXX/attr-cxx0x.cpp @@ -1,15 +1,15 @@ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s -int align_illegal [[align(3)]]; //expected-error {{requested alignment is not a power of 2}} -char align_big [[align(int)]]; -int align_small [[align(1)]]; // FIXME: this should be rejected -int align_multiple [[align(1), align(8), align(1)]]; +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); struct align_member { - int member [[align(8)]]; + int member alignas(8); }; -typedef char align_typedef [[align(8)]]; +typedef char align_typedef alignas(8); template using align_alias_template = align_typedef; static_assert(alignof(align_big) == alignof(int), "k's alignment is wrong");