[PATCH] Fix PR c++/69098 (bogus errors with static data member template)

Patrick Palka patrick@parcs.ath.cx
Wed Feb 10 19:16:00 GMT 2016


tsubst_qualified_id() is currently not prepared to handle a SCOPED_REF
whose RHS is a variable template.  r226642 made this deficiency more
obvious by marking all variable templates as dependent (thus forcing
them to be wrapped in a SCOPED_REF) but before that it was also possible
to trigger a bogus error if the scope of the variable template was
dependent (e.g. foo2 in the test case 69098-2.C fails to compile even
before r226642, whereas foo1 fails to compile only after r226642).

Further, check_template_keyword() is currently not prepared to handle
variable templates as well.  And again r226642 helped to expose this
issue but it was already possible to trigger before that (e.g. foo4
always failed to compile whereas foo3 only fails after r226642).

This patch makes tsubst_qualified_id() and check_template_keyword()
handle variable templates accordingly.  The changes in
check_template_keyword() are fairly straightforward, and in
tsubst_qualified_id() I just copied the way variable templates are
handled in tsubst_copy_and_build [TEMPLATE_ID_EXPR].

Boostrap + regtest in progress on x86_64-pc-linux-gnu, Ok to commit
after testing?

gcc/cp/ChangeLog:

	PR c++/69098
	* pt.c (tsubst_qualified_id): Consider that EXPR might
	be a variable template.
	* typeck.c (check_template_keyword): Don't emit an error
	if DECL is a variable template.

gcc/testsuite/ChangeLog:

	PR c++/69098
	* g++.dg/cpp1y/69098.C: New test.
	* g++.dg/cpp1y/69098-2.C: New test.
---
 gcc/cp/pt.c                          | 15 ++++++++++++-
 gcc/cp/typeck.c                      | 10 ++++++++-
 gcc/testsuite/g++.dg/cpp1y/69098-2.C | 37 +++++++++++++++++++++++++++++++
 gcc/testsuite/g++.dg/cpp1y/69098.C   | 43 ++++++++++++++++++++++++++++++++++++
 4 files changed, 103 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/69098-2.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/69098.C

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 725adba..6780a98 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -13726,7 +13726,20 @@ tsubst_qualified_id (tree qualified_id, tree args,
     }
 
   if (is_template)
-    expr = lookup_template_function (expr, template_args);
+    {
+      if (variable_template_p (expr))
+	{
+	  expr = lookup_template_variable (expr, template_args);
+	  if (!any_dependent_template_arguments_p (template_args))
+	    {
+	      expr = finish_template_variable (expr, complain);
+	      mark_used (expr);
+	    }
+	  expr = convert_from_reference (expr);
+	}
+      else
+	expr = lookup_template_function (expr, template_args);
+    }
 
   if (expr == error_mark_node && complain & tf_error)
     qualified_name_lookup_error (scope, TREE_OPERAND (qualified_id, 1),
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index d2c23f4..959dc5a 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -2601,7 +2601,15 @@ check_template_keyword (tree decl)
   if (TREE_CODE (decl) != TEMPLATE_DECL
       && TREE_CODE (decl) != TEMPLATE_ID_EXPR)
     {
-      if (!is_overloaded_fn (decl))
+      if (VAR_P (decl))
+	{
+	  if (DECL_USE_TEMPLATE (decl)
+	      && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl)))
+	    ;
+	  else
+	    permerror (input_location, "%qD is not a template", decl);
+	}
+      else if (!is_overloaded_fn (decl))
 	permerror (input_location, "%qD is not a template", decl);
       else
 	{
diff --git a/gcc/testsuite/g++.dg/cpp1y/69098-2.C b/gcc/testsuite/g++.dg/cpp1y/69098-2.C
new file mode 100644
index 0000000..2e968bb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/69098-2.C
@@ -0,0 +1,37 @@
+// PR c++/69098
+// { dg-do compile { target c++14 } }
+
+struct A
+{
+  template <int>
+  static void *pf;
+};
+
+template <typename B>
+bool foo1 () {
+  return A::pf<false>;
+}
+
+template <typename B>
+bool foo2 () {
+  return B::template pf<false>;
+}
+
+template <typename B>
+bool foo3 () {
+  return &A::pf<false>;
+}
+
+template <typename B>
+bool foo4 () {
+  return &B::template pf<false>;
+}
+
+
+void bar () {
+  foo1<A>();
+  foo2<A>();
+  foo3<A>();
+  foo4<A>();
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp1y/69098.C b/gcc/testsuite/g++.dg/cpp1y/69098.C
new file mode 100644
index 0000000..afc4294
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/69098.C
@@ -0,0 +1,43 @@
+// PR c++/69098
+// { dg-do compile { target c++14 } }
+
+template<typename> struct SpecPerType;
+
+class Specializer
+{
+public:
+    template<bool> void MbrFnTempl() //Must be a template
+	{
+	}
+	template<unsigned> struct InnerClassTempl
+	{  //Had to be a template whenever I tested for it
+		static void InnerMemberFn();
+	};
+
+	void Trigger()
+	{
+		InnerClassTempl<0u>::InnerMemberFn();
+	}
+};
+
+template<> struct SpecPerType<Specializer>
+{
+	using FnType = void (Specializer::*)();
+    template<bool P> static constexpr FnType SpecMbrFnPtr =
+        &Specializer::template MbrFnTempl<P>;
+};
+
+template<bool> constexpr SpecPerType<Specializer>::FnType
+    SpecPerType<Specializer>::SpecMbrFnPtr; //Just a formalism
+
+template<unsigned X> void Specializer::InnerClassTempl<X>::InnerMemberFn()
+{
+	using Spec = SpecPerType<Specializer>;
+	typename Spec::FnType ErrorSite = Spec::template SpecMbrFnPtr<true>;
+    //ErrorSite would get called next in the original code
+    //(this should result in a call to MbrFnTempl)
+}
+
+int main()
+{
+}
-- 
2.7.1.257.g925a48d



More information about the Gcc-patches mailing list