diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2011-05-05 21:57:07 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2011-05-05 21:57:07 +0000 |
commit | 3e4c6c4c79a03f5cb0c4671d7c282d623c6dc35e (patch) | |
tree | b08336e8100cbc8e287931126f179dd37225a94f /lib/Sema/SemaDeclCXX.cpp | |
parent | 78a7d7d79964119a3f35b262eb154b5cbf1001ed (diff) |
Implement support for C++0x alias templates.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130953 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaDeclCXX.cpp')
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 100 |
1 files changed, 96 insertions, 4 deletions
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, |