[PATCH] D65022: [Sema] Always instantiate the initializer of a variable template with undeduced type (8.0 regression)
erik.pilkington added a comment. Hmm, looks like this patch fails to fix the case where we're referencing the variable in an non-odr use context, since we don't even bother to instantiate the initializer here: template struct S { template static constexpr auto x = 43; }; int main() { sizeof(S::x); } I think we should instantiate the initializer before forming a referencing expression and marking it used. @rsmith: do you mind if I just land https://reviews.llvm.org/D65022?id=210905 and file a bug to fix the regression we're seeing here? CHANGES SINCE LAST ACTION https://reviews.llvm.org/D65022/new/ https://reviews.llvm.org/D65022 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D65022: [Sema] Always instantiate the initializer of a variable template with undeduced type (8.0 regression)
erik.pilkington updated this revision to Diff 212470. erik.pilkington added a comment. Rebase on top of r367367. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D65022/new/ https://reviews.llvm.org/D65022 Files: clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/SemaExprMember.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 @@ -424,3 +424,34 @@ } } #endif + +#ifndef PRECXX11 +namespace auto_variable_instantiate_initializer { +template struct S { + template static constexpr auto v = 1; + template static constexpr auto v2 = T{}; + + template > + void implicit() { +double d = v2; +int i2 = v; + } + + void implicit_nondep() { +int i = v; +double d = v2; + } +}; + +void useit() { + S x; + // We used to fail to instantiate the initializer, leading to an auto type + // leaking through here. + int i = x.v; + float j = x.v2; + + x.implicit(); + x.implicit_nondep(); +} +} + #endif Index: clang/lib/Sema/SemaExprMember.cpp === --- clang/lib/Sema/SemaExprMember.cpp +++ clang/lib/Sema/SemaExprMember.cpp @@ -1160,11 +1160,17 @@ } if (VarTemplateDecl *VarTempl = dyn_cast(MemberDecl)) { if (VarDecl *Var = getVarTemplateSpecialization( -VarTempl, TemplateArgs, MemberNameInfo, TemplateKWLoc)) - return BuildMemberExpr( +VarTempl, TemplateArgs, MemberNameInfo, TemplateKWLoc)) { + MemberExpr *ME = BuildMemberExpr( BaseExpr, IsArrow, OpLoc, , TemplateKWLoc, Var, FoundDecl, /*HadMultipleCandidates=*/false, MemberNameInfo, Var->getType().getNonReferenceType(), VK_LValue, OK_Ordinary); + + // BuildMemberExpr may have deduced an auto variable's type. Patch back + // that type to avoid forming an expression with undeduced type. + ME->setType(Var->getType().getNonReferenceType()); + return ME; +} return ExprError(); } Index: clang/lib/Sema/SemaExpr.cpp === --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -3163,9 +3163,15 @@ break; } -return BuildDeclRefExpr(VD, type, valueKind, NameInfo, , FoundD, -/*FIXME: TemplateKWLoc*/ SourceLocation(), -TemplateArgs); +DeclRefExpr *DRE = BuildDeclRefExpr( +VD, type, valueKind, NameInfo, , FoundD, +/*FIXME: TemplateKWLoc*/ SourceLocation(), TemplateArgs); + +// BuildDeclRefExpr may have deduced an auto variable's type. Patch back +// that type to avoid forming an expression with undeduced type. +if (isa(VD)) + DRE->setType(VD->getType().getNonReferenceType()); +return DRE; } } 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 @@ -424,3 +424,34 @@ } } #endif + +#ifndef PRECXX11 +namespace auto_variable_instantiate_initializer { +template struct S { + template static constexpr auto v = 1; + template static constexpr auto v2 = T{}; + + template > + void implicit() { +double d = v2; +int i2 = v; + } + + void implicit_nondep() { +int i = v; +double d = v2; + } +}; + +void useit() { + S x; + // We used to fail to instantiate the initializer, leading to an auto type + // leaking through here. + int i = x.v; + float j = x.v2; + + x.implicit(); + x.implicit_nondep(); +} +} + #endif Index: clang/lib/Sema/SemaExprMember.cpp === --- clang/lib/Sema/SemaExprMember.cpp +++ clang/lib/Sema/SemaExprMember.cpp @@ -1160,11 +1160,17 @@ } if (VarTemplateDecl *VarTempl = dyn_cast(MemberDecl)) { if (VarDecl *Var = getVarTemplateSpecialization( -VarTempl, TemplateArgs, MemberNameInfo, TemplateKWLoc)) - return BuildMemberExpr( +VarTempl, TemplateArgs, MemberNameInfo, TemplateKWLoc)) { + MemberExpr *ME = BuildMemberExpr( BaseExpr, IsArrow, OpLoc, , TemplateKWLoc, Var, FoundDecl, /*HadMultipleCandidates=*/false, MemberNameInfo, Var->getType().getNonReferenceType(), VK_LValue, OK_Ordinary); + + // BuildMemberExpr may have deduced an auto variable's type. Patch back + // that type to avoid forming an expression with undeduced type. + ME->setType(Var->getType().getNonReferenceType()); + return ME; +} return ExprError(); } Index: clang/lib/Sema/SemaExpr.cpp === ---
[PATCH] D65022: [Sema] Always instantiate the initializer of a variable template with undeduced type (8.0 regression)
erik.pilkington updated this revision to Diff 212026. erik.pilkington added a comment. Fix the type of the MemberExpr/DeclRefExpr after instantiating the variable initializer. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D65022/new/ https://reviews.llvm.org/D65022 Files: clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/SemaExprMember.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,34 @@ } int = B::template n; // expected-error {{use of variable template 'n' requires template arguments}} } + +#ifndef PRECXX11 +namespace auto_variable_instantiate_initializer { +template struct S { + template static constexpr auto v = 1; + template static constexpr auto v2 = T{}; + + template > + void implicit() { +double d = v2; +int i2 = v; + } + + void implicit_nondep() { +int i = v; +double d = v2; + } +}; + +void useit() { + S x; + // We used to fail to instantiate the initializer, leading to an auto type + // leaking through here. + int i = x.v; + float j = x.v2; + + x.implicit(); + x.implicit_nondep(); +} +} +#endif Index: clang/lib/Sema/SemaExprMember.cpp === --- clang/lib/Sema/SemaExprMember.cpp +++ clang/lib/Sema/SemaExprMember.cpp @@ -1160,11 +1160,17 @@ } if (VarTemplateDecl *VarTempl = dyn_cast(MemberDecl)) { if (VarDecl *Var = getVarTemplateSpecialization( -*this, VarTempl, TemplateArgs, MemberNameInfo, TemplateKWLoc)) - return BuildMemberExpr( +*this, VarTempl, TemplateArgs, MemberNameInfo, TemplateKWLoc)) { + MemberExpr *ME = BuildMemberExpr( BaseExpr, IsArrow, OpLoc, , TemplateKWLoc, Var, FoundDecl, /*HadMultipleCandidates=*/false, MemberNameInfo, Var->getType().getNonReferenceType(), VK_LValue, OK_Ordinary); + + // BuildMemberExpr may have deduced an auto variable's type. Patch back + // that type to avoid forming an expression with undeduced type. + ME->setType(Var->getType().getNonReferenceType()); + return ME; +} return ExprError(); } Index: clang/lib/Sema/SemaExpr.cpp === --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -3163,9 +3163,15 @@ break; } -return BuildDeclRefExpr(VD, type, valueKind, NameInfo, , FoundD, -/*FIXME: TemplateKWLoc*/ SourceLocation(), -TemplateArgs); +DeclRefExpr *DRE = BuildDeclRefExpr( +VD, type, valueKind, NameInfo, , FoundD, +/*FIXME: TemplateKWLoc*/ SourceLocation(), TemplateArgs); + +// BuildDeclRefExpr may have deduced an auto variable's type. Patch back +// that type to avoid forming an expression with undeduced type. +if (isa(VD)) + DRE->setType(VD->getType().getNonReferenceType()); +return DRE; } } 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,34 @@ } int = B::template n; // expected-error {{use of variable template 'n' requires template arguments}} } + +#ifndef PRECXX11 +namespace auto_variable_instantiate_initializer { +template struct S { + template static constexpr auto v = 1; + template static constexpr auto v2 = T{}; + + template > + void implicit() { +double d = v2; +int i2 = v; + } + + void implicit_nondep() { +int i = v; +double d = v2; + } +}; + +void useit() { + S x; + // We used to fail to instantiate the initializer, leading to an auto type + // leaking through here. + int i = x.v; + float j = x.v2; + + x.implicit(); + x.implicit_nondep(); +} +} +#endif Index: clang/lib/Sema/SemaExprMember.cpp === --- clang/lib/Sema/SemaExprMember.cpp +++ clang/lib/Sema/SemaExprMember.cpp @@ -1160,11 +1160,17 @@ } if (VarTemplateDecl *VarTempl = dyn_cast(MemberDecl)) { if (VarDecl *Var = getVarTemplateSpecialization( -*this, VarTempl, TemplateArgs, MemberNameInfo, TemplateKWLoc)) - return BuildMemberExpr( +*this, VarTempl, TemplateArgs, MemberNameInfo, TemplateKWLoc)) { + MemberExpr *ME = BuildMemberExpr( BaseExpr, IsArrow, OpLoc, , TemplateKWLoc, Var, FoundDecl, /*HadMultipleCandidates=*/false, MemberNameInfo, Var->getType().getNonReferenceType(), VK_LValue, OK_Ordinary); + + // BuildMemberExpr may have deduced an auto variable's type. Patch back + // that
[PATCH] D65022: [Sema] Always instantiate the initializer of a variable template with undeduced type (8.0 regression)
rsmith added a comment. Well, this restores an incorrect behaviour: we're not permitted to substitute into the initializer of the variable template here. Can you look into fixing this properly, by instantiating the type when forming the MemberExpr? If not, taking this to fix the regression seems OK, but please file a bug for the introduced misbehaviour. Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D65022/new/ https://reviews.llvm.org/D65022 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D65022: [Sema] Always instantiate the initializer of a variable template with undeduced type (8.0 regression)
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 struct Outer { template static constexpr auto x = 1; }; int main() { Outer x; int i = x.x; } We'd defer the instantiation of the initializer of the variable template when instantiating Outer (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::x` 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 = B::template n; // expected-error {{use of variable template 'n' requires template arguments}} } + +#ifndef PRECXX11 +namespace auto_variable_instantiate_initializer { +template struct S { + template static constexpr auto v = 1; + template static constexpr auto v2 = T{}; +}; + +void useit() { + S x; + // We used to fail to instantiate the initializer, leading to an auto type + // leaking through here. + int i = x.v; + float j = x.v2; +} +} +#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 = B::template n; // expected-error {{use of variable template 'n' requires template arguments}} } + +#ifndef PRECXX11 +namespace auto_variable_instantiate_initializer { +template struct S { + template static constexpr auto v = 1; + template static constexpr auto v2 = T{}; +}; + +void useit() { + S x; + // We used to fail to instantiate the initializer, leading to an auto type + // leaking through here. + int i = x.v; + float j = x.v2; +} +} +#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