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
Sun Feb 21 18:24:29 PST 2016


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);
-
+    }
     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
+




More information about the cfe-commits mailing list