diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-10-17 20:37:29 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-10-17 20:37:29 +0000 |
commit | bd2dc746109fdcf4d2885f89872892adb0925cd5 (patch) | |
tree | 57929b3af79636b783879820bebd99fc7b972149 /lib/Sema/SemaTemplateInstantiateDecl.cpp | |
parent | 355e8c8de83ab6633bfd42f44e16f8a6209b46f1 (diff) |
Don't forget to substitute into the qualifier when instantiating the definition
of a member function of a class template that is defined outside the template.
This substitution can actually fail in some weird cases.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@220085 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaTemplateInstantiateDecl.cpp')
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 48 |
1 files changed, 29 insertions, 19 deletions
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index ec8c08ddf5..a89bf28813 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -36,14 +36,24 @@ static bool isDeclWithinFunction(const Decl *D) { return false; } -bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl, - DeclaratorDecl *NewDecl) { +template<typename DeclT> +static bool SubstQualifier(Sema &SemaRef, const DeclT *OldDecl, DeclT *NewDecl, + const MultiLevelTemplateArgumentList &TemplateArgs) { if (!OldDecl->getQualifierLoc()) return false; + assert((NewDecl->getFriendObjectKind() || + !OldDecl->getLexicalDeclContext()->isDependentContext()) && + "non-friend with qualified name defined in dependent context"); + Sema::ContextRAII SavedContext( + SemaRef, + const_cast<DeclContext *>(NewDecl->getFriendObjectKind() + ? NewDecl->getLexicalDeclContext() + : OldDecl->getLexicalDeclContext())); + NestedNameSpecifierLoc NewQualifierLoc - = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(), - TemplateArgs); + = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(), + TemplateArgs); if (!NewQualifierLoc) return true; @@ -52,20 +62,14 @@ bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl, return false; } +bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl, + DeclaratorDecl *NewDecl) { + return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs); +} + bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl, TagDecl *NewDecl) { - if (!OldDecl->getQualifierLoc()) - return false; - - NestedNameSpecifierLoc NewQualifierLoc - = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(), - TemplateArgs); - - if (!NewQualifierLoc) - return true; - - NewDecl->setQualifierInfo(NewQualifierLoc); - return false; + return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs); } // Include attribute instantiation code. @@ -3497,15 +3501,21 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (PatternDecl->isDefaulted()) SetDeclDefaulted(Function, PatternDecl->getLocation()); else { + MultiLevelTemplateArgumentList TemplateArgs = + getTemplateInstantiationArgs(Function, nullptr, false, PatternDecl); + + // Substitute into the qualifier; we can get a substitution failure here + // through evil use of alias templates. + // FIXME: Is CurContext correct for this? Should we go to the (instantiation + // of the) lexical context of the pattern? + SubstQualifier(*this, PatternDecl, Function, TemplateArgs); + ActOnStartOfFunctionDef(nullptr, Function); // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. Sema::ContextRAII savedContext(*this, Function); - MultiLevelTemplateArgumentList TemplateArgs = - getTemplateInstantiationArgs(Function, nullptr, false, PatternDecl); - addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope, TemplateArgs); |