forked from OSchip/llvm-project
parent
de49b8fa3b
commit
44c247f0f0
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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<
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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, "");
|
Loading…
Reference in New Issue