Implement support for C++0x alias templates.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130953 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Richard Smith 2011-05-05 21:57:07 +00:00
Родитель 78a7d7d799
Коммит 3e4c6c4c79
59 изменённых файлов: 1119 добавлений и 138 удалений

Просмотреть файл

@ -32,6 +32,7 @@ td {
</ul>
<li><a href="#checking_upcoming_features">Checks for Upcoming Standard Language Features</a></li>
<ul>
<li><a href="#cxx_alias_templates">C++0x alias templates</a></li>
<li><a href="#cxx_attributes">C++0x attributes</a></li>
<li><a href="#cxx_decltype">C++0x <tt>decltype()</tt></a></li>
<li><a href="#cxx_default_function_template_args">C++0x default template arguments in function templates</a></li>
@ -378,6 +379,11 @@ not yet implemented will be noted.</p>
<p>Use <tt>__has_feature(cxx_decltype)</tt> to determine if support for the
<tt>decltype()</tt> specifier is enabled.</p>
<h3 id="cxx_alias_templates">C++0x alias templates</h3>
<p>Use <tt>__has_feature(cxx_alias_templates)</tt> to determine if support for
C++0x's alias declarations and alias templates is enabled.</p>
<h3 id="cxx_attributes">C++0x attributes</h3>
<p>Use <tt>__has_feature(cxx_attributes)</tt> to determine if support for

Просмотреть файл

@ -30,6 +30,7 @@ class ClassTemplatePartialSpecializationDecl;
class TemplateTypeParmDecl;
class NonTypeTemplateParmDecl;
class TemplateTemplateParmDecl;
class TypeAliasTemplateDecl;
/// \brief Stores a template parameter of any kind.
typedef llvm::PointerUnion3<TemplateTypeParmDecl*, NonTypeTemplateParmDecl*,
@ -230,6 +231,7 @@ public:
static bool classof(const FunctionTemplateDecl *D) { return true; }
static bool classof(const ClassTemplateDecl *D) { return true; }
static bool classof(const TemplateTemplateParmDecl *D) { return true; }
static bool classof(const TypeAliasTemplateDecl *D) { return true; }
static bool classofKind(Kind K) {
return K >= firstTemplate && K <= lastTemplate;
}
@ -672,6 +674,7 @@ public:
static bool classof(const RedeclarableTemplateDecl *D) { return true; }
static bool classof(const FunctionTemplateDecl *D) { return true; }
static bool classof(const ClassTemplateDecl *D) { return true; }
static bool classof(const TypeAliasTemplateDecl *D) { return true; }
static bool classofKind(Kind K) {
return K >= firstRedeclarableTemplate && K <= lastRedeclarableTemplate;
}
@ -2014,6 +2017,78 @@ public:
friend class ASTDeclReader;
};
/// Declaration of an alias template. For example:
///
/// template <typename T> using V = std::map<T*, int, MyCompare<T>>;
class TypeAliasTemplateDecl : public RedeclarableTemplateDecl,
public RedeclarableTemplate<TypeAliasTemplateDecl> {
static void DeallocateCommon(void *Ptr);
protected:
typedef RedeclarableTemplate<TypeAliasTemplateDecl> redeclarable_base;
typedef CommonBase Common;
TypeAliasTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
TemplateParameterList *Params, NamedDecl *Decl)
: RedeclarableTemplateDecl(TypeAliasTemplate, DC, L, Name, Params, Decl) { }
CommonBase *newCommon(ASTContext &C);
Common *getCommonPtr() {
return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
}
public:
/// Get the underlying function declaration of the template.
TypeAliasDecl *getTemplatedDecl() const {
return static_cast<TypeAliasDecl*>(TemplatedDecl);
}
TypeAliasTemplateDecl *getCanonicalDecl() {
return redeclarable_base::getCanonicalDecl();
}
const TypeAliasTemplateDecl *getCanonicalDecl() const {
return redeclarable_base::getCanonicalDecl();
}
/// \brief Retrieve the previous declaration of this function template, or
/// NULL if no such declaration exists.
TypeAliasTemplateDecl *getPreviousDeclaration() {
return redeclarable_base::getPreviousDeclaration();
}
/// \brief Retrieve the previous declaration of this function template, or
/// NULL if no such declaration exists.
const TypeAliasTemplateDecl *getPreviousDeclaration() const {
return redeclarable_base::getPreviousDeclaration();
}
TypeAliasTemplateDecl *getInstantiatedFromMemberTemplate() {
return redeclarable_base::getInstantiatedFromMemberTemplate();
}
/// \brief Create a function template node.
static TypeAliasTemplateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
DeclarationName Name,
TemplateParameterList *Params,
NamedDecl *Decl);
/// \brief Create an empty alias template node.
static TypeAliasTemplateDecl *Create(ASTContext &C, EmptyShell);
// Implement isa/cast/dyncast support
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const TypeAliasTemplateDecl *D) { return true; }
static bool classofKind(Kind K) { return K == TypeAliasTemplate; }
friend class ASTDeclReader;
friend class ASTDeclWriter;
};
/// Implementation of inline functions that require the template declarations
inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD)
: Function(FTD) { }

Просмотреть файл

@ -1368,6 +1368,11 @@ DEF_TRAVERSE_DECL(TypeAliasDecl, {
// source.
})
DEF_TRAVERSE_DECL(TypeAliasTemplateDecl, {
TRY_TO(TraverseDecl(D->getTemplatedDecl()));
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
})
DEF_TRAVERSE_DECL(UnresolvedUsingTypenameDecl, {
// A dependent using declaration which was marked with 'typename'.
// template<class T> class A : public B<T> { using typename B<T>::foo; };

Просмотреть файл

@ -3201,6 +3201,10 @@ public:
/// Other template specialization types, for which the template name
/// is dependent, may be canonical types. These types are always
/// dependent.
///
/// An instance of this type is followed by an array of TemplateArgument*s,
/// then, if the template specialization type is for a type alias template,
/// a QualType representing the non-canonical aliased type.
class TemplateSpecializationType
: public Type, public llvm::FoldingSetNode {
/// \brief The name of the template being specialized.
@ -3212,7 +3216,8 @@ class TemplateSpecializationType
TemplateSpecializationType(TemplateName T,
const TemplateArgument *Args,
unsigned NumArgs, QualType Canon);
unsigned NumArgs, QualType Canon,
QualType Aliased);
friend class ASTContext; // ASTContext creates these
@ -3247,6 +3252,16 @@ public:
return isa<InjectedClassNameType>(getCanonicalTypeInternal());
}
/// True if this template specialization type is for a type alias
/// template.
bool isTypeAlias() const;
/// Get the aliased type, if this is a specialization of a type alias
/// template.
QualType getAliasedType() const {
assert(isTypeAlias() && "not a type alias template specialization");
return *reinterpret_cast<const QualType*>(end());
}
typedef const TemplateArgument * iterator;
iterator begin() const { return getArgs(); }
@ -3268,12 +3283,14 @@ public:
const TemplateArgument &getArg(unsigned Idx) const; // in TemplateBase.h
bool isSugared() const {
return !isDependentType() || isCurrentInstantiation();
return !isDependentType() || isCurrentInstantiation() || isTypeAlias();
}
QualType desugar() const { return getCanonicalTypeInternal(); }
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) {
Profile(ID, Template, getArgs(), NumArgs, Ctx);
if (isTypeAlias())
getAliasedType().Profile(ID);
}
static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T,

Просмотреть файл

@ -50,6 +50,7 @@ def Named : Decl<1>;
def RedeclarableTemplate : DDecl<Template, 1>;
def FunctionTemplate : DDecl<RedeclarableTemplate>;
def ClassTemplate : DDecl<RedeclarableTemplate>;
def TypeAliasTemplate : DDecl<RedeclarableTemplate>;
def TemplateTemplateParm : DDecl<Template>;
def Using : DDecl<Named>;
def UsingShadow : DDecl<Named>;

Просмотреть файл

@ -443,6 +443,8 @@ def ext_alias_declaration : ExtWarn<
"alias declarations accepted as a C++0x extension">, InGroup<CXX0x>;
def err_alias_declaration_not_identifier : Error<
"name defined in alias declaration must be an identifier">;
def err_alias_declaration_specialization : Error<
"%select{partial specialization|explicit specialization|explicit instantiation}0 of alias templates is not permitted">;
// C++0x override control
def ext_override_control_keyword : Extension<

Просмотреть файл

@ -544,6 +544,8 @@ def err_type_defined_in_result_type : Error<
"%0 can not be defined in the result type of a function">;
def err_type_defined_in_param_type : Error<
"%0 can not be defined in a parameter type">;
def err_type_defined_in_alias_template : Error<
"%0 can not be defined in a type alias template">;
def note_pure_virtual_function : Note<
"unimplemented pure virtual method %0 in %1">;
@ -1674,7 +1676,7 @@ def err_template_arg_must_be_expr : Error<
def err_template_arg_nontype_ambig : Error<
"template argument for non-type template parameter is treated as type %0">;
def err_template_arg_must_be_template : Error<
"template argument for template template parameter must be a class template">;
"template argument for template template parameter must be a class template%select{| or type alias template}0">;
def ext_template_arg_local_type : ExtWarn<
"template argument uses local type %0">, InGroup<LocalTypeTemplateArgs>;
def ext_template_arg_unnamed_type : ExtWarn<
@ -1820,6 +1822,8 @@ def err_template_spec_needs_template_parameters : Error<
def err_template_param_list_matches_nontemplate : Error<
"template parameter list matching the non-templated nested type %0 should "
"be empty ('template<>')">;
def err_alias_template_extra_headers : Error<
"extraneous template parameter list in alias template declaration">;
def err_template_spec_extra_headers : Error<
"extraneous template parameter list in template specialization or "
"out-of-line template definition">;
@ -1897,6 +1901,8 @@ def note_function_template_spec_here : Note<
"in instantiation of function template specialization %q0 requested here">;
def note_template_static_data_member_def_here : Note<
"in instantiation of static data member %q0 requested here">;
def note_template_type_alias_instantiation_here : Note<
"in instantiation of template type alias %0 requested here">;
def note_default_arg_instantiation_here : Note<
"in instantiation of default argument for '%0' required here">;
@ -2034,7 +2040,7 @@ def err_non_type_template_in_nested_name_specifier : Error<
def err_template_id_not_a_type : Error<
"template name refers to non-type template '%0'">;
def note_template_declared_here : Note<
"%select{function template|class template|template template parameter}0 "
"%select{function template|class template|type alias template|template template parameter}0 "
"%1 declared here">;
// C++0x Variadic Templates
@ -2172,9 +2178,9 @@ def err_redefinition_different_type : Error<
def err_redefinition_different_kind : Error<
"redefinition of %0 as different kind of symbol">;
def err_redefinition_different_typedef : Error<
"%select{typedef|type alias}0 redefinition with different types (%1 vs %2)">;
"%select{typedef|type alias|type alias template}0 redefinition with different types (%1 vs %2)">;
def err_tag_reference_non_tag : Error<
"elaborated type refers to %select{a non-tag type|a typedef|a type alias|a template}0">;
"elaborated type refers to %select{a non-tag type|a typedef|a type alias|a template|a type alias template}0">;
def err_tag_reference_conflict : Error<
"implicit declaration introduced by elaborated type conflicts with "
"%select{a declaration|a typedef|a type alias|a template}0 of the same name">;

Просмотреть файл

@ -1332,7 +1332,8 @@ public:
CXXCatchContext, // C++ catch exception-declaration
BlockLiteralContext, // Block literal declarator.
TemplateTypeArgContext, // Template type argument.
AliasDeclContext // C++0x alias-declaration.
AliasDeclContext, // C++0x alias-declaration.
AliasTemplateContext // C++0x alias-declaration template.
};
private:
@ -1474,6 +1475,7 @@ public:
case TypeNameContext:
case AliasDeclContext:
case AliasTemplateContext:
case PrototypeContext:
case ObjCPrototypeContext:
case TemplateParamContext:
@ -1503,6 +1505,7 @@ public:
case TypeNameContext:
case AliasDeclContext:
case AliasTemplateContext:
case ObjCPrototypeContext:
case BlockLiteralContext:
case TemplateTypeArgContext:
@ -1531,6 +1534,7 @@ public:
case CXXCatchContext:
case TypeNameContext:
case AliasDeclContext:
case AliasTemplateContext:
case BlockLiteralContext:
case TemplateTypeArgContext:
return false;

Просмотреть файл

@ -944,6 +944,7 @@ public:
void CheckShadow(Scope *S, VarDecl *D, const LookupResult& R);
void CheckShadow(Scope *S, VarDecl *D);
void CheckCastAlign(Expr *Op, QualType T, SourceRange TRange);
void CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *D);
NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
QualType R, TypeSourceInfo *TInfo,
LookupResult &Previous, bool &Redeclaration);
@ -1652,6 +1653,10 @@ public:
AssociatedNamespaceSet &AssociatedNamespaces,
AssociatedClassSet &AssociatedClasses);
void FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S,
bool ConsiderLinkage,
bool ExplicitInstantiationOrSpecialization);
bool DiagnoseAmbiguousLookup(LookupResult &Result);
//@}
@ -2468,6 +2473,7 @@ public:
SourceLocation TypenameLoc);
Decl *ActOnAliasDeclaration(Scope *CurScope,
AccessSpecifier AS,
MultiTemplateParamsArg TemplateParams,
SourceLocation UsingLoc,
UnqualifiedId &Name,
TypeResult Type);
@ -3412,7 +3418,8 @@ public:
TPC_FunctionTemplate,
TPC_ClassTemplateMember,
TPC_FriendFunctionTemplate,
TPC_FriendFunctionTemplateDefinition
TPC_FriendFunctionTemplateDefinition,
TPC_TypeAliasTemplate
};
bool CheckTemplateParameterList(TemplateParameterList *NewParams,

Просмотреть файл

@ -335,9 +335,9 @@ namespace clang {
Decl *VisitLabelDecl(LabelDecl *D);
Decl *VisitNamespaceDecl(NamespaceDecl *D);
Decl *VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
Decl *VisitTypedefNameDecl(TypedefNameDecl *D, bool IsTypeAlias);
Decl *VisitTypedefDecl(TypedefDecl *D);
Decl *VisitTypeAliasDecl(TypeAliasDecl *D);
Decl *VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
Decl *VisitVarDecl(VarDecl *D);
Decl *VisitAccessSpecDecl(AccessSpecDecl *D);
Decl *VisitFieldDecl(FieldDecl *D);
@ -415,6 +415,7 @@ namespace clang {
bool SubstQualifier(const TagDecl *OldDecl,
TagDecl *NewDecl);
Decl *InstantiateTypedefNameDecl(TypedefNameDecl *D, bool IsTypeAlias);
ClassTemplatePartialSpecializationDecl *
InstantiateClassTemplatePartialSpecialization(
ClassTemplateDecl *ClassTemplate,

Просмотреть файл

@ -761,6 +761,8 @@ namespace clang {
DECL_NON_TYPE_TEMPLATE_PARM,
/// \brief A TemplateTemplateParmDecl record.
DECL_TEMPLATE_TEMPLATE_PARM,
/// \brief A TypeAliasTemplateDecl record.
DECL_TYPE_ALIAS_TEMPLATE,
/// \brief A StaticAssertDecl record.
DECL_STATIC_ASSERT,
/// \brief A record containing CXXBaseSpecifiers.

Просмотреть файл

@ -969,13 +969,18 @@ ASTContext::getTypeInfo(const Type *T) const {
return getTypeInfo(
cast<AttributedType>(T)->getEquivalentType().getTypePtr());
case Type::TemplateSpecialization:
case Type::TemplateSpecialization: {
assert(getCanonicalType(T) != T &&
"Cannot request the size of a dependent type");
// FIXME: this is likely to be wrong once we support template
// aliases, since a template alias could refer to a typedef that
// has an __aligned__ attribute on it.
return getTypeInfo(getCanonicalType(T));
const TemplateSpecializationType *TST = cast<TemplateSpecializationType>(T);
// A type alias template specialization may refer to a typedef with the
// aligned attribute on it.
if (TST->isTypeAlias())
return getTypeInfo(TST->getAliasedType().getTypePtr());
else
return getTypeInfo(getCanonicalType(T));
}
}
assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2");
@ -2247,10 +2252,10 @@ TypeSourceInfo *
ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
SourceLocation NameLoc,
const TemplateArgumentListInfo &Args,
QualType CanonType) const {
QualType Underlying) const {
assert(!Name.getAsDependentTemplateName() &&
"No dependent template names here!");
QualType TST = getTemplateSpecializationType(Name, Args, CanonType);
QualType TST = getTemplateSpecializationType(Name, Args, Underlying);
TypeSourceInfo *DI = CreateTypeSourceInfo(TST);
TemplateSpecializationTypeLoc TL
@ -2266,7 +2271,7 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
QualType
ASTContext::getTemplateSpecializationType(TemplateName Template,
const TemplateArgumentListInfo &Args,
QualType Canon) const {
QualType Underlying) const {
assert(!Template.getAsDependentTemplateName() &&
"No dependent template names here!");
@ -2278,35 +2283,46 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
ArgVec.push_back(Args[i].getArgument());
return getTemplateSpecializationType(Template, ArgVec.data(), NumArgs,
Canon);
Underlying);
}
QualType
ASTContext::getTemplateSpecializationType(TemplateName Template,
const TemplateArgument *Args,
unsigned NumArgs,
QualType Canon) const {
QualType Underlying) const {
assert(!Template.getAsDependentTemplateName() &&
"No dependent template names here!");
// Look through qualified template names.
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
Template = TemplateName(QTN->getTemplateDecl());
if (!Canon.isNull())
Canon = getCanonicalType(Canon);
else
Canon = getCanonicalTemplateSpecializationType(Template, Args, NumArgs);
bool isTypeAlias =
Template.getAsTemplateDecl() &&
isa<TypeAliasTemplateDecl>(Template.getAsTemplateDecl());
QualType CanonType;
if (!Underlying.isNull())
CanonType = getCanonicalType(Underlying);
else {
assert(!isTypeAlias &&
"Underlying type for template alias must be computed by caller");
CanonType = getCanonicalTemplateSpecializationType(Template, Args,
NumArgs);
}
// Allocate the (non-canonical) template specialization type, but don't
// try to unique it: these types typically have location information that
// we don't unique and don't want to lose.
void *Mem = Allocate((sizeof(TemplateSpecializationType) +
sizeof(TemplateArgument) * NumArgs),
void *Mem = Allocate(sizeof(TemplateSpecializationType) +
sizeof(TemplateArgument) * NumArgs +
(isTypeAlias ? sizeof(QualType) : 0),
TypeAlignment);
TemplateSpecializationType *Spec
= new (Mem) TemplateSpecializationType(Template,
Args, NumArgs,
Canon);
CanonType,
isTypeAlias ? Underlying : QualType());
Types.push_back(Spec);
return QualType(Spec, 0);
@ -2318,6 +2334,10 @@ ASTContext::getCanonicalTemplateSpecializationType(TemplateName Template,
unsigned NumArgs) const {
assert(!Template.getAsDependentTemplateName() &&
"No dependent template names here!");
assert((!Template.getAsTemplateDecl() ||
!isa<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) &&
"Underlying type for template alias must be computed by caller");
// Look through qualified template names.
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
Template = TemplateName(QTN->getTemplateDecl());
@ -2346,7 +2366,7 @@ ASTContext::getCanonicalTemplateSpecializationType(TemplateName Template,
TypeAlignment);
Spec = new (Mem) TemplateSpecializationType(CanonTemplate,
CanonArgs.data(), NumArgs,
QualType());
QualType(), QualType());
Types.push_back(Spec);
TemplateSpecializationTypes.InsertNode(Spec, InsertPos);
}

Просмотреть файл

@ -56,9 +56,11 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) {
continue;
}
// Don't desugar template specializations.
if (isa<TemplateSpecializationType>(Ty))
break;
// Don't desugar template specializations, unless it's an alias template.
if (const TemplateSpecializationType *TST
= dyn_cast<TemplateSpecializationType>(Ty))
if (!TST->isTypeAlias())
break;
// Don't desugar magic Objective-C types.
if (QualType(Ty,0) == Context.getObjCIdType() ||

Просмотреть файл

@ -439,6 +439,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case Typedef:
case TypeAlias:
case TypeAliasTemplate:
case UnresolvedUsingTypename:
case TemplateTypeParm:
return IDNS_Ordinary | IDNS_Type;

Просмотреть файл

@ -735,3 +735,34 @@ FriendTemplateDecl *FriendTemplateDecl::Create(ASTContext &Context,
EmptyShell Empty) {
return new (Context) FriendTemplateDecl(Empty);
}
//===----------------------------------------------------------------------===//
// TypeAliasTemplateDecl Implementation
//===----------------------------------------------------------------------===//
TypeAliasTemplateDecl *TypeAliasTemplateDecl::Create(ASTContext &C,
DeclContext *DC,
SourceLocation L,
DeclarationName Name,
TemplateParameterList *Params,
NamedDecl *Decl) {
AdoptTemplateParameterList(Params, DC);
return new (C) TypeAliasTemplateDecl(DC, L, Name, Params, Decl);
}
TypeAliasTemplateDecl *TypeAliasTemplateDecl::Create(ASTContext &C,
EmptyShell) {
return new (C) TypeAliasTemplateDecl(0, SourceLocation(), DeclarationName(),
0, 0);
}
void TypeAliasTemplateDecl::DeallocateCommon(void *Ptr) {
static_cast<Common *>(Ptr)->~Common();
}
RedeclarableTemplateDecl::CommonBase *
TypeAliasTemplateDecl::newCommon(ASTContext &C) {
Common *CommonPtr = new (C) Common;
C.AddDeallocation(DeallocateCommon, CommonPtr);
return CommonPtr;
}

Просмотреть файл

@ -619,7 +619,8 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
// TemplateDecl
void visitTemplateDeclChildren(TemplateDecl *D) {
visitTemplateParameters(D->getTemplateParameters());
dispatch(D->getTemplatedDecl());
if (D->getTemplatedDecl())
dispatch(D->getTemplatedDecl());
}
// FunctionTemplateDecl

Просмотреть файл

@ -1559,13 +1559,13 @@ anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N) {
TemplateSpecializationType::
TemplateSpecializationType(TemplateName T,
const TemplateArgument *Args,
unsigned NumArgs, QualType Canon)
const TemplateArgument *Args, unsigned NumArgs,
QualType Canon, QualType AliasedType)
: Type(TemplateSpecialization,
Canon.isNull()? QualType(this, 0) : Canon,
T.isDependent(), false, T.containsUnexpandedParameterPack()),
Template(T), NumArgs(NumArgs)
{
Canon.isNull()? T.isDependent() : Canon->isDependentType(),
false, T.containsUnexpandedParameterPack()),
Template(T), NumArgs(NumArgs) {
assert(!T.getAsDependentTemplateName() &&
"Use DependentTemplateSpecializationType for dependent template-name");
assert((!Canon.isNull() ||
@ -1576,7 +1576,12 @@ TemplateSpecializationType(TemplateName T,
= reinterpret_cast<TemplateArgument *>(this + 1);
for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
// Update dependent and variably-modified bits.
if (Args[Arg].isDependent())
// If the canonical type exists and is non-dependent, the template
// specialization type can be non-dependent even if one of the type
// arguments is. Given:
// template<typename T> using U = int;
// U<T> is always non-dependent, irrespective of the type T.
if (Canon.isNull() && Args[Arg].isDependent())
setDependent();
if (Args[Arg].getKind() == TemplateArgument::Type &&
Args[Arg].getAsType()->isVariablyModifiedType())
@ -1586,6 +1591,15 @@ TemplateSpecializationType(TemplateName T,
new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]);
}
// Store the aliased type if this is a type alias template specialization.
bool IsTypeAlias = !AliasedType.isNull();
assert(IsTypeAlias == isTypeAlias() &&
"allocated wrong size for type alias");
if (IsTypeAlias) {
TemplateArgument *Begin = reinterpret_cast<TemplateArgument *>(this + 1);
*reinterpret_cast<QualType*>(Begin + getNumArgs()) = AliasedType;
}
}
void
@ -1599,6 +1613,11 @@ TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
Args[Idx].Profile(ID, Context);
}
bool TemplateSpecializationType::isTypeAlias() const {
TemplateDecl *D = Template.getAsTemplateDecl();
return D && isa<TypeAliasTemplateDecl>(D);
}
QualType
QualifierCollector::apply(const ASTContext &Context, QualType QT) const {
if (!hasNonFastQualifiers())

Просмотреть файл

@ -51,6 +51,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::ImplicitParam:
case Decl::ClassTemplate:
case Decl::FunctionTemplate:
case Decl::TypeAliasTemplate:
case Decl::TemplateTemplateParm:
case Decl::ObjCMethod:
case Decl::ObjCCategory:

Просмотреть файл

@ -2060,6 +2060,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case Decl::UsingDirective:
case Decl::ClassTemplate:
case Decl::FunctionTemplate:
case Decl::TypeAliasTemplate:
case Decl::NamespaceAlias:
break;
case Decl::CXXConstructor:

Просмотреть файл

@ -557,6 +557,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("ownership_returns", true)
.Case("ownership_takes", true)
// C++0x features
.Case("cxx_alias_templates", LangOpts.CPlusPlus0x)
.Case("cxx_attributes", LangOpts.CPlusPlus0x)
.Case("cxx_auto_type", LangOpts.CPlusPlus0x)
.Case("cxx_decltype", LangOpts.CPlusPlus0x)

Просмотреть файл

@ -387,13 +387,34 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
bool IsAliasDecl = Tok.is(tok::equal);
TypeResult TypeAlias;
if (IsAliasDecl) {
// TODO: Do we want to support attributes somewhere in an alias declaration?
// Can't follow GCC since it doesn't support them yet!
// TODO: Attribute support. C++0x attributes may appear before the equals.
// Where can GNU attributes appear?
ConsumeToken();
if (!getLang().CPlusPlus0x)
Diag(Tok.getLocation(), diag::ext_alias_declaration);
// Type alias templates cannot be specialized.
int SpecKind = -1;
if (Name.getKind() == UnqualifiedId::IK_TemplateId)
SpecKind = 0;
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization)
SpecKind = 1;
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
SpecKind = 2;
if (SpecKind != -1) {
SourceRange Range;
if (SpecKind == 0)
Range = SourceRange(Name.TemplateId->LAngleLoc,
Name.TemplateId->RAngleLoc);
else
Range = TemplateInfo.getSourceRange();
Diag(Range.getBegin(), diag::err_alias_declaration_specialization)
<< SpecKind << Range;
SkipUntil(tok::semi);
return 0;
}
// Name must be an identifier.
if (Name.getKind() != UnqualifiedId::IK_Identifier) {
Diag(Name.StartLocation, diag::err_alias_declaration_not_identifier);
@ -408,7 +429,9 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
Diag(SS.getBeginLoc(), diag::err_alias_declaration_not_identifier)
<< FixItHint::CreateRemoval(SS.getRange());
TypeAlias = ParseTypeName(0, Declarator::AliasDeclContext);
TypeAlias = ParseTypeName(0, TemplateInfo.Kind ?
Declarator::AliasTemplateContext :
Declarator::AliasDeclContext);
} else
// Parse (optional) attributes (most likely GNU strong-using extension).
MaybeParseGNUAttributes(attrs);
@ -421,9 +444,9 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
tok::semi);
// Diagnose an attempt to declare a templated using-declaration.
// TODO: in C++0x, alias-declarations can be templates:
// In C++0x, alias-declarations can be templates:
// template <...> using id = type;
if (TemplateInfo.Kind) {
if (TemplateInfo.Kind && !IsAliasDecl) {
SourceRange R = TemplateInfo.getSourceRange();
Diag(UsingLoc, diag::err_templated_using_declaration)
<< R << FixItHint::CreateRemoval(R);
@ -434,9 +457,14 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
return 0;
}
if (IsAliasDecl)
return Actions.ActOnAliasDeclaration(getCurScope(), AS, UsingLoc, Name,
TypeAlias);
if (IsAliasDecl) {
TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
MultiTemplateParamsArg TemplateParamsArg(Actions,
TemplateParams ? TemplateParams->data() : 0,
TemplateParams ? TemplateParams->size() : 0);
return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg,
UsingLoc, Name, TypeAlias);
}
return Actions.ActOnUsingDeclaration(getCurScope(), AS, true, UsingLoc, SS,
Name, attrs.getList(),
@ -1515,8 +1543,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
MaybeParseMicrosoftAttributes(attrs);
if (Tok.is(tok::kw_using)) {
// FIXME: Check for template aliases
ProhibitAttributes(attrs);
// Eat 'using'.
@ -1527,7 +1553,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
SkipUntil(tok::semi, true, true);
} else {
SourceLocation DeclEnd;
// Otherwise, it must be using-declaration.
// Otherwise, it must be a using-declaration or an alias-declaration.
ParseUsingDeclaration(Declarator::MemberContext, TemplateInfo,
UsingLoc, DeclEnd, AS);
}

Просмотреть файл

@ -905,10 +905,10 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
// C++0x [temp.arg.template]p1:
// A template-argument for a template template-parameter shall be the name
// of a class template or a template alias, expressed as id-expression.
// of a class template or an alias template, expressed as id-expression.
//
// We parse an id-expression that refers to a class template or template
// alias. The grammar we parse is:
// We parse an id-expression that refers to a class template or alias
// template. The grammar we parse is:
//
// nested-name-specifier[opt] template[opt] identifier ...[opt]
//
@ -969,7 +969,7 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
MemberOfUnknownSpecialization);
if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template) {
// We have an id-expression that refers to a class template or
// (C++0x) template alias.
// (C++0x) alias template.
Result = ParsedTemplateArgument(SS, Template, Name.StartLocation);
}
}

Просмотреть файл

@ -445,8 +445,8 @@ static AccessResult MatchesFriend(Sema &S,
continue;
// If the template names don't match, it can't be a dependent
// match. This isn't true in C++0x because of template aliases.
if (!S.LangOpts.CPlusPlus0x && CTD->getDeclName() != Friend->getDeclName())
// match.
if (CTD->getDeclName() != Friend->getDeclName())
continue;
// If the class's context can't instantiate to the friend's

Просмотреть файл

@ -94,9 +94,13 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
if (EnteringContext) {
const Type *NNSType = NNS->getAsType();
if (!NNSType) {
// do nothing, fall out
} else if (const TemplateSpecializationType *SpecType
= NNSType->getAs<TemplateSpecializationType>()) {
return 0;
}
// Look through type alias templates, per C++0x [temp.dep.type]p1.
NNSType = Context.getCanonicalType(NNSType);
if (const TemplateSpecializationType *SpecType
= NNSType->getAs<TemplateSpecializationType>()) {
// We are entering the context of the nested name specifier, so try to
// match the nested name specifier to either a primary class template
// or a class template partial specialization.
@ -382,7 +386,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
isDependent = ObjectType->isDependentType();
} else if (SS.isSet()) {
// This nested-name-specifier occurs after another nested-name-specifier,
// so long into the context associated with the prior nested-name-specifier.
// so look into the context associated with the prior nested-name-specifier.
LookupCtx = computeDeclContext(SS, EnteringContext);
isDependent = isDependentScopeSpecifier(SS);
Found.setContextRange(SS.getRange());
@ -712,8 +716,13 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
if (T.isNull())
return true;
// FIXME: Template aliases will need to check the resulting type to make
// sure that it's either dependent or a tag type.
// Alias template specializations can produce types which are not valid
// nested name specifiers.
if (!T->isDependentType() && !T->getAs<TagType>()) {
Diag(TemplateNameLoc, diag::err_nested_name_spec_non_tag) << T;
NoteAllFoundTemplates(Template.get());
return true;
}
// Provide source-location information for the template specialization
// type.

Просмотреть файл

@ -891,19 +891,19 @@ static bool isOutOfScopePreviousDeclaration(NamedDecl *,
/// Filters out lookup results that don't fall within the given scope
/// as determined by isDeclInScope.
static void FilterLookupForScope(Sema &SemaRef, LookupResult &R,
DeclContext *Ctx, Scope *S,
bool ConsiderLinkage,
bool ExplicitInstantiationOrSpecialization) {
void Sema::FilterLookupForScope(LookupResult &R,
DeclContext *Ctx, Scope *S,
bool ConsiderLinkage,
bool ExplicitInstantiationOrSpecialization) {
LookupResult::Filter F = R.makeFilter();
while (F.hasNext()) {
NamedDecl *D = F.next();
if (SemaRef.isDeclInScope(D, Ctx, S, ExplicitInstantiationOrSpecialization))
if (isDeclInScope(D, Ctx, S, ExplicitInstantiationOrSpecialization))
continue;
if (ConsiderLinkage &&
isOutOfScopePreviousDeclaration(D, Ctx, SemaRef.Context))
isOutOfScopePreviousDeclaration(D, Ctx, Context))
continue;
F.erase();
@ -3304,15 +3304,13 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Handle attributes prior to checking for duplicates in MergeVarDecl
ProcessDeclAttributes(S, NewTD, D);
CheckTypedefForVariablyModifiedType(S, NewTD);
return ActOnTypedefNameDecl(S, DC, NewTD, Previous, Redeclaration);
}
/// ActOnTypedefNameDecl - Perform semantic checking for a declaration which
/// declares a typedef-name, either using the 'typedef' type specifier or via
/// a C++0x [dcl.typedef]p2 alias-declaration: 'using T = A;'.
NamedDecl*
Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
LookupResult &Previous, bool &Redeclaration) {
void
Sema::CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *NewTD) {
// C99 6.7.7p2: If a typedef name specifies a variably modified type
// then it shall have block scope.
// Note that variably modified types must be fixed before merging the decl so
@ -3343,10 +3341,18 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
}
}
}
}
/// ActOnTypedefNameDecl - Perform semantic checking for a declaration which
/// declares a typedef-name, either using the 'typedef' type specifier or via
/// a C++0x [dcl.typedef]p2 alias-declaration: 'using T = A;'.
NamedDecl*
Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
LookupResult &Previous, bool &Redeclaration) {
// Merge the decl with the existing one if appropriate. If the decl is
// in an outer scope, it isn't the same thing.
FilterLookupForScope(*this, Previous, DC, S, /*ConsiderLinkage*/ false,
FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage*/ false,
/*ExplicitInstantiationOrSpecialization=*/false);
if (!Previous.empty()) {
Redeclaration = true;
@ -3625,7 +3631,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Don't consider existing declarations that are in a different
// scope and are out-of-semantic-context declarations (if the new
// declaration has linkage).
FilterLookupForScope(*this, Previous, DC, S, NewVD->hasLinkage(),
FilterLookupForScope(Previous, DC, S, NewVD->hasLinkage(),
isExplicitSpecialization);
if (!getLangOptions().CPlusPlus)
@ -4072,7 +4078,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Set the lexical context.
NewFD->setLexicalDeclContext(CurContext);
// Filter out previous declarations that don't match the scope.
FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage(),
FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(),
/*ExplicitInstantiationOrSpecialization=*/false);
} else {
isFriend = D.getDeclSpec().isFriendSpecified();
@ -4350,7 +4356,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
// Filter out previous declarations that don't match the scope.
FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage(),
FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(),
isExplicitSpecialization ||
isFunctionTemplateSpecialization);
@ -4417,6 +4423,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
bool IsTypeAlias = false;
if (const TypedefType *TT = Param->getType()->getAs<TypedefType>())
IsTypeAlias = isa<TypeAliasDecl>(TT->getDecl());
else if (const TemplateSpecializationType *TST =
Param->getType()->getAs<TemplateSpecializationType>())
IsTypeAlias = TST->isTypeAlias();
Diag(Param->getLocation(), diag::err_param_typedef_of_void)
<< IsTypeAlias;
}

Просмотреть файл

@ -3467,6 +3467,11 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
if (const TypedefType *TT = DeclaratorType->getAs<TypedefType>())
Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name)
<< DeclaratorType << isa<TypeAliasDecl>(TT->getDecl());
else if (const TemplateSpecializationType *TST =
DeclaratorType->getAs<TemplateSpecializationType>())
if (TST->isTypeAlias())
Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name)
<< DeclaratorType << 1;
// C++ [class.dtor]p2:
// A destructor is used to destroy objects of its class type. A
@ -4701,9 +4706,13 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
Decl *Sema::ActOnAliasDeclaration(Scope *S,
AccessSpecifier AS,
MultiTemplateParamsArg TemplateParamLists,
SourceLocation UsingLoc,
UnqualifiedId &Name,
TypeResult Type) {
// Skip up to the relevant declaration scope.
while (S->getFlags() & Scope::TemplateParamScope)
S = S->getParent();
assert((S->getFlags() & Scope::DeclScope) &&
"got alias-declaration outside of declaration scope");
@ -4719,8 +4728,11 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
return 0;
if (DiagnoseUnexpandedParameterPack(Name.StartLocation, TInfo,
UPPC_DeclarationType))
UPPC_DeclarationType)) {
Invalid = true;
TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy,
TInfo->getTypeLoc().getBeginLoc());
}
LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration);
LookupName(Previous, S);
@ -4745,13 +4757,93 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
if (Invalid)
NewTD->setInvalidDecl();
CheckTypedefForVariablyModifiedType(S, NewTD);
Invalid |= NewTD->isInvalidDecl();
bool Redeclaration = false;
ActOnTypedefNameDecl(S, CurContext, NewTD, Previous, Redeclaration);
NamedDecl *NewND;
if (TemplateParamLists.size()) {
TypeAliasTemplateDecl *OldDecl = 0;
TemplateParameterList *OldTemplateParams = 0;
if (TemplateParamLists.size() != 1) {
Diag(UsingLoc, diag::err_alias_template_extra_headers)
<< SourceRange(TemplateParamLists.get()[1]->getTemplateLoc(),
TemplateParamLists.get()[TemplateParamLists.size()-1]->getRAngleLoc());
}
TemplateParameterList *TemplateParams = TemplateParamLists.get()[0];
// Only consider previous declarations in the same scope.
FilterLookupForScope(Previous, CurContext, S, /*ConsiderLinkage*/false,
/*ExplicitInstantiationOrSpecialization*/false);
if (!Previous.empty()) {
Redeclaration = true;
OldDecl = Previous.getAsSingle<TypeAliasTemplateDecl>();
if (!OldDecl && !Invalid) {
Diag(UsingLoc, diag::err_redefinition_different_kind)
<< Name.Identifier;
NamedDecl *OldD = Previous.getRepresentativeDecl();
if (OldD->getLocation().isValid())
Diag(OldD->getLocation(), diag::note_previous_definition);
Invalid = true;
}
if (!Invalid && OldDecl && !OldDecl->isInvalidDecl()) {
if (TemplateParameterListsAreEqual(TemplateParams,
OldDecl->getTemplateParameters(),
/*Complain=*/true,
TPL_TemplateMatch))
OldTemplateParams = OldDecl->getTemplateParameters();
else
Invalid = true;
TypeAliasDecl *OldTD = OldDecl->getTemplatedDecl();
if (!Invalid &&
!Context.hasSameType(OldTD->getUnderlyingType(),
NewTD->getUnderlyingType())) {
// FIXME: The C++0x standard does not clearly say this is ill-formed,
// but we can't reasonably accept it.
Diag(NewTD->getLocation(), diag::err_redefinition_different_typedef)
<< 2 << NewTD->getUnderlyingType() << OldTD->getUnderlyingType();
if (OldTD->getLocation().isValid())
Diag(OldTD->getLocation(), diag::note_previous_definition);
Invalid = true;
}
}
}
// Merge any previous default template arguments into our parameters,
// and check the parameter list.
if (CheckTemplateParameterList(TemplateParams, OldTemplateParams,
TPC_TypeAliasTemplate))
return 0;
TypeAliasTemplateDecl *NewDecl =
TypeAliasTemplateDecl::Create(Context, CurContext, UsingLoc,
Name.Identifier, TemplateParams,
NewTD);
NewDecl->setAccess(AS);
if (Invalid)
NewDecl->setInvalidDecl();
else if (OldDecl)
NewDecl->setPreviousDeclaration(OldDecl);
NewND = NewDecl;
} else {
ActOnTypedefNameDecl(S, CurContext, NewTD, Previous, Redeclaration);
NewND = NewTD;
}
if (!Redeclaration)
PushOnScopeChains(NewTD, S);
PushOnScopeChains(NewND, S);
return NewTD;
return NewND;
}
Decl *Sema::ActOnNamespaceAliasDef(Scope *S,

Просмотреть файл

@ -92,11 +92,9 @@ void Sema::FilterAcceptableTemplateNames(LookupResult &R) {
// ambiguity in certain cases (for example, if it is found in more than
// one base class). If all of the injected-class-names that are found
// refer to specializations of the same class template, and if the name
// is followed by a template-argument-list, the reference refers to the
// class template itself and not a specialization thereof, and is not
// is used as a template-name, the reference refers to the class
// template itself and not a specialization thereof, and is not
// ambiguous.
//
// FIXME: Will we eventually have to do the same for alias templates?
if (ClassTemplateDecl *ClassTmpl = dyn_cast<ClassTemplateDecl>(Repl))
if (!ClassTemplates.insert(ClassTmpl)) {
filter.erase();
@ -199,7 +197,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
// We'll do this lookup again later.
R.suppressDiagnostics();
} else {
assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD));
assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD) ||
isa<TypeAliasTemplateDecl>(TD));
TemplateKind = TNK_Type_template;
}
}
@ -1062,6 +1061,7 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S,
SourceRange DefArgRange) {
switch (TPC) {
case Sema::TPC_ClassTemplate:
case Sema::TPC_TypeAliasTemplate:
return false;
case Sema::TPC_FunctionTemplate:
@ -1187,9 +1187,10 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
bool MissingDefaultArg = false;
// C++0x [temp.param]p11:
// If a template parameter of a primary class template is a template
// parameter pack, it shall be the last template parameter.
if (SawParameterPack && TPC == TPC_ClassTemplate) {
// If a template parameter of a primary class template or alias template
// is a template parameter pack, it shall be the last template parameter.
if (SawParameterPack &&
(TPC == TPC_ClassTemplate || TPC == TPC_TypeAliasTemplate)) {
Diag(ParameterPackLoc,
diag::err_template_param_pack_must_be_last_template_parameter);
Invalid = true;
@ -1655,7 +1656,8 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) {
Diag(Template->getLocation(), diag::note_template_declared_here)
<< (isa<FunctionTemplateDecl>(Template)? 0
: isa<ClassTemplateDecl>(Template)? 1
: 2)
: isa<TypeAliasTemplateDecl>(Template)? 2
: 3)
<< Template->getDeclName();
return;
}
@ -1675,13 +1677,24 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) {
QualType Sema::CheckTemplateIdType(TemplateName Name,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs) {
DependentTemplateName *DTN = Name.getAsDependentTemplateName();
if (DTN && DTN->isIdentifier())
// When building a template-id where the template-name is dependent,
// assume the template is a type template. Either our assumption is
// correct, or the code is ill-formed and will be diagnosed when the
// dependent name is substituted.
return Context.getDependentTemplateSpecializationType(ETK_None,
DTN->getQualifier(),
DTN->getIdentifier(),
TemplateArgs);
TemplateDecl *Template = Name.getAsTemplateDecl();
if (!Template || isa<FunctionTemplateDecl>(Template)) {
// We might have a substituted template template parameter pack. If so,
// build a template specialization type for it.
if (Name.getAsSubstTemplateTemplateParmPack())
return Context.getTemplateSpecializationType(Name, TemplateArgs);
Diag(TemplateLoc, diag::err_template_id_not_a_type)
<< Name;
NoteAllFoundTemplates(Name);
@ -1700,9 +1713,29 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
QualType CanonType;
if (Name.isDependent() ||
TemplateSpecializationType::anyDependentTemplateArguments(
TemplateArgs)) {
if (TypeAliasTemplateDecl *AliasTemplate
= dyn_cast<TypeAliasTemplateDecl>(Template)) {
// Find the canonical type for this type alias template specialization.
TypeAliasDecl *Pattern = AliasTemplate->getTemplatedDecl();
if (Pattern->isInvalidDecl())
return QualType();
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
Converted.data(), Converted.size());
// Only substitute for the innermost template argument list.
MultiLevelTemplateArgumentList TemplateArgLists;
TemplateArgLists.addOuterTemplateArguments(&TemplateArgs);
InstantiatingTemplate Inst(*this, TemplateLoc, Template);
CanonType = SubstType(Pattern->getUnderlyingType(),
TemplateArgLists, AliasTemplate->getLocation(),
AliasTemplate->getDeclName());
if (CanonType.isNull())
return QualType();
} else if (Name.isDependent() ||
TemplateSpecializationType::anyDependentTemplateArguments(
TemplateArgs)) {
// This class template specialization is a dependent
// type. Therefore, its canonical type is another class template
// specialization type that contains all of the converted
@ -1894,6 +1927,16 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo());
return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T));
}
if (TypeAliasTemplateDecl *TAT =
dyn_cast_or_null<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) {
// C++0x [dcl.type.elab]p2:
// If the identifier resolves to a typedef-name or the simple-template-id
// resolves to an alias template specialization, the
// elaborated-type-specifier is ill-formed.
Diag(TemplateLoc, diag::err_tag_reference_non_tag) << 4;
Diag(TAT->getLocation(), diag::note_declared_at);
}
QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs);
if (Result.isNull())
@ -2485,7 +2528,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
}
// We have a template argument that actually does refer to a class
// template, template alias, or template template parameter, and
// template, alias template, or template template parameter, and
// therefore cannot be a non-type template argument.
Diag(Arg.getLocation(), diag::err_template_arg_must_be_expr)
<< Arg.getSourceRange();
@ -2562,7 +2605,8 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
case TemplateArgument::Type:
// We have a template template parameter but the template
// argument does not refer to a template.
Diag(Arg.getLocation(), diag::err_template_arg_must_be_template);
Diag(Arg.getLocation(), diag::err_template_arg_must_be_template)
<< getLangOptions().CPlusPlus0x;
return true;
case TemplateArgument::Declaration:
@ -3722,9 +3766,10 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
return false;
}
// C++ [temp.arg.template]p1:
// C++0x [temp.arg.template]p1:
// A template-argument for a template template-parameter shall be
// the name of a class template, expressed as id-expression. Only
// the name of a class template or an alias template, expressed as an
// id-expression. When the template-argument names a class template, only
// primary class templates are considered when matching the
// template template argument with the corresponding parameter;
// partial specializations are not considered even if their
@ -3734,7 +3779,8 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
// will happen when we are dealing with, e.g., class template
// partial specializations.
if (!isa<ClassTemplateDecl>(Template) &&
!isa<TemplateTemplateParmDecl>(Template)) {
!isa<TemplateTemplateParmDecl>(Template) &&
!isa<TypeAliasTemplateDecl>(Template)) {
assert(isa<FunctionTemplateDecl>(Template) &&
"Only function templates are possible here");
Diag(Arg.getLocation(), diag::err_template_arg_not_class_template);
@ -4051,7 +4097,7 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
// C++0x [temp.arg.template]p3:
// A template-argument matches a template template-parameter (call it P)
// when each of the template parameters in the template-parameter-list of
// the template-argument's corresponding class template or template alias
// the template-argument's corresponding class template or alias template
// (call it A) matches the corresponding template parameter in the
// template-parameter-list of P. [...]
TemplateParameterList::iterator NewParm = New->begin();

Просмотреть файл

@ -446,10 +446,15 @@ void Sema::PrintInstantiationStack() {
Diags.Report(Active->PointOfInstantiation, DiagID)
<< Function
<< Active->InstantiationRange;
} else {
} else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
Diags.Report(Active->PointOfInstantiation,
diag::note_template_static_data_member_def_here)
<< cast<VarDecl>(D)
<< VD
<< Active->InstantiationRange;
} else {
Diags.Report(Active->PointOfInstantiation,
diag::note_template_type_alias_instantiation_here)
<< cast<TypeAliasTemplateDecl>(D)
<< Active->InstantiationRange;
}
break;
@ -968,8 +973,7 @@ TemplateName TemplateInstantiator::TransformTemplateName(CXXScopeSpec &SS,
}
TemplateName Template = Arg.getAsTemplate();
assert(!Template.isNull() && Template.getAsTemplateDecl() &&
"Wrong kind of template template argument");
assert(!Template.isNull() && "Null template template argument");
// We don't ever want to substitute for a qualified template name, since
// the qualifier is handled separately. So, look through the qualified

Просмотреть файл

@ -128,8 +128,8 @@ TemplateDeclInstantiator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
return Inst;
}
Decl *TemplateDeclInstantiator::VisitTypedefNameDecl(TypedefNameDecl *D,
bool IsTypeAlias) {
Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
bool IsTypeAlias) {
bool Invalid = false;
TypeSourceInfo *DI = D->getTypeSourceInfo();
if (DI->getType()->isDependentType() ||
@ -178,17 +178,62 @@ Decl *TemplateDeclInstantiator::VisitTypedefNameDecl(TypedefNameDecl *D,
SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef);
Typedef->setAccess(D->getAccess());
Owner->addDecl(Typedef);
return Typedef;
}
Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
return VisitTypedefNameDecl(D, /*IsTypeAlias=*/false);
Decl *Typedef = InstantiateTypedefNameDecl(D, /*IsTypeAlias=*/false);
Owner->addDecl(Typedef);
return Typedef;
}
Decl *TemplateDeclInstantiator::VisitTypeAliasDecl(TypeAliasDecl *D) {
return VisitTypedefNameDecl(D, /*IsTypeAlias=*/true);
Decl *Typedef = InstantiateTypedefNameDecl(D, /*IsTypeAlias=*/true);
Owner->addDecl(Typedef);
return Typedef;
}
Decl *
TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
// Create a local instantiation scope for this type alias template, which
// will contain the instantiations of the template parameters.
LocalInstantiationScope Scope(SemaRef);
TemplateParameterList *TempParams = D->getTemplateParameters();
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
return 0;
TypeAliasDecl *Pattern = D->getTemplatedDecl();
TypeAliasTemplateDecl *PrevAliasTemplate = 0;
if (Pattern->getPreviousDeclaration()) {
DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName());
if (Found.first != Found.second) {
PrevAliasTemplate = dyn_cast<TypeAliasTemplateDecl>(*Found.first);
}
}
TypeAliasDecl *AliasInst = cast_or_null<TypeAliasDecl>(
InstantiateTypedefNameDecl(Pattern, /*IsTypeAlias=*/true));
if (!AliasInst)
return 0;
TypeAliasTemplateDecl *Inst
= TypeAliasTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(),
D->getDeclName(), InstParams, AliasInst);
if (PrevAliasTemplate)
Inst->setPreviousDeclaration(PrevAliasTemplate);
Inst->setAccess(D->getAccess());
if (!PrevAliasTemplate)
Inst->setInstantiatedFromMemberTemplate(D);
Owner->addDecl(Inst);
return Inst;
}
/// \brief Instantiate an initializer, breaking it into separate

Просмотреть файл

@ -1601,6 +1601,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
Error = 7; // Template type argument
break;
case Declarator::AliasDeclContext:
case Declarator::AliasTemplateContext:
Error = 9; // Type alias
break;
case Declarator::TypeNameContext:
@ -1659,7 +1660,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// Does this declaration declare a typedef-name?
bool IsTypedefName =
D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef ||
D.getContext() == Declarator::AliasDeclContext;
D.getContext() == Declarator::AliasDeclContext ||
D.getContext() == Declarator::AliasTemplateContext;
// Walk the DeclTypeInfo, building the recursive type as we go.
// DeclTypeInfos are ordered from the identifier out, which is
@ -1839,7 +1841,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// anyway.
if (IsTypedefName && FTI.getExceptionSpecType())
Diag(FTI.getExceptionSpecLoc(), diag::err_exception_spec_in_typedef)
<< (D.getContext() == Declarator::AliasDeclContext);
<< (D.getContext() == Declarator::AliasDeclContext ||
D.getContext() == Declarator::AliasTemplateContext);
if (!FTI.NumArgs && !FTI.isVariadic && !getLangOptions().CPlusPlus) {
// Simple void foo(), where the incoming T is the result type.
@ -2204,6 +2207,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
case Declarator::ObjCPrototypeContext: // FIXME: special diagnostic here?
case Declarator::TypeNameContext:
case Declarator::AliasDeclContext:
case Declarator::AliasTemplateContext:
case Declarator::MemberContext:
case Declarator::BlockContext:
case Declarator::ForContext:
@ -2640,13 +2644,17 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
CheckExtraCXXDefaultArguments(D);
// C++0x [dcl.type]p3:
// A type-specifier-seq shall not define a class or enumeration
// unless it appears in the type-id of an alias-declaration
// (7.1.3).
if (OwnedTag && OwnedTag->isDefinition() &&
D.getContext() != Declarator::AliasDeclContext)
Diag(OwnedTag->getLocation(), diag::err_type_defined_in_type_specifier)
<< Context.getTypeDeclType(OwnedTag);
// A type-specifier-seq shall not define a class or enumeration unless
// it appears in the type-id of an alias-declaration (7.1.3) that is not
// the declaration of a template-declaration.
if (OwnedTag && OwnedTag->isDefinition()) {
if (D.getContext() == Declarator::AliasTemplateContext)
Diag(OwnedTag->getLocation(), diag::err_type_defined_in_alias_template)
<< Context.getTypeDeclType(OwnedTag);
else if (D.getContext() != Declarator::AliasDeclContext)
Diag(OwnedTag->getLocation(), diag::err_type_defined_in_type_specifier)
<< Context.getTypeDeclType(OwnedTag);
}
}
return CreateParsedType(T, TInfo);

Просмотреть файл

@ -21,6 +21,7 @@
#include "clang/Sema/ScopeInfo.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
@ -855,7 +856,7 @@ public:
case LookupResult::Found:
case LookupResult::FoundOverloaded:
case LookupResult::FoundUnresolvedValue: {
NamedDecl *SomeDecl = Result.getRepresentativeDecl();
NamedDecl *SomeDecl = Result.getRepresentativeDecl();
unsigned Kind = 0;
if (isa<TypedefDecl>(SomeDecl)) Kind = 1;
else if (isa<TypeAliasDecl>(SomeDecl)) Kind = 2;
@ -863,7 +864,7 @@ public:
SemaRef.Diag(IdLoc, diag::err_tag_reference_non_tag) << Kind;
SemaRef.Diag(SomeDecl->getLocation(), diag::note_declared_at);
break;
}
}
default:
// FIXME: Would be nice to highlight just the source range.
SemaRef.Diag(IdLoc, diag::err_not_tag_in_scope)
@ -4389,6 +4390,23 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
NewTemplateArgs);
if (!Result.isNull()) {
// Specializations of template template parameters are represented as
// TemplateSpecializationTypes, and substitution of type alias templates
// within a dependent context can transform them into
// DependentTemplateSpecializationTypes.
if (isa<DependentTemplateSpecializationType>(Result)) {
DependentTemplateSpecializationTypeLoc NewTL
= TLB.push<DependentTemplateSpecializationTypeLoc>(Result);
NewTL.setKeywordLoc(TL.getTemplateNameLoc());
NewTL.setQualifierLoc(NestedNameSpecifierLoc());
NewTL.setNameLoc(TL.getTemplateNameLoc());
NewTL.setLAngleLoc(TL.getLAngleLoc());
NewTL.setRAngleLoc(TL.getRAngleLoc());
for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i)
NewTL.setArgLocInfo(i, NewTemplateArgs[i].getLocInfo());
return Result;
}
TemplateSpecializationTypeLoc NewTL
= TLB.push<TemplateSpecializationTypeLoc>(Result);
NewTL.setTemplateNameLoc(TL.getTemplateNameLoc());
@ -4478,6 +4496,21 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
if (NamedT.isNull())
return QualType();
// C++0x [dcl.type.elab]p2:
// If the identifier resolves to a typedef-name or the simple-template-id
// resolves to an alias template specialization, the
// elaborated-type-specifier is ill-formed.
if (const TemplateSpecializationType *TST =
NamedT->getAs<TemplateSpecializationType>()) {
TemplateName Template = TST->getTemplateName();
if (TypeAliasTemplateDecl *TAT =
dyn_cast_or_null<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) {
SemaRef.Diag(TL.getNamedTypeLoc().getBeginLoc(),
diag::err_tag_reference_non_tag) << 4;
SemaRef.Diag(TAT->getLocation(), diag::note_declared_at);
}
}
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
QualifierLoc != TL.getQualifierLoc() ||

Просмотреть файл

@ -3366,14 +3366,14 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx);
llvm::SmallVector<TemplateArgument, 8> Args;
ReadTemplateArgumentList(Args, *Loc.F, Record, Idx);
QualType Canon = GetType(Record[Idx++]);
QualType Underlying = GetType(Record[Idx++]);
QualType T;
if (Canon.isNull())
if (Underlying.isNull())
T = Context->getCanonicalTemplateSpecializationType(Name, Args.data(),
Args.size());
else
T = Context->getTemplateSpecializationType(Name, Args.data(),
Args.size(), Canon);
Args.size(), Underlying);
const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent);
return T;
}

Просмотреть файл

@ -125,6 +125,7 @@ namespace clang {
void VisitClassTemplateDecl(ClassTemplateDecl *D);
void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
void VisitUsingDecl(UsingDecl *D);
void VisitUsingShadowDecl(UsingShadowDecl *D);
void VisitLinkageSpecDecl(LinkageSpecDecl *D);
@ -1266,6 +1267,10 @@ void ASTDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
D->ParameterPack = Record[Idx++];
}
void ASTDeclReader::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
VisitRedeclarableTemplateDecl(D);
}
void ASTDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) {
VisitDecl(D);
D->AssertExpr = Reader.ReadExpr(F);
@ -1572,6 +1577,9 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
D = TemplateTemplateParmDecl::Create(*Context, 0, SourceLocation(), 0, 0,
false, 0, 0);
break;
case DECL_TYPE_ALIAS_TEMPLATE:
D = TypeAliasTemplateDecl::Create(*Context, Decl::EmptyShell());
break;
case DECL_STATIC_ASSERT:
D = StaticAssertDecl::Create(*Context, 0, SourceLocation(), 0, 0,
SourceLocation());

Просмотреть файл

@ -277,7 +277,8 @@ ASTTypeWriter::VisitTemplateSpecializationType(
for (TemplateSpecializationType::iterator ArgI = T->begin(), ArgE = T->end();
ArgI != ArgE; ++ArgI)
Writer.AddTemplateArgument(*ArgI, Record);
Writer.AddTypeRef(T->isCanonicalUnqualified() ? QualType()
Writer.AddTypeRef(T->isTypeAlias() ? T->getAliasedType() :
T->isCanonicalUnqualified() ? QualType()
: T->getCanonicalTypeInternal(),
Record);
Code = TYPE_TEMPLATE_SPECIALIZATION;

Просмотреть файл

@ -86,6 +86,7 @@ namespace clang {
void VisitClassTemplateDecl(ClassTemplateDecl *D);
void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
void VisitUsingDecl(UsingDecl *D);
void VisitUsingShadowDecl(UsingShadowDecl *D);
void VisitLinkageSpecDecl(LinkageSpecDecl *D);
@ -1081,6 +1082,11 @@ void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM;
}
void ASTDeclWriter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
VisitRedeclarableTemplateDecl(D);
Code = serialization::DECL_TYPE_ALIAS_TEMPLATE;
}
void ASTDeclWriter::VisitStaticAssertDecl(StaticAssertDecl *D) {
VisitDecl(D);
Writer.AddStmt(D->getAssertExpr());

Просмотреть файл

@ -0,0 +1,13 @@
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
struct A { };
template<typename T> using X = A; // expected-note {{declared here}}
struct X<int>* p2; // expected-error {{elaborated type refers to a type alias template}}
template<typename T> using Id = T; // expected-note {{declared here}}
template<template<typename> class F>
struct Y {
struct F<int> i; // expected-error {{elaborated type refers to a type alias template}}
};
template struct Y<Id>; // expected-note {{requested here}}

Просмотреть файл

@ -1,10 +1,9 @@
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
// FIXME: when clang supports alias-declarations.
#if 0
using X = struct { // ok
};
#endif
template<typename T> using Y = struct { // expected-error {{can not be defined in a type alias template}}
};
class K {
virtual ~K();

Просмотреть файл

@ -0,0 +1,8 @@
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
template<typename T> using A = int;
template<typename T> using A<T*> = char; // expected-error {{partial specialization of alias templates is not permitted}}
template<> using A<char> = char; // expected-error {{explicit specialization of alias templates is not permitted}}
template using A<char> = char; // expected-error {{explicit instantiation of alias templates is not permitted}}
// Best guess as to what the user was trying to do: missing template<>.
using A<char> = char; // expected-error {{partial specialization of alias templates is not permitted}}

Просмотреть файл

@ -0,0 +1,8 @@
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
template<typename T> using U = T;
// The name of the alias template is a template-name.
U<char> x;
void f(U<int>);
typedef U<U<U<U<int>>>> I;

Просмотреть файл

@ -0,0 +1,45 @@
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
template<typename T> using U = T;
using I = U<U<U<U<int>>>>;
using I = int;
template<typename A, typename B> using Fst = A;
template<typename A, typename B> using Snd = B;
using I = Fst<Snd<char,int>,double>;
namespace StdExample {
// Prerequisites for example.
template<class T, class A> struct vector { /* ... */ };
template<class T> struct Alloc {};
template<class T> using Vec = vector<T, Alloc<T>>;
Vec<int> v;
template<class T>
void process(Vec<T>& v) // expected-note {{previous definition is here}}
{ /* ... */ }
template<class T>
void process(vector<T, Alloc<T>>& w) // expected-error {{redefinition of 'process'}}
{ /* ... */ }
template<template<class> class TT>
void f(TT<int>); // expected-note {{candidate template ignored}}
template<template<class,class> class TT>
void g(TT<int, Alloc<int>>);
int h() {
f(v); // expected-error {{no matching function for call to 'f'}}
g(v); // OK: TT = vector
}
// v's type is same as vector<int, Alloc<int>>.
using VTest = vector<int, Alloc<int>>;
using VTest = decltype(v);
}

Просмотреть файл

@ -0,0 +1,13 @@
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
// The example given in the standard (this is rejected for other reasons anyway).
template<class T> struct A;
template<class T> using B = typename A<T>::U; // expected-error {{no type named 'U' in 'A<T>'}}
template<class T> struct A {
typedef B<T> U; // expected-note {{in instantiation of template type alias 'B' requested here}}
};
B<short> b;
template<typename T> using U = int;
// FIXME: This is illegal, but probably only because CWG1044 missed this paragraph.
template<typename T> using U = U<T>;

Просмотреть файл

@ -0,0 +1,13 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
template<typename> struct Y1;
template<typename, int> struct Y2;
template<class T1, class T2 = int> using B2 = T1;
template<class T1 = int, class T2> using B2 = T1;
template<template<class> class F, template<class> class G = Y1> using B2t = F<G<int>>;
template<template<class> class F = Y2, template<class> class G> using B2t = F<G<int>>;
template<int N, int M = 5> using B2n = Y2<int, N + M>;
template<int N = 5, int M> using B2n = Y2<int, N + M>;

Просмотреть файл

@ -1,29 +1,48 @@
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
// If a template-parameter of a class template has a default
// template-argument, each subsequent template-parameter shall either
// have a default template-argument supplied or be a template
// parameter pack.
// If a template-parameter of a class template or alias template has a default
// template-argument, each subsequent template-parameter shall either have a
// default template-argument supplied or be a template parameter pack.
template<typename> struct vector;
template<typename T = int, typename> struct X3t; // expected-error{{template parameter missing a default argument}} expected-note{{previous default template argument defined here}}
template<typename T = int, typename> using A3t = int; // expected-error{{template parameter missing a default argument}} expected-note{{previous default template argument defined here}}
template<int V = 0, int> struct X3nt; // expected-error{{template parameter missing a default argument}} expected-note{{previous default template argument defined here}}
template<int V = 0, int> using A3nt = int; // expected-error{{template parameter missing a default argument}} expected-note{{previous default template argument defined here}}
template<template<class> class M = vector, template<class> class> struct X3tt; // expected-error{{template parameter missing a default argument}} expected-note{{previous default template argument defined here}}
template<template<class> class M = vector, template<class> class> using A3tt = int; // expected-error{{template parameter missing a default argument}} expected-note{{previous default template argument defined here}}
template<typename T = int, typename ...Types> struct X2t;
template<typename T = int, typename ...Types> using A2t = X2t<T, Types...>;
template<int V = 0, int ...Values> struct X2nt;
template<int V = 0, int ...Values> using A2nt = X2nt<V, Values...>;
template<template<class> class M = vector, template<class> class... Metas>
struct X2tt;
template<template<class> class M = vector, template<class> class... Metas>
using A2tt = X2tt<M, Metas...>;
// If a template-parameter of a primary class template is a template
// parameter pack, it shall be the last template-parameter .
// If a template-parameter of a primary class template or alias template is a
// template parameter pack, it shall be the last template-parameter.
template<typename ...Types, // expected-error{{template parameter pack must be the last template parameter}}
int After>
struct X0t;
template<typename ...Types, // expected-error{{template parameter pack must be the last template parameter}}
int After>
using A0t = int;
template<int ...Values, // expected-error{{template parameter pack must be the last template parameter}}
int After>
struct X0nt;
template<int ...Values, // expected-error{{template parameter pack must be the last template parameter}}
int After>
using A0nt = int;
template<template<typename> class ...Templates, // expected-error{{template parameter pack must be the last template parameter}}
int After>
struct X0tt;
template<template<typename> class ...Templates, // expected-error{{template parameter pack must be the last template parameter}}
int After>
using A0tt = int;
// [ Note: These are not requirements for function templates or class
// template partial specializations because template arguments can be

Просмотреть файл

@ -0,0 +1,30 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
// Examples from CWG1056.
namespace Example1 {
template<class T> struct A;
template<class T> using B = A<T>;
template<class T> struct A {
struct C {};
B<T>::C bc; // ok, B<T> is the current instantiation.
};
template<class T> struct A<A<T>> {
struct C {};
B<B<T>>::C bc; // ok, B<B<T>> is the current instantiation.
};
template<class T> struct A<A<A<T>>> {
struct C {};
B<B<T>>::C bc; // expected-error {{missing 'typename'}}
};
}
namespace Example2 {
template<class T> struct A {
void g();
};
template<class T> using B = A<T>;
template<class T> void B<T>::g() {} // ok.
}

Просмотреть файл

@ -0,0 +1,23 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
namespace Old {
template<template<class> class TT> struct X { };
template<class> struct Y { };
template<class T> using Z = Y<T>;
X<Y> y;
X<Z> z;
using SameType = decltype(y); // expected-note {{here}}
using SameType = decltype(z); // expected-error {{different types}}
}
namespace New {
template<class T> struct X { };
template<class> struct Y { };
template<class T> using Z = Y<T>;
X<Y<int>> y;
X<Z<int>> z;
using SameType = decltype(y);
using SameType = decltype(z); // ok
}

Просмотреть файл

@ -0,0 +1,41 @@
// RUN: %clang_cc1 -std=c++0x -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
template<typename T> struct alloc {};
template<typename T> using Alloc = alloc<T>;
template<typename T, typename A = Alloc<T>> struct vector {};
template<typename T> using Vec = vector<T>;
template<typename T> void f(Vec<T> v);
template<typename T> void g(T);
template<template<typename> class F> void h(F<int>);
// CHECK: define void @_Z1zv(
void z() {
vector<int> VI;
f(VI);
// CHECK: call void @_Z1fIiEv6vectorIT_5allocIS1_EE(
Vec<double> VD;
g(VD);
// CHECK: call void @_Z1gI6vectorId5allocIdEEEvT_(
h<Vec>(VI);
// CHECK: call void @_Z1hI3VecEvT_IiE(
Alloc<int> AC;
h(AC);
// CHECK: call void @_Z1hI5allocEvT_IiE(
h<Alloc>(AC);
// CHECK: call void @_Z1hI5AllocEvT_IiE(
Vec<char> VC;
g<Vec<char>>(VC);
// CHECK: call void @_Z1gI6vectorIc5allocIcEEEvT_(
Vec<Vec<int>> VVI;
g(VVI);
// CHECK: call void @_Z1gI6vectorIS0_Ii5allocIiEES1_IS3_EEEvT_(
}

Просмотреть файл

@ -0,0 +1,14 @@
// RUN: %clang_cc1 -std=c++0x -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
template<typename T> using id = T;
struct S {
template<typename T, int N>
operator id<T[N]>&();
template<typename T, typename U>
operator id<T (U::*)()>() const;
};
void f() {
int (&a)[42] = S(); // CHECK: @_ZN1ScvRAT0__T_IiLi42EEEv(
char (S::*fp)() = S(); // CHECK: @_ZNK1ScvMT0_FT_vEIcS_EEv(
};

Просмотреть файл

@ -155,3 +155,12 @@ int no_override_control();
// CHECK-0X: has_override_control
// CHECK-NO-0X: no_override_control
#if __has_feature(cxx_alias_templates)
int has_alias_templates();
#else
int no_alias_templates();
#endif
// CHECK-0X: has_alias_templates
// CHECK-NO-0X: no_alias_templates

Просмотреть файл

@ -0,0 +1,20 @@
// Test this without pch.
// RUN: %clang_cc1 -x c++ -std=c++0x -include %S/cxx-alias-decl.h -fsyntax-only -emit-llvm -o - %s
// Test with pch.
// RUN: %clang_cc1 -x c++ -std=c++0x -emit-pch -o %t %S/cxx-alias-decl.h
// RUN: %clang_cc1 -x c++ -std=c++0x -include-pch %t -fsyntax-only -emit-llvm -o - %s
template struct T<S>;
C<A>::A<char> a;
using T1 = decltype(a);
using T1 = D<int, char>;
using T2 = B<A>;
using T2 = S;
using A = int;
template<typename U> using B = S;
template<typename U> using C = T<U>;
template<typename U, typename V> using D = typename T<U>::template A<V>;

11
test/PCH/cxx-alias-decl.h Normal file
Просмотреть файл

@ -0,0 +1,11 @@
// Header for PCH test cxx-alias-decl.cpp
struct S {};
template<typename U> struct T {
template<typename V> using A = T<V>;
};
using A = int;
template<typename U> using B = S;
template<typename U> using C = T<U>;
template<typename U, typename V> using D = typename T<U>::template A<V>;

Просмотреть файл

@ -0,0 +1,147 @@
// RUN: %clang_cc1 -verify -std=c++0x %s
namespace RedeclAliasTypedef {
template<typename U> using T = int;
template<typename U> using T = int;
template<typename U> using T = T<U>;
}
namespace IllegalTypeIds {
template<typename U> using A = void(int n = 0); // expected-error {{default arguments can only be specified for parameters in a function declaration}}
template<typename U> using B = inline void(int n); // expected-error {{type name does not allow function specifier}}
template<typename U> using C = virtual void(int n); // expected-error {{type name does not allow function specifier}}
template<typename U> using D = explicit void(int n); // expected-error {{type name does not allow function specifier}}
template<typename U> using E = void(int n) throw(); // expected-error {{exception specifications are not allowed in type aliases}}
// FIXME: this is illegal; we incorrectly accept it for typedefs too.
template<typename U> using F = void(*)(int n) &&; // expected-err
template<typename U> using G = __thread void(int n); // expected-error {{type name does not allow storage class to be specified}}
template<typename U> using H = void(int n); // ok
template<typename U> using I = void(int n) &&; // ok
}
namespace IllegalSyntax {
template<typename Z> using ::T = void(int n); // expected-error {{name defined in alias declaration must be an identifier}}
template<typename Z> using operator int = void(int n); // expected-error {{name defined in alias declaration must be an identifier}}
template<typename Z> using typename U = void; // expected-error {{name defined in alias declaration must be an identifier}}
template<typename Z> using typename ::V = void(int n); // expected-error {{name defined in alias declaration must be an identifier}}
template<typename Z> using typename ::operator bool = void(int n); // expected-error {{name defined in alias declaration must be an identifier}}
}
namespace VariableLengthArrays {
template<typename Z> using T = int[42]; // ok
int n = 32;
template<typename Z> using T = int[n]; // expected-error {{variable length array declaration not allowed at file scope}}
const int m = 42;
template<typename Z> using U = int[m]; // expected-note {{previous definition}}
template<typename Z> using U = int[42]; // ok
template<typename Z> using U = int; // expected-error {{type alias template redefinition with different types ('int' vs 'int [42]')}}
}
namespace RedeclFunc {
int f(int, char**);
template<typename Z> using T = int;
T<char> f(int, char **); // ok
}
namespace LookupFilter {
namespace N { template<typename U> using S = int; }
using namespace N;
template<typename U> using S = S<U>*; // ok
}
namespace InFunctions {
template<typename...T> struct S0 {
template<typename Z> using U = T*; // expected-error {{declaration type contains unexpanded parameter pack 'T'}}
U<char> u;
};
template<typename Z> using T1 = int;
template<typename Z> using T2 = int[-1]; // expected-error {{array size is negative}}
template<typename...T> struct S3 { // expected-note {{template parameter is declared here}}
template<typename Z> using T = int; // expected-error {{declaration of 'T' shadows template parameter}}
};
template<typename Z> using Z = Z;
}
namespace ClassNameRedecl {
class C0 {
// FIXME: this diagnostic is pretty poor
template<typename U> using C0 = int; // expected-error {{name defined in alias declaration must be an identifier}}
};
class C1 {
// FIXME: this diagnostic is pretty poor
template<typename U> using C1 = C1; // expected-error {{name defined in alias declaration must be an identifier}}
};
class C2 {
template<typename U> using C0 = C1; // ok
};
template<typename...T> class C3 {
template<typename U> using f = T; // expected-error {{declaration type contains unexpanded parameter pack 'T'}}
};
template<typename T> class C4 { // expected-note {{template parameter is declared here}}
template<typename U> using T = int; // expected-error {{declaration of 'T' shadows template parameter}}
};
class C5 {
class c; // expected-note {{previous definition}}
template<typename U> using c = int; // expected-error {{redefinition of 'c' as different kind of symbol}}
class d; // expected-note {{previous definition}}
template<typename U> using d = d; // expected-error {{redefinition of 'd' as different kind of symbol}}
};
class C6 {
class c { template<typename U> using C6 = int; }; // ok
};
}
class CtorDtorName {
template<typename T> using X = CtorDtorName;
X<int>(); // expected-error {{expected member name}}
~X<int>(); // expected-error {{destructor cannot be declared using a type alias}}
};
namespace TagName {
template<typename Z> using S = struct { int n; }; // expected-error {{can not be defined}}
template<typename Z> using T = class { int n; }; // expected-error {{can not be defined}}
template<typename Z> using U = enum { a, b, c }; // expected-error {{can not be defined}}
template<typename Z> using V = struct V { int n; }; // expected-error {{redefinition of 'V' as different kind of symbol}} \
expected-error {{'TagName::V' can not be defined in a type alias template}} \
expected-note {{previous definition is here}}
}
namespace StdExample {
template<typename T, typename U> struct pair;
template<typename T> using handler_t = void (*)(T);
extern handler_t<int> ignore;
extern void (*ignore)(int);
// FIXME: we recover as if cell is an undeclared variable. the diagnostics are terrible!
template<typename T> using cell = pair<T*, cell<T>*>; // expected-error {{use of undeclared identifier 'cell'}} \
expected-error {{'T' does not refer to a value}} \
expected-note {{declared here}} \
expected-error {{expected ';' after alias declaration}}
}
namespace Access {
class C0 {
template<typename Z> using U = int; // expected-note {{declared private here}}
};
C0::U<int> v; // expected-error {{'U' is a private member}}
class C1 {
public:
template<typename Z> using U = int;
};
C1::U<int> w; // ok
}
namespace VoidArg {
template<typename Z> using V = void;
V<int> f(int); // ok
V<char> g(V<double>); // expected-error {{empty parameter list defined with a type alias of 'void' not allowed}}
}
namespace Curried {
template<typename T, typename U> struct S;
template<typename T> template<typename U> using SS = S<T, U>; // expected-error {{extraneous template parameter list in alias template declaration}}
}

Просмотреть файл

@ -9,8 +9,13 @@ struct align_member {
int member [[align(8)]];
};
typedef char align_typedef [[align(8)]];
template<typename T> using align_alias_template = align_typedef;
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(align_member) == 8, "quuux's alignment 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_alias_template<int>) == 8, "alias template's alignment is wrong");

Просмотреть файл

@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s
// RUN: %clang_cc1 -fsyntax-only -pedantic -verify -std=c++0x %s
template<typename T> using U = int &;
template<typename T, int Size> void f() {
T x1;
@ -7,4 +9,5 @@ template<typename T, int Size> void f() {
T x4[]; // expected-error{{needs an explicit size or an initializer}}
T x5[Size];
int x6[Size];
U<T> x7; // expected-error{{declaration of reference variable 'x7' requires an initializer}}
}

Просмотреть файл

@ -0,0 +1,23 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
template<typename T> using A = int; // expected-note 2{{previous}}
template<typename T> using A = char; // expected-error {{type alias template redefinition with different types ('char' vs 'int')}}
template<typename T1, typename T2> using A = T1; // expected-error {{too many template parameters in template redeclaration}}
template<typename T1, typename T2> using B = T1; // expected-note {{previous}}
template<typename T2, typename T1> using B = T1; // expected-error {{type alias template redefinition with different types}}
template<typename> struct S;
template<template<typename> class F> using FInt = F<int>;
template<typename X> using SXRInt = FInt<S<X>::template R>;
template<typename X> using SXRInt = typename S<X>::template R<int>; // ok, redeclaration.
template<template<typename> class> struct TT;
namespace FilterLookup {
TT<A> f(); // expected-note {{previous declaration is here}}
template<typename> using A = int;
TT<A> f(); // expected-error {{functions that differ only in their return type cannot be overloaded}}
}

Просмотреть файл

@ -0,0 +1,34 @@
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
template<template<template<typename> class, typename> class T, template<typename> class V> struct PartialApply {
template<typename W> using R = T<V, W>;
};
template<typename T> using Id = T;
template<template<typename> class, typename X> using Zero = X;
template<template<template<typename> class, typename> class N, template<typename> class F, typename X> using Succ = F<N<F,X>>;
template<template<typename> class F, typename X> using One = Succ<Zero, F, X>;
template<template<typename> class F, typename X> using Two = Succ<One, F, X>;
template<template<template<typename> class, typename> class A,
template<template<typename> class, typename> class B,
template<typename> class F,
typename X> using Add = A<F, B<F, X>>;
template<template<template<typename> class, typename> class A,
template<template<typename> class, typename> class B,
template<typename> class F,
typename X> using Mul = A<PartialApply<B,F>::template R, X>;
template<template<typename> class F, typename X> using Four = Add<Two, Two, F, X>;
template<template<typename> class F, typename X> using Sixteen = Mul<Four, Four, F, X>;
template<template<typename> class F, typename X> using TwoHundredAndFiftySix = Mul<Sixteen, Sixteen, F, X>;
template<typename T, T N> struct Const { static const T value = N; };
template<typename A> struct IncrementHelper;
template<typename T, T N> struct IncrementHelper<Const<T, N>> { using Result = Const<T, N+1>; };
template<typename A> using Increment = typename IncrementHelper<A>::Result;
using Arr = int[TwoHundredAndFiftySix<Increment, Const<int, 0>>::value];
using Arr = int[256];

Просмотреть файл

@ -0,0 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
template<typename T> using Id = T; // expected-note {{type alias template 'Id' declared here}}
struct U { static Id<int> V; };
Id<int> ::U::V; // expected-error {{type 'Id<int>' (aka 'int') cannot be used prior to '::' because it has no members}} \
expected-error {{C++ requires a type specifier}}

Просмотреть файл

@ -0,0 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
template<template<typename> class D> using C = D<int>;
// Substitution of the alias template transforms the TemplateSpecializationType
// 'D<int>' into the DependentTemplateSpecializationType 'T::template U<int>'.
template<typename T> void f(C<T::template U>);

Просмотреть файл

@ -3915,6 +3915,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::Namespace:
case Decl::Typedef:
case Decl::TypeAlias:
case Decl::TypeAliasTemplate:
case Decl::TemplateTypeParm:
case Decl::EnumConstant:
case Decl::Field:

Просмотреть файл

@ -460,14 +460,13 @@ welcome!</p>
</tr>
<tr>
<td>template aliases</td>
<td class="basic"></td>
<td class="basic"></td>
<td class="basic"></td>
<td></td>
<td class="complete" align="center">&#x2713;</td>
<td class="complete" align="center">&#x2713;</td>
<td class="complete" align="center">&#x2713;</td>
<td class="complete" align="center">&#x2713;</td>
<td>7.1.3, 14.6.7</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1489.pdf">N1489</a>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf">N2258</a>
Only non-template type aliases implemented
</td>
</tr>
<tr>