aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaDeclCXX.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2011-05-05 21:57:07 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2011-05-05 21:57:07 +0000
commit3e4c6c4c79a03f5cb0c4671d7c282d623c6dc35e (patch)
treeb08336e8100cbc8e287931126f179dd37225a94f /lib/Sema/SemaDeclCXX.cpp
parent78a7d7d79964119a3f35b262eb154b5cbf1001ed (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.cpp100
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,