Handle alignas(foo...) pack expansions.

llvm-svn: 175875
This commit is contained in:
Richard Smith 2013-02-22 08:32:16 +00:00
parent de49b8fa3b
commit 44c247f0f0
9 changed files with 154 additions and 75 deletions

View File

@ -50,6 +50,8 @@ protected:
bool Inherited : 1;
bool IsPackExpansion : 1;
virtual ~Attr();
void* operator new(size_t bytes) throw() {
@ -73,7 +75,7 @@ public:
protected:
Attr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex = 0)
: Range(R), AttrKind(AK), SpellingListIndex(SpellingListIndex),
Inherited(false) {}
Inherited(false), IsPackExpansion(false) {}
public:
@ -89,8 +91,11 @@ public:
bool isInherited() const { return Inherited; }
void setPackExpansion(bool PE) { IsPackExpansion = PE; }
bool isPackExpansion() const { return IsPackExpansion; }
// Clone this attribute.
virtual Attr* clone(ASTContext &C) const = 0;
virtual Attr *clone(ASTContext &C) const = 0;
virtual bool isLateParsed() const { return false; }

View File

@ -516,8 +516,6 @@ def err_attributes_not_allowed : Error<"an attribute list cannot appear here">;
def err_l_square_l_square_not_attribute : Error<
"C++11 only allows consecutive left square brackets when "
"introducing an attribute">;
def err_alignas_pack_exp_unsupported : Error<
"pack expansions in alignment specifiers are not supported yet">;
def err_ms_declspec_type : Error<
"__declspec attributes must be an identifier or string literal">;
def warn_ms_declspec_unknown : Warning<

View File

@ -44,8 +44,9 @@ struct AvailabilityChange {
bool isValid() const { return !Version.empty(); }
};
/// AttributeList - Represents GCC's __attribute__ declaration. There are
/// 4 forms of this construct...they are:
/// AttributeList - Represents a syntactic attribute.
///
/// For a GNU attribute, there are four forms of this construct:
///
/// 1: __attribute__(( const )). ParmName/Args/NumArgs will all be unused.
/// 2: __attribute__(( mode(byte) )). ParmName used, Args/NumArgs unused.
@ -72,6 +73,7 @@ private:
SourceRange AttrRange;
SourceLocation ScopeLoc;
SourceLocation ParmLoc;
SourceLocation EllipsisLoc;
/// The number of expression arguments this attribute has.
/// The expressions themselves are stored after the object.
@ -154,11 +156,11 @@ private:
IdentifierInfo *scopeName, SourceLocation scopeLoc,
IdentifierInfo *parmName, SourceLocation parmLoc,
Expr **args, unsigned numArgs,
Syntax syntaxUsed)
Syntax syntaxUsed, SourceLocation ellipsisLoc)
: AttrName(attrName), ScopeName(scopeName), ParmName(parmName),
AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc),
NumArgs(numArgs), SyntaxUsed(syntaxUsed), Invalid(false),
UsedAsTypeAttr(false), IsAvailability(false),
EllipsisLoc(ellipsisLoc), NumArgs(numArgs), SyntaxUsed(syntaxUsed),
Invalid(false), UsedAsTypeAttr(false), IsAvailability(false),
IsTypeTagForDatatype(false), NextInPosition(0), NextInPool(0) {
if (numArgs) memcpy(getArgsBuffer(), args, numArgs * sizeof(Expr*));
AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
@ -175,7 +177,7 @@ private:
const Expr *messageExpr,
Syntax syntaxUsed)
: AttrName(attrName), ScopeName(scopeName), ParmName(parmName),
AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc),
AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc), EllipsisLoc(),
NumArgs(0), SyntaxUsed(syntaxUsed),
Invalid(false), UsedAsTypeAttr(false), IsAvailability(true),
IsTypeTagForDatatype(false),
@ -196,7 +198,7 @@ private:
bool mustBeNull, Syntax syntaxUsed)
: AttrName(attrName), ScopeName(scopeName), ParmName(argumentKindName),
AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(argumentKindLoc),
NumArgs(0), SyntaxUsed(syntaxUsed),
EllipsisLoc(), NumArgs(0), SyntaxUsed(syntaxUsed),
Invalid(false), UsedAsTypeAttr(false), IsAvailability(false),
IsTypeTagForDatatype(true), NextInPosition(NULL), NextInPool(NULL) {
TypeTagForDatatypeData &ExtraData = getTypeTagForDatatypeDataSlot();
@ -246,6 +248,9 @@ public:
bool isUsedAsTypeAttr() const { return UsedAsTypeAttr; }
void setUsedAsTypeAttr() { UsedAsTypeAttr = true; }
bool isPackExpansion() const { return EllipsisLoc.isValid(); }
SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
Kind getKind() const { return Kind(AttrKind); }
static Kind getKind(const IdentifierInfo *Name, const IdentifierInfo *Scope,
Syntax SyntaxUsed);
@ -459,13 +464,15 @@ public:
IdentifierInfo *scopeName, SourceLocation scopeLoc,
IdentifierInfo *parmName, SourceLocation parmLoc,
Expr **args, unsigned numArgs,
AttributeList::Syntax syntax) {
AttributeList::Syntax syntax,
SourceLocation ellipsisLoc = SourceLocation()) {
void *memory = allocate(sizeof(AttributeList)
+ numArgs * sizeof(Expr*));
return add(new (memory) AttributeList(attrName, attrRange,
scopeName, scopeLoc,
parmName, parmLoc,
args, numArgs, syntax));
args, numArgs, syntax,
ellipsisLoc));
}
AttributeList *create(IdentifierInfo *attrName, SourceRange attrRange,
@ -599,10 +606,11 @@ public:
IdentifierInfo *scopeName, SourceLocation scopeLoc,
IdentifierInfo *parmName, SourceLocation parmLoc,
Expr **args, unsigned numArgs,
AttributeList::Syntax syntax) {
AttributeList::Syntax syntax,
SourceLocation ellipsisLoc = SourceLocation()) {
AttributeList *attr =
pool.create(attrName, attrRange, scopeName, scopeLoc, parmName, parmLoc,
args, numArgs, syntax);
args, numArgs, syntax, ellipsisLoc);
add(attr);
return attr;
}

View File

@ -6545,9 +6545,9 @@ public:
/// AddAlignedAttr - Adds an aligned attribute to a particular declaration.
void AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
unsigned SpellingListIndex);
unsigned SpellingListIndex, bool IsPackExpansion);
void AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *T,
unsigned SpellingListIndex);
unsigned SpellingListIndex, bool IsPackExpansion);
/// \brief The kind of conversion being performed.
enum CheckedConversionKind {

View File

@ -2101,7 +2101,7 @@ ExprResult Parser::ParseAlignArgument(SourceLocation Start,
/// [C++11] 'alignas' '(' type-id ...[opt] ')'
/// [C++11] 'alignas' '(' assignment-expression ...[opt] ')'
void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
SourceLocation *endLoc) {
SourceLocation *EndLoc) {
assert((Tok.is(tok::kw_alignas) || Tok.is(tok::kw__Alignas)) &&
"Not an alignment-specifier!");
@ -2120,19 +2120,13 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
}
T.consumeClose();
if (endLoc)
*endLoc = T.getCloseLocation();
// FIXME: Handle pack-expansions here.
if (EllipsisLoc.isValid()) {
Diag(EllipsisLoc, diag::err_alignas_pack_exp_unsupported);
return;
}
if (EndLoc)
*EndLoc = T.getCloseLocation();
ExprVector ArgExprs;
ArgExprs.push_back(ArgExpr.release());
Attrs.addNew(KWName, KWLoc, 0, KWLoc, 0, T.getOpenLocation(),
ArgExprs.data(), 1, AttributeList::AS_Keyword);
ArgExprs.data(), 1, AttributeList::AS_Keyword, EllipsisLoc);
}
/// ParseDeclarationSpecifiers

View File

@ -3315,27 +3315,28 @@ static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
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. This constraint cannot be applied until we have seen
// all the attributes which apply to the variable.
if (Attr.getNumArgs() == 0) {
D->addAttr(::new (S.Context) AlignedAttr(Attr.getRange(), S.Context,
true, 0, Attr.getAttributeSpellingListIndex()));
return;
}
S.AddAlignedAttr(Attr.getRange(), D, Attr.getArg(0),
Attr.getAttributeSpellingListIndex());
Expr *E = Attr.getArg(0);
if (Attr.isPackExpansion() && !E->containsUnexpandedParameterPack()) {
S.Diag(Attr.getEllipsisLoc(),
diag::err_pack_expansion_without_parameter_packs);
return;
}
if (!Attr.isPackExpansion() && S.DiagnoseUnexpandedParameterPack(E))
return;
S.AddAlignedAttr(Attr.getRange(), D, E, Attr.getAttributeSpellingListIndex(),
Attr.isPackExpansion());
}
void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
unsigned SpellingListIndex) {
// FIXME: Handle pack-expansions here.
if (DiagnoseUnexpandedParameterPack(E))
return;
unsigned SpellingListIndex, bool IsPackExpansion) {
AlignedAttr TmpAttr(AttrRange, Context, true, E, SpellingListIndex);
SourceLocation AttrLoc = AttrRange.getBegin();
@ -3379,7 +3380,9 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
if (E->isTypeDependent() || E->isValueDependent()) {
// Save dependent expressions in the AST to be instantiated.
D->addAttr(::new (Context) AlignedAttr(TmpAttr));
AlignedAttr *AA = ::new (Context) AlignedAttr(TmpAttr);
AA->setPackExpansion(IsPackExpansion);
D->addAttr(AA);
return;
}
@ -3414,17 +3417,20 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
}
}
D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true,
ICE.take(), SpellingListIndex));
AlignedAttr *AA = ::new (Context) AlignedAttr(AttrRange, Context, true,
ICE.take(), SpellingListIndex);
AA->setPackExpansion(IsPackExpansion);
D->addAttr(AA);
}
void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *TS,
unsigned SpellingListIndex) {
unsigned SpellingListIndex, bool IsPackExpansion) {
// FIXME: Cache the number on the Attr object if non-dependent?
// FIXME: Perform checking of type validity
D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, false, TS,
SpellingListIndex));
return;
AlignedAttr *AA = ::new (Context) AlignedAttr(AttrRange, Context, false, TS,
SpellingListIndex);
AA->setPackExpansion(IsPackExpansion);
D->addAttr(AA);
}
void Sema::CheckAlignasUnderalignment(Decl *D) {

View File

@ -60,6 +60,64 @@ bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl,
// Include attribute instantiation code.
#include "clang/Sema/AttrTemplateInstantiate.inc"
static void instantiateDependentAlignedAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const AlignedAttr *Aligned, Decl *New, bool IsPackExpansion) {
if (Aligned->isAlignmentExpr()) {
// The alignment expression is a constant expression.
EnterExpressionEvaluationContext Unevaluated(S, Sema::ConstantEvaluated);
ExprResult Result = S.SubstExpr(Aligned->getAlignmentExpr(), TemplateArgs);
if (!Result.isInvalid())
S.AddAlignedAttr(Aligned->getLocation(), New, Result.takeAs<Expr>(),
Aligned->getSpellingListIndex(), IsPackExpansion);
} else {
TypeSourceInfo *Result = S.SubstType(Aligned->getAlignmentType(),
TemplateArgs, Aligned->getLocation(),
DeclarationName());
if (Result)
S.AddAlignedAttr(Aligned->getLocation(), New, Result,
Aligned->getSpellingListIndex(), IsPackExpansion);
}
}
static void instantiateDependentAlignedAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const AlignedAttr *Aligned, Decl *New) {
if (!Aligned->isPackExpansion()) {
instantiateDependentAlignedAttr(S, TemplateArgs, Aligned, New, false);
return;
}
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
if (Aligned->isAlignmentExpr())
S.collectUnexpandedParameterPacks(Aligned->getAlignmentExpr(),
Unexpanded);
else
S.collectUnexpandedParameterPacks(Aligned->getAlignmentType()->getTypeLoc(),
Unexpanded);
assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
// Determine whether we can expand this attribute pack yet.
bool Expand = true, RetainExpansion = false;
Optional<unsigned> NumExpansions;
// FIXME: Use the actual location of the ellipsis.
SourceLocation EllipsisLoc = Aligned->getLocation();
if (S.CheckParameterPacksForExpansion(EllipsisLoc, Aligned->getRange(),
Unexpanded, TemplateArgs, Expand,
RetainExpansion, NumExpansions))
return;
if (!Expand) {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(S, -1);
instantiateDependentAlignedAttr(S, TemplateArgs, Aligned, New, true);
} else {
for (unsigned I = 0; I != *NumExpansions; ++I) {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(S, I);
instantiateDependentAlignedAttr(S, TemplateArgs, Aligned, New, false);
}
}
}
void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
const Decl *Tmpl, Decl *New,
LateInstantiatedAttrVec *LateAttrs,
@ -69,31 +127,13 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
const Attr *TmplAttr = *i;
// FIXME: This should be generalized to more than just the AlignedAttr.
if (const AlignedAttr *Aligned = dyn_cast<AlignedAttr>(TmplAttr)) {
if (Aligned->isAlignmentDependent()) {
if (Aligned->isAlignmentExpr()) {
// The alignment expression is a constant expression.
EnterExpressionEvaluationContext Unevaluated(*this,
Sema::ConstantEvaluated);
ExprResult Result = SubstExpr(Aligned->getAlignmentExpr(),
TemplateArgs);
if (!Result.isInvalid())
AddAlignedAttr(Aligned->getLocation(), New, Result.takeAs<Expr>(),
Aligned->getSpellingListIndex());
} else {
TypeSourceInfo *Result = SubstType(Aligned->getAlignmentType(),
TemplateArgs,
Aligned->getLocation(),
DeclarationName());
if (Result)
AddAlignedAttr(Aligned->getLocation(), New, Result,
Aligned->getSpellingListIndex());
}
continue;
}
const AlignedAttr *Aligned = dyn_cast<AlignedAttr>(TmplAttr);
if (Aligned && Aligned->isAlignmentDependent()) {
instantiateDependentAlignedAttr(*this, TemplateArgs, Aligned, New);
continue;
}
assert(!TmplAttr->isPackExpansion());
if (TmplAttr->isLateParsed() && LateAttrs) {
// Late parsed attributes must be instantiated and attached after the
// enclosing class has been instantiated. See Sema::InstantiateClass.

View File

@ -21,9 +21,14 @@ void f(alignas(1) char c) { // expected-error {{'alignas' attribute cannot be ap
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}}
template <typename... T> struct alignas(T...) align_class_temp_pack_type {};
template <unsigned... A> struct alignas(A...) align_class_temp_pack_expr {};
struct alignas(int...) alignas_expansion_no_packs {}; // expected-error {{pack expansion does not contain any unexpanded parameter packs}}
template <typename... A> struct outer {
template <typename... B> struct alignas(alignof(A) * alignof(B)...) inner {};
// expected-error@-1 {{pack expansion contains parameter packs 'A' and 'B' that have different lengths (1 vs. 2)}}
};
outer<int>::inner<short, double> mismatched_packs; // expected-note {{in instantiation of}}
typedef char align_typedef alignas(8); // expected-error {{'alignas' attribute only applies to variables, data members and tag types}}
template<typename T> using align_alias_template = align_typedef alignas(8); // expected-error {{'alignas' attribute cannot be applied to types}}
@ -35,6 +40,6 @@ 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_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_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(outer<int,char>::inner<double,short>) == alignof(int) * alignof(double), "template's alignment is wrong");

View File

@ -0,0 +1,23 @@
// RUN: %clang_cc1 -std=c++11 -verify %s
// expected-no-diagnostics
using size_t = decltype(sizeof(0));
template<typename T, typename U>
constexpr T max(T t, U u) { return t > u ? t : u; }
template<typename T, typename ...Ts>
constexpr auto max(T t, Ts ...ts) -> decltype(max(t, max(ts...))) {
return max(t, max(ts...));
}
template<typename...T> struct my_union {
alignas(T...) char buffer[max(sizeof(T)...)];
};
struct alignas(8) A { char c; };
struct alignas(4) B { short s; };
struct C { char a[16]; };
static_assert(sizeof(my_union<A, B, C>) == 16, "");
static_assert(alignof(my_union<A, B, C>) == 8, "");