diff mbox

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

Message ID 1455131764-11282-1-git-send-email-patrick@parcs.ath.cx
State New
Headers show

Commit Message

Patrick Palka Feb. 10, 2016, 7:16 p.m. UTC
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

Comments

Patrick Palka Feb. 10, 2016, 7:24 p.m. UTC | #1
On Wed, Feb 10, 2016 at 2:16 PM, Patrick Palka <patrick@parcs.ath.cx> wrote:
> 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).

Err, sorry, disregard this last sentence, including the parenthetical.
Both tsubst_qualified_id() and check_template_keyword() must be fixed
in order for foo2 to compile.  For foo1 to compile, only
tsubst_qualified_id() must be fixed.  foo3 and foo4 are just examples
for which an earlier iteration of this patch caused an ICE.
Jason Merrill Feb. 10, 2016, 9:02 p.m. UTC | #2
On 02/10/2016 02:16 PM, Patrick Palka wrote:
> ...in tsubst_qualified_id() I just copied the way variable templates are
> handled in tsubst_copy_and_build [TEMPLATE_ID_EXPR].

Let's factor that code out into another function rather than copy it.

Jason
diff mbox

Patch

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()
+{
+}