On 12/03/2015 09:55 AM, David Malcolm wrote:
Testcase g++.dg/template/ref3.C:

      1 // PR c++/28341
      2
      3 template<const int&> struct A {};
      4
      5 template<typename T> struct B
      6 {
      7   A<(T)0> b; // { dg-error "constant|not a valid" }
      8   A<T(0)> a; // { dg-error "constant|not a valid" }
      9 };
     10
     11 B<const int&> b;

The output of this test for both c++11 and c++14 is unaffected
by the patch kit:
  g++.dg/template/ref3.C: In instantiation of 'struct B<const int&>':
  g++.dg/template/ref3.C:11:15:   required from here
  g++.dg/template/ref3.C:7:11: error: '0' is not a valid template argument for type 
'const int&' because it is not an lvalue
  g++.dg/template/ref3.C:8:11: error: '0' is not a valid template argument for type 
'const int&' because it is not an lvalue

However, the c++98 output is changed:

Status quo for c++98:
g++.dg/template/ref3.C: In instantiation of 'struct B<const int&>':
g++.dg/template/ref3.C:11:15:   required from here
g++.dg/template/ref3.C:7:11: error: a cast to a type other than an integral or 
enumeration type cannot appear in a constant-expression
g++.dg/template/ref3.C:8:11: error: a cast to a type other than an integral or 
enumeration type cannot appear in a constant-expression

(line 7 and 8 are at the closing semicolon for fields b and a)

With the patchkit for c++98:
g++.dg/template/ref3.C: In instantiation of 'struct B<const int&>':
g++.dg/template/ref3.C:11:15:   required from here
g++.dg/template/ref3.C:7:5: error: a cast to a type other than an integral or 
enumeration type cannot appear in a constant-expression
g++.dg/template/ref3.C:7:5: error: a cast to a type other than an integral or 
enumeration type cannot appear in a constant-expression

So the 2nd:
   "error: a cast to a type other than an integral or enumeration type cannot appear 
in a constant-expression"
moves from line 8 to line 7 (and moves them to earlier, having ranges)

What's happening is that cp_parser_enclosed_template_argument_list
builds a CAST_EXPR, the first time from cp_parser_cast_expression,
the second time from cp_parser_functional_cast; these have locations
representing the correct respective caret&ranges, i.e.:

    A<(T)0> b;
      ^~~~

and:

    A<T(0)> a;
      ^~~~

Eventually finish_template_type is called for each, to build a RECORD_TYPE,
and we get a cache hit the 2nd time through here in pt.c:
8281          hash = spec_hasher::hash (&elt);
8282          entry = type_specializations->find_with_hash (&elt, hash);
8283
8284          if (entry)
8285            return entry->spec;

due to:
   template_args_equal (ot=<cast_expr 0x7ffff19bc400>, nt=<cast_expr 
0x7ffff19bc480>) at ../../src/gcc/cp/pt.c:7778
which calls:
   cp_tree_equal (t1=<cast_expr 0x7ffff19bc400>, t2=<cast_expr 0x7ffff19bc480>) 
at ../../src/gcc/cp/tree.c:2833
and returns equality.

Hence we get a single RECORD_TYPE for the type A<(T)(0)>, and hence
when issuing the errors it uses the TREE_VEC for the first one,
using the location of the first line.

Why does the type sharing affect where the parser gives the error?

I'm not sure what the ideal fix for this is; for now I've worked
around it by updating the dg directives to reflect the new output.

gcc/testsuite/ChangeLog:
        * g++.dg/template/ref3.C: Update locations of dg directives.
---
  gcc/testsuite/g++.dg/template/ref3.C | 6 ++++--
  1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/gcc/testsuite/g++.dg/template/ref3.C 
b/gcc/testsuite/g++.dg/template/ref3.C
index 976c093..6e568c3 100644
--- a/gcc/testsuite/g++.dg/template/ref3.C
+++ b/gcc/testsuite/g++.dg/template/ref3.C
@@ -4,8 +4,10 @@ template<const int&> struct A {};

  template<typename T> struct B
  {
-  A<(T)0> b; // { dg-error "constant|not a valid" }
-  A<T(0)> a; // { dg-error "constant|not a valid" }
+  A<(T)0> b; // { dg-error "constant" "" { target c++98_only } }
+  // { dg-error "not a valid" "" { target c++11 } 7 }
+
+  A<T(0)> a; // { dg-error "not a valid" "" { target c++11 } }
  };

  B<const int&> b;


Reply via email to