Bug 69098 - [5/6 regression] Member function pointer template flagged with 'is not a function template'
Summary: [5/6 regression] Member function pointer template flagged with 'is not a func...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 6.0
: P2 minor
Target Milestone: 5.4
Assignee: Patrick Palka
URL:
Keywords: rejects-valid
Depends on:
Blocks:
 
Reported: 2015-12-31 05:38 UTC by Hireve
Modified: 2016-02-22 15:58 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work: 5.1.0
Known to fail: 6.0
Last reconfirmed: 2016-01-04 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Hireve 2015-12-31 05:38:27 UTC
GCC HEAD on Wandbox rejects the code I pasted below, while Clang accepts it without errors. Link: http://melpon.org/wandbox/permlink/DShqHOBBMDx3X0H2

I also have a local TDM-GCC 5.1.0 (DW2) installation which gives the same error message for my original code, but for some reason the bug doesn’t trigger on Wandbox’s 5.1.0 with the minimal testcase I’ve extracted.

/*-- Code --*/
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()
{
}
Comment 1 Hireve 2016-01-02 18:48:15 UTC
The error message I got, copied from Wandbox:

prog.cc: In instantiation of 'static void Specializer::InnerClassTempl<<anonymous> >::InnerMemberFn() [with unsigned int <anonymous> = 0u]':
prog.cc:16:24:   required from here
prog.cc:33:36: error: 'template<bool P> constexpr void (Specializer::* const SpecPerType<Specializer>::SpecMbrFnPtr)()<<anonymous> >' is not a function template
  typename Spec::FnType ErrorSite = Spec::template SpecMbrFnPtr<true>;
                                    ^~~~

prog.cc:33:36: error: 'SpecMbrFnPtr<true>' is not a member of 'Spec {aka SpecPerType<Specializer>}'
Comment 2 Martin Sebor 2016-01-04 04:39:06 UTC
Confirmed.  The following simplified test case also reproduces the error with today's top of trunk.  5.1.0 compiles the test case successfully so this is a regression.

$ cat u.cpp && /home/msebor/build/gcc-trunk-svn/gcc/xg++ -B/home/msebor/build/gcc-trunk-svn/gcc -S -Wall -Wextra -o/dev/null -std=c++14 u.cpp
struct A
{    
  template <int>
  static void (*pf)();
};

template <int>
void foo () {
  (void)A::pf<true>;
}

void bar () {
  foo<0>();
}
u.cpp: In instantiation of ‘void foo() [with int <anonymous> = 0]’:
u.cpp:13:10:   required from here
u.cpp:9:9: error: ‘template<int <anonymous> > void (* A::pf)()<<anonymous> >’ is not a function template
   (void)A::pf<true>;
         ^

u.cpp:9:9: error: ‘pf<true>’ is not a member of ‘A’
Comment 3 Hireve 2016-01-05 22:11:54 UTC
Your testcase is really quite a bit smaller still – impressive skills! :)

Thanks for confirming and since 5.1.0 works for you, on Wandbox and additionally your testcase doesn’t fail locally, I guess I might just have looked at the wrong one of my two installations when I queried the version, perhaps I forgot to prepend '.\' or something like that.
Comment 4 Patrick Palka 2016-01-31 22:49:26 UTC
(In reply to Martin Sebor from comment #2)
> Confirmed.  The following simplified test case also reproduces the error
> with today's top of trunk.  5.1.0 compiles the test case successfully so
> this is a regression.
> 
> $ cat u.cpp && /home/msebor/build/gcc-trunk-svn/gcc/xg++
> -B/home/msebor/build/gcc-trunk-svn/gcc -S -Wall -Wextra -o/dev/null
> -std=c++14 u.cpp
> struct A
> {    
>   template <int>
>   static void (*pf)();
> };
> 
> template <int>
> void foo () {
>   (void)A::pf<true>;
> }
> 
> void bar () {
>   foo<0>();
> }
> u.cpp: In instantiation of ‘void foo() [with int <anonymous> = 0]’:
> u.cpp:13:10:   required from here
> u.cpp:9:9: error: ‘template<int <anonymous> > void (* A::pf)()<<anonymous>
> >’ is not a function template
>    (void)A::pf<true>;
>          ^
> 
> u.cpp:9:9: error: ‘pf<true>’ is not a member of ‘A’

This test seems to regress between 5.2 and 5.3.
Comment 5 Martin Sebor 2016-02-01 03:47:34 UTC
I looks like it was introduced in r186681.  The last good commit before that is r186667, and none of those in between touch the C++ front end.  Though the changes in r186681 look very mechanical and not related to templates at all so I'm not sure.
Comment 6 Patrick Palka 2016-02-01 16:46:14 UTC
This fixes it:

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index ef79b59..264c8aa 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -13735,7 +13735,19 @@ 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);
+           }
+       }
+      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),
Comment 7 Jakub Jelinek 2016-02-10 11:48:27 UTC
(In reply to Patrick Palka from comment #6)
> This fixes it:

Are you going to post it to gcc-patches (with ChangeLog and testcase)?
Comment 8 Jakub Jelinek 2016-02-10 11:56:37 UTC
The #c5 mentioned revisions look really weird, my bisection shows this regressed on the trunk with r226642, which has been indeed backported to 5 branch too.
Downgrading to P2, as we've already released one compiler (5.3) with this bug.
Comment 9 Patrick Palka 2016-02-10 16:38:37 UTC
(In reply to Jakub Jelinek from comment #7)
> (In reply to Patrick Palka from comment #6)
> > This fixes it:
> 
> Are you going to post it to gcc-patches (with ChangeLog and testcase)?

It doesn't yet make sense to me why r226642 introduces this regression. Once I figure it out I'll post the patch.
Comment 10 Patrick Palka 2016-02-10 17:06:56 UTC
(In reply to Patrick Palka from comment #9)
> (In reply to Jakub Jelinek from comment #7)
> > (In reply to Patrick Palka from comment #6)
> > > This fixes it:
> > 
> > Are you going to post it to gcc-patches (with ChangeLog and testcase)?
> 
> It doesn't yet make sense to me why r226642 introduces this regression. Once
> I figure it out I'll post the patch.

This change

--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -8187,14 +8187,14 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
 tree
 lookup_template_variable (tree templ, tree arglist)
 {
-  tree type = unknown_type_node;
+  tree type = NULL_TREE;
   return build2 (TEMPLATE_ID_EXPR, type, templ, arglist);
 }

made finish_id_expression later wrap the variable-template expression in a SCOPE_REF since the expression is now considered dependent (dependent_type_p returns true for a NULL_TREE).  But later during instantiation, tsubst is not yet prepared to handle a SCOPE_REF whose RHS is a variable template and the patch I posted seems to address that.
Comment 11 Patrick Palka 2016-02-10 17:53:48 UTC
There is another bug lurking here, though.  The following test case fails to compile, even with my proposed patch:

struct A
{
  template <int>
  static void *pf;
};

template <typename B>
bool foo () {
  return B::template pf<false>;
}

bool bar () {
  return foo<A>();
}


69098.C: In instantiation of ‘bool foo() [with B = A]’:
69098.C:16:17:   required from here
69098.C:12:10: error: ‘A::pf<0>’ is not a template [-fpermissive]
   return B::template pf<false>;
          ^
Comment 12 Patrick Palka 2016-02-12 01:12:24 UTC
Author: ppalka
Date: Fri Feb 12 01:11:52 2016
New Revision: 233365

URL: https://gcc.gnu.org/viewcvs?rev=233365&root=gcc&view=rev
Log:
Fix PR c++/69098 (bogus errors with static data member template)

gcc/cp/ChangeLog:

	PR c++/69098
	* pt.c (lookup_and_finish_template_variable): New function,
	extracted from ...
	(tsubst_copy_and_build) [TEMPLATE_ID_EXPR]: ... here.
	(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.


Added:
    trunk/gcc/testsuite/g++.dg/cpp1y/69098-2.C
    trunk/gcc/testsuite/g++.dg/cpp1y/69098.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/pt.c
    trunk/gcc/cp/typeck.c
    trunk/gcc/testsuite/ChangeLog
Comment 13 Jakub Jelinek 2016-02-22 15:37:24 UTC
Is this fixed now?
Comment 14 Patrick Palka 2016-02-22 15:58:44 UTC
Oops yeah, fixed for GCC 6.