From: Faisal Vali Date: Mon, 22 Feb 2016 02:24:29 +0000 (+0000) Subject: Fix PR24473 : Teach clang to remember to substitute into member variable templates... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fa10bdb3583fb71c702b6f6c66378746319dd24f;p=clang Fix PR24473 : Teach clang to remember to substitute into member variable templates referred to within dependent qualified ids. In passing also fix a semi-related bug that allows access to variable templates through member access notation. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@261506 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index 415587498d..17e6e16a88 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -902,6 +902,32 @@ static bool IsInFnTryBlockHandler(const Scope *S) { return false; } +static VarDecl * +getVarTemplateSpecialization(Sema &S, VarTemplateDecl *VarTempl, + const TemplateArgumentListInfo *TemplateArgs, + const DeclarationNameInfo &MemberNameInfo, + SourceLocation TemplateKWLoc) { + + if (!TemplateArgs) { + S.Diag(MemberNameInfo.getBeginLoc(), diag::err_template_decl_ref) + << /*Variable template*/ 1 << MemberNameInfo.getName() + << MemberNameInfo.getSourceRange(); + + S.Diag(VarTempl->getLocation(), diag::note_template_decl_here); + + return nullptr; + } + DeclResult VDecl = S.CheckVarTemplateId( + VarTempl, TemplateKWLoc, MemberNameInfo.getLoc(), *TemplateArgs); + if (VDecl.isInvalid()) + return nullptr; + VarDecl *Var = cast(VDecl.get()); + if (!Var->getTemplateSpecializationKind()) + Var->setTemplateSpecializationKind(TSK_ImplicitInstantiation, + MemberNameInfo.getLoc()); + return Var; +} + ExprResult Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, SourceLocation OpLoc, bool IsArrow, @@ -1069,9 +1095,20 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, // Handle the implicit-member-access case. if (!BaseExpr) { // If this is not an instance member, convert to a non-member access. - if (!MemberDecl->isCXXInstanceMember()) + if (!MemberDecl->isCXXInstanceMember()) { + // If this is a variable template, get the instantiated variable + // declaration corresponding to the supplied template arguments + // (while emitting diagnostics as necessary) that will be referenced + // by this expression. + if (isa(MemberDecl)) { + MemberDecl = getVarTemplateSpecialization( + *this, cast(MemberDecl), TemplateArgs, + R.getLookupNameInfo(), TemplateKWLoc); + if (!MemberDecl) + return ExprError(); + } return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), MemberDecl); - + } SourceLocation Loc = R.getNameLoc(); if (SS.getRange().isValid()) Loc = SS.getRange().getBegin(); @@ -1127,6 +1164,15 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, TemplateKWLoc, Enum, FoundDecl, MemberNameInfo, Enum->getType(), VK_RValue, OK_Ordinary); } + if (VarTemplateDecl *VarTempl = dyn_cast(MemberDecl)) { + if (VarDecl *Var = getVarTemplateSpecialization( + *this, VarTempl, TemplateArgs, MemberNameInfo, TemplateKWLoc)) + return BuildMemberExpr(*this, Context, BaseExpr, IsArrow, OpLoc, SS, + TemplateKWLoc, Var, FoundDecl, MemberNameInfo, + Var->getType().getNonReferenceType(), VK_LValue, + OK_Ordinary); + return ExprError(); + } // We found something that we didn't expect. Complain. if (isa(MemberDecl)) diff --git a/test/SemaCXX/cxx1y-variable-templates_in_class.cpp b/test/SemaCXX/cxx1y-variable-templates_in_class.cpp index 65e2d6b608..1c59585b32 100644 --- a/test/SemaCXX/cxx1y-variable-templates_in_class.cpp +++ b/test/SemaCXX/cxx1y-variable-templates_in_class.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -verify -fsyntax-only %s -Wno-c++11-extensions -Wno-c++1y-extensions -DPRECXX11 // RUN: %clang_cc1 -std=c++11 -verify -fsyntax-only -Wno-c++1y-extensions %s -// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only %s +// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only %s -DCPP1Y #define CONST const @@ -338,3 +338,47 @@ namespace b20896909 { A ai; // expected-note {{in instantiation of}} } } +namespace member_access_is_ok { +#ifdef CPP1Y + namespace ns1 { + struct A { + template constexpr static T Var = N; + }; + static_assert(A{}.Var == 5,""); + } // end ns1 +#endif // CPP1Y + +namespace ns2 { + template struct A { + template static T&& Var; + }; + template template T&& A::Var = T(N + M); + int *AV = &A().Var; + +} //end ns2 +} // end ns member_access_is_ok + +#ifdef CPP1Y +namespace PR24473 { +struct Value +{ + template + static constexpr T value = 0; +}; + +template +struct Something +{ + void foo() { + static_assert(TValue::template value == 0, ""); // error + } +}; + +int main() { + Something{}.foo(); + return 0; +} + +} // end ns PR24473 +#endif // CPP1Y +