diff options
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaAccess.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaCXXScopeSpec.cpp | 21 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 41 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 100 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 84 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 12 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 55 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 26 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 37 |
9 files changed, 313 insertions, 67 deletions
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index 411d424dd8..63983c3daf 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -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 diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 5ee256ab21..ff3890023e 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -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. diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 6231fbd111..7845247a24 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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; } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 2ef15b672d..6dad78442d 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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, diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 7a4e54de0f..09431650f2 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -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(); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 92ba095cd6..3e1e735c85 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -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 diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 6fa208f6f8..2c0c7ae90f 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -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 diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 00ac1d63db..06548a44dd 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -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); diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 4bb1841716..da60fccf7e 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -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() || |