зеркало из https://github.com/microsoft/clang-1.git
Implement C++11 [dcl.align]p1 and C11 6.7.5/2 rules for alignas and _Alignas.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@173779 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
52a92509aa
Коммит
4cd81c5bf5
|
@ -1651,6 +1651,10 @@ def err_attribute_argument_not_int : Error<
|
||||||
"'%0' attribute requires integer constant">;
|
"'%0' attribute requires integer constant">;
|
||||||
def err_aligned_attribute_argument_not_int : Error<
|
def err_aligned_attribute_argument_not_int : Error<
|
||||||
"'aligned' attribute requires integer constant">;
|
"'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<
|
def err_attribute_first_argument_not_int_or_bool : Error<
|
||||||
"%0 attribute first argument must be of int or bool type">;
|
"%0 attribute first argument must be of int or bool type">;
|
||||||
def err_attribute_argument_outof_range : Error<
|
def err_attribute_argument_outof_range : Error<
|
||||||
|
|
|
@ -3890,6 +3890,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
|
||||||
case tok::kw_explicit:
|
case tok::kw_explicit:
|
||||||
case tok::kw__Noreturn:
|
case tok::kw__Noreturn:
|
||||||
|
|
||||||
|
// alignment-specifier
|
||||||
|
case tok::kw__Alignas:
|
||||||
|
|
||||||
// friend keyword.
|
// friend keyword.
|
||||||
case tok::kw_friend:
|
case tok::kw_friend:
|
||||||
|
|
||||||
|
|
|
@ -2156,14 +2156,13 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) {
|
||||||
|
|
||||||
/// ParseCXXCatchBlock - Parse a C++ catch block, called handler in the standard
|
/// ParseCXXCatchBlock - Parse a C++ catch block, called handler in the standard
|
||||||
///
|
///
|
||||||
/// handler:
|
/// handler:
|
||||||
/// 'catch' '(' exception-declaration ')' compound-statement
|
/// 'catch' '(' exception-declaration ')' compound-statement
|
||||||
///
|
///
|
||||||
/// exception-declaration:
|
/// exception-declaration:
|
||||||
/// type-specifier-seq declarator
|
/// attribute-specifier-seq[opt] type-specifier-seq declarator
|
||||||
/// type-specifier-seq abstract-declarator
|
/// attribute-specifier-seq[opt] type-specifier-seq abstract-declarator[opt]
|
||||||
/// type-specifier-seq
|
/// '...'
|
||||||
/// '...'
|
|
||||||
///
|
///
|
||||||
StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) {
|
StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) {
|
||||||
assert(Tok.is(tok::kw_catch) && "Expected 'catch'");
|
assert(Tok.is(tok::kw_catch) && "Expected 'catch'");
|
||||||
|
@ -2184,9 +2183,15 @@ StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) {
|
||||||
// without default arguments.
|
// without default arguments.
|
||||||
Decl *ExceptionDecl = 0;
|
Decl *ExceptionDecl = 0;
|
||||||
if (Tok.isNot(tok::ellipsis)) {
|
if (Tok.isNot(tok::ellipsis)) {
|
||||||
|
ParsedAttributesWithRange Attributes(AttrFactory);
|
||||||
|
MaybeParseCXX11Attributes(Attributes);
|
||||||
|
|
||||||
DeclSpec DS(AttrFactory);
|
DeclSpec DS(AttrFactory);
|
||||||
|
DS.takeAttributesFrom(Attributes);
|
||||||
|
|
||||||
if (ParseCXXTypeSpecifierSeq(DS))
|
if (ParseCXXTypeSpecifierSeq(DS))
|
||||||
return StmtError();
|
return StmtError();
|
||||||
|
|
||||||
Declarator ExDecl(DS, Declarator::CXXCatchContext);
|
Declarator ExDecl(DS, Declarator::CXXCatchContext);
|
||||||
ParseDeclarator(ExDecl);
|
ParseDeclarator(ExDecl);
|
||||||
ExceptionDecl = Actions.ActOnExceptionDeclarator(getCurScope(), ExDecl);
|
ExceptionDecl = Actions.ActOnExceptionDeclarator(getCurScope(), ExDecl);
|
||||||
|
|
|
@ -3272,9 +3272,47 @@ static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//FIXME: The C++0x version of this attribute has more limited applicabilty
|
// C++11 alignas(...) and C11 _Alignas(...) have additional requirements.
|
||||||
// than GNU's, and should error out when it is used to specify a
|
// FIXME: Use a more reliable mechanism to determine how the attribute was
|
||||||
// weaker alignment, rather than being silently ignored.
|
// 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) {
|
if (Attr.getNumArgs() == 0) {
|
||||||
D->addAttr(::new (S.Context) AlignedAttr(Attr.getRange(), S.Context,
|
D->addAttr(::new (S.Context) AlignedAttr(Attr.getRange(), S.Context,
|
||||||
|
|
|
@ -5,7 +5,7 @@ _Alignas(4) char c1;
|
||||||
unsigned _Alignas(long) char c2;
|
unsigned _Alignas(long) char c2;
|
||||||
char _Alignas(16) c3;
|
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;
|
char _Alignas(_Alignof(int)) c5;
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,17 @@ _Alignas(1) unsigned _Alignas(8) int _Alignas(1) align_multiple;
|
||||||
|
|
||||||
struct align_member {
|
struct align_member {
|
||||||
_Alignas(8) int 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_big) == alignof(int), "k's alignment is wrong");
|
||||||
_Static_assert(alignof(align_small) == 1, "j'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_multiple) == 8, "l's alignment is wrong");
|
||||||
_Static_assert(alignof(struct align_member) == 8, "quuux'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(sizeof(struct align_member) == 8, "quuux's size is wrong");
|
||||||
_Static_assert(alignof(align_typedef) == 8, "typedef's alignment is wrong");
|
|
||||||
|
|
|
@ -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}}
|
int align_illegal alignas(3); //expected-error {{requested alignment is not a power of 2}}
|
||||||
char align_big alignas(int);
|
char align_big alignas(int);
|
||||||
int align_small alignas(1); // FIXME: this should be rejected
|
int align_small alignas(1); // FIXME: this should be rejected
|
||||||
int align_multiple alignas(1) alignas(8) alignas(1);
|
int align_multiple alignas(1) alignas(8) alignas(1);
|
||||||
|
alignas(4) int align_before;
|
||||||
|
|
||||||
struct align_member {
|
struct align_member {
|
||||||
int member alignas(8);
|
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 {};
|
template <unsigned A> struct alignas(A) align_class_template {};
|
||||||
|
|
||||||
// FIXME: these should not error
|
// 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 <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}}
|
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);
|
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;
|
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_big) == alignof(int), "k's alignment is wrong");
|
||||||
static_assert(alignof(align_small) == 1, "j'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_multiple) == 8, "l's alignment is wrong");
|
||||||
static_assert(alignof(align_member) == 8, "quuux'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(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<8>) == 8, "template's alignment is wrong");
|
||||||
static_assert(alignof(align_class_template<16>) == 16, "template's alignment is wrong");
|
static_assert(alignof(align_class_template<16>) == 16, "template's alignment is wrong");
|
||||||
// FIXME: enable these tests
|
// 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_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_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");
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче