r220085 - Don't forget to substitute into the qualifier when instantiating the definition
Richard Smith
richard-llvm at metafoo.co.uk
Fri Oct 17 13:37:29 PDT 2014
Author: rsmith
Date: Fri Oct 17 15:37:29 2014
New Revision: 220085
URL: http://llvm.org/viewvc/llvm-project?rev=220085&view=rev
Log:
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.
Added:
cfe/trunk/test/SemaTemplate/instantiate-scope.cpp
Modified:
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=220085&r1=220084&r2=220085&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Fri Oct 17 15:37:29 2014
@@ -36,14 +36,24 @@ static bool isDeclWithinFunction(const 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::SubstQual
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
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);
Added: cfe/trunk/test/SemaTemplate/instantiate-scope.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-scope.cpp?rev=220085&view=auto
==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-scope.cpp (added)
+++ cfe/trunk/test/SemaTemplate/instantiate-scope.cpp Fri Oct 17 15:37:29 2014
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+template<typename ...T> struct X {
+ void f(int);
+ void f(...);
+ static int n;
+};
+
+template<typename T, typename U> using A = T;
+
+// These definitions are OK, X<A<T, decltype(...)>...> is equivalent to X<T...>
+// so this defines the member of the primary template.
+template<typename ...T>
+void X<A<T, decltype(f(T()))>...>::f(int) {} // expected-error {{undeclared}}
+
+template<typename ...T>
+int X<A<T, decltype(f(T()))>...>::n = 0; // expected-error {{undeclared}}
+
+struct Y {}; void f(Y);
+
+void g() {
+ // OK, substitution succeeds.
+ X<Y>().f(0);
+ X<Y>::n = 1;
+
+ // Error, substitution fails; this should not be treated as a SFINAE-able
+ // condition, so we don't select X<void>::f(...).
+ X<void>().f(0); // expected-note {{instantiation of}}
+ X<void>::n = 1; // expected-note {{instantiation of}}
+}
More information about the cfe-commits
mailing list