aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Attr.h9
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td2
-rw-r--r--include/clang/Sema/AttributeList.h30
-rw-r--r--include/clang/Sema/Sema.h4
-rw-r--r--lib/Parse/ParseDecl.cpp14
-rw-r--r--lib/Sema/SemaDeclAttr.cpp44
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp86
-rw-r--r--test/SemaCXX/attr-cxx0x.cpp17
-rw-r--r--test/SemaTemplate/alignas.cpp23
9 files changed, 154 insertions, 75 deletions
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
index fbb097011f..61c57f9928 100644
--- a/include/clang/AST/Attr.h
+++ b/include/clang/AST/Attr.h
@@ -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; }
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 6035937be6..2fbd99a688 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -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<
diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index 17444cb196..a8d3eb4fb7 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/include/clang/Sema/AttributeList.h
@@ -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;
}
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index da82325819..7101286a7b 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -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 {
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index a204532789..4628f3dc17 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -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
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 1142e0dd2d..8e2bac6ed0 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -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;
+ }
-void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
- unsigned SpellingListIndex) {
- // FIXME: Handle pack-expansions here.
- if (DiagnoseUnexpandedParameterPack(E))
+ 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, 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) {
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index defa968475..a829070b2f 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -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.
diff --git a/test/SemaCXX/attr-cxx0x.cpp b/test/SemaCXX/attr-cxx0x.cpp
index d1787f186b..002800e749 100644
--- a/test/SemaCXX/attr-cxx0x.cpp
+++ b/test/SemaCXX/attr-cxx0x.cpp
@@ -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");
diff --git a/test/SemaTemplate/alignas.cpp b/test/SemaTemplate/alignas.cpp
new file mode 100644
index 0000000000..8a1f96e5bd
--- /dev/null
+++ b/test/SemaTemplate/alignas.cpp
@@ -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, "");