r261506 - Fix PR24473 : Teach clang to remember to substitute into member variable templates referred to within dependent qualified ids.
Faisal Vali via cfe-commits
cfe-commits at lists.llvm.org
Mon Feb 22 05:07:29 PST 2016
On Mon, Feb 22, 2016 at 6:46 AM, Faisal Vali <faisalv at gmail.com> wrote:
> On Sun, Feb 21, 2016 at 11:45 PM, Richard Smith <richard at metafoo.co.uk> wrote:
>> On 21 Feb 2016 8:21 p.m., "Faisal Vali" <faisalv at gmail.com> wrote:
>>>
>>> On Sun, Feb 21, 2016 at 10:06 PM, Richard Smith <richard at metafoo.co.uk>
>>> wrote:
>>> > On 21 Feb 2016 6:29 p.m., "Faisal Vali via cfe-commits"
>>> > <cfe-commits at lists.llvm.org> wrote:
>>> >>
>>> >> Author: faisalv
>>> >> Date: Sun Feb 21 20:24:29 2016
>>> >> New Revision: 261506
>>> >>
>>> >> URL: http://llvm.org/viewvc/llvm-project?rev=261506&view=rev
>>> >> Log:
>>> >> 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.
>>> >>
>>> >>
>>> >> Modified:
>>> >> cfe/trunk/lib/Sema/SemaExprMember.cpp
>>> >> cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
>>> >>
>>> >> Modified: cfe/trunk/lib/Sema/SemaExprMember.cpp
>>> >> URL:
>>> >>
>>> >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprMember.cpp?rev=261506&r1=261505&r2=261506&view=diff
>>> >>
>>> >>
>>> >> ==============================================================================
>>> >> --- cfe/trunk/lib/Sema/SemaExprMember.cpp (original)
>>> >> +++ cfe/trunk/lib/Sema/SemaExprMember.cpp Sun Feb 21 20:24:29 2016
>>> >> @@ -902,6 +902,32 @@ static bool IsInFnTryBlockHandler(const
>>> >> 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<VarDecl>(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 *Bas
>>> >> // 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<VarTemplateDecl>(MemberDecl)) {
>>> >> + MemberDecl = getVarTemplateSpecialization(
>>> >> + *this, cast<VarTemplateDecl>(MemberDecl), TemplateArgs,
>>> >> + R.getLookupNameInfo(), TemplateKWLoc);
>>> >> + if (!MemberDecl)
>>> >> + return ExprError();
>>> >> + }
>>> >> return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(),
>>> >> MemberDecl);
>>> >
>>> > Does this properly preserve the template argument list as written?
>>> >
>>>
>>> Shouldn't it? Since it passes on the passed in template argument list
>>> (that I'm assuming is preserved) to CheckVarTemplateId?
>>
>> None of the three arguments passed to BuildDeclarationNameExpr references
>> the template argument list as written. Passing it to CheckVarTemplateId is
>> insufficient -- that can't preserve the template arguments from each use,
>> because it produces the same result for all uses.
>>
>
> I see what you mean. I'll pass the TemplateArgs through to
> BuildDeclRefExpr so it is preserved within that node. Does it make
> sense to squirrel the FoundDecl (the template) within the
> DeclRefExpr node too?
>
FYI, I think we should, since the FoundDecl could be a using member
declaration for a base class' variable template. (Not sure why this
wasn't being preserved for the non-variable template case either?)
>
>
>>> Perhaps you have an example in mind?
>>>
>>> Thanks!
>>>
>>> >> -
>>> >> + }
>>> >> SourceLocation Loc = R.getNameLoc();
>>> >> if (SS.getRange().isValid())
>>> >> Loc = SS.getRange().getBegin();
>>> >> @@ -1127,6 +1164,15 @@ Sema::BuildMemberReferenceExpr(Expr *Bas
>>> >> TemplateKWLoc, Enum, FoundDecl,
>>> >> MemberNameInfo,
>>> >> Enum->getType(), VK_RValue, OK_Ordinary);
>>> >> }
>>> >> + if (VarTemplateDecl *VarTempl =
>>> >> dyn_cast<VarTemplateDecl>(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<TypeDecl>(MemberDecl))
>>> >>
>>> >> Modified: cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
>>> >> URL:
>>> >>
>>> >> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp?rev=261506&r1=261505&r2=261506&view=diff
>>> >>
>>> >>
>>> >> ==============================================================================
>>> >> --- cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
>>> >> (original)
>>> >> +++ cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp Sun
>>> >> Feb
>>> >> 21 20:24:29 2016
>>> >> @@ -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<int> ai; // expected-note {{in instantiation of}}
>>> >> }
>>> >> }
>>> >> +namespace member_access_is_ok {
>>> >> +#ifdef CPP1Y
>>> >> + namespace ns1 {
>>> >> + struct A {
>>> >> + template<class T, T N> constexpr static T Var = N;
>>> >> + };
>>> >> + static_assert(A{}.Var<int,5> == 5,"");
>>> >> + } // end ns1
>>> >> +#endif // CPP1Y
>>> >> +
>>> >> +namespace ns2 {
>>> >> + template<class T> struct A {
>>> >> + template<class U, T N, U M> static T&& Var;
>>> >> + };
>>> >> + template<class T> template<class U, T N, U M> T&& A<T>::Var = T(N +
>>> >> M);
>>> >> + int *AV = &A<int>().Var<char, 5, 'A'>;
>>> >> +
>>> >> +} //end ns2
>>> >> +} // end ns member_access_is_ok
>>> >> +
>>> >> +#ifdef CPP1Y
>>> >> +namespace PR24473 {
>>> >> +struct Value
>>> >> +{
>>> >> + template<class T>
>>> >> + static constexpr T value = 0;
>>> >> +};
>>> >> +
>>> >> +template<typename TValue>
>>> >> +struct Something
>>> >> +{
>>> >> + void foo() {
>>> >> + static_assert(TValue::template value<int> == 0, ""); // error
>>> >> + }
>>> >> +};
>>> >> +
>>> >> +int main() {
>>> >> + Something<Value>{}.foo();
>>> >> + return 0;
>>> >> +}
>>> >> +
>>> >> +} // end ns PR24473
>>> >> +#endif // CPP1Y
>>> >> +
>>> >>
>>> >>
>>> >> _______________________________________________
>>> >> cfe-commits mailing list
>>> >> cfe-commits at lists.llvm.org
>>> >> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list