erik.pilkington created this revision. erik.pilkington added reviewers: rsmith, rjmccall. Herald added subscribers: dexonsmith, jkorous. Herald added a project: clang.
This patch fixes a regression introduced in r359947. Here: template <class T2> struct Outer { template <class T1> static constexpr auto x = 1; }; int main() { Outer<int> x; int i = x.x<int>; } We'd defer the instantiation of the initializer of the variable template when instantiating Outer<int> (leaving the variable template with an undeduced type). We do eventually instantiate the initializer and deduce the type of the variable when we're marking `Outer<int>::x<int>` referenced, but not before forming a MemberExpr that refers to the undeduced type. I think we could avoid instantiating the initializer of the variable template here, but that doesn't appear to be the intent of r359947, so this patch just falls back to the 8.0 behaviour. Fixes rdar://52619644 Thanks for taking a look! Erik Repository: rC Clang https://reviews.llvm.org/D65022 Files: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp Index: clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp =================================================================== --- clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp +++ clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp @@ -395,3 +395,20 @@ } int &t = B::template n; // expected-error {{use of variable template 'n' requires template arguments}} } + +#ifndef PRECXX11 +namespace auto_variable_instantiate_initializer { +template <class T2> struct S { + template <class T> static constexpr auto v = 1; + template <class T> static constexpr auto v2 = T{}; +}; + +void useit() { + S<int> x; + // We used to fail to instantiate the initializer, leading to an auto type + // leaking through here. + int i = x.v<float>; + float j = x.v2<float>; +} +} +#endif Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4506,11 +4506,11 @@ Context.setStaticLocalNumber(NewVar, Context.getStaticLocalNumber(OldVar)); // Figure out whether to eagerly instantiate the initializer. - if (InstantiatingVarTemplate || InstantiatingVarTemplatePartialSpec) { - // We're producing a template. Don't instantiate the initializer yet. - } else if (NewVar->getType()->isUndeducedType()) { + if (NewVar->getType()->isUndeducedType()) { // We need the type to complete the declaration of the variable. InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs); + } else if (InstantiatingVarTemplate || InstantiatingVarTemplatePartialSpec) { + // We're producing a template. Don't instantiate the initializer yet. } else if (InstantiatingSpecFromTemplate || (OldVar->isInline() && OldVar->isThisDeclarationADefinition() && !NewVar->isThisDeclarationADefinition())) {
Index: clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp =================================================================== --- clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp +++ clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp @@ -395,3 +395,20 @@ } int &t = B::template n; // expected-error {{use of variable template 'n' requires template arguments}} } + +#ifndef PRECXX11 +namespace auto_variable_instantiate_initializer { +template <class T2> struct S { + template <class T> static constexpr auto v = 1; + template <class T> static constexpr auto v2 = T{}; +}; + +void useit() { + S<int> x; + // We used to fail to instantiate the initializer, leading to an auto type + // leaking through here. + int i = x.v<float>; + float j = x.v2<float>; +} +} +#endif Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4506,11 +4506,11 @@ Context.setStaticLocalNumber(NewVar, Context.getStaticLocalNumber(OldVar)); // Figure out whether to eagerly instantiate the initializer. - if (InstantiatingVarTemplate || InstantiatingVarTemplatePartialSpec) { - // We're producing a template. Don't instantiate the initializer yet. - } else if (NewVar->getType()->isUndeducedType()) { + if (NewVar->getType()->isUndeducedType()) { // We need the type to complete the declaration of the variable. InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs); + } else if (InstantiatingVarTemplate || InstantiatingVarTemplatePartialSpec) { + // We're producing a template. Don't instantiate the initializer yet. } else if (InstantiatingSpecFromTemplate || (OldVar->isInline() && OldVar->isThisDeclarationADefinition() && !NewVar->isThisDeclarationADefinition())) {
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits