From 77fe610cd77daed05bd9084edc7bd181cf5a8622 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 2 Dec 2015 12:54:56 -0500 Subject: [PATCH 07/10] Fix g++.dg/template/ref3.C Testcase g++.dg/template/ref3.C: 1 // PR c++/28341 2 3 template struct A {}; 4 5 template struct B 6 { 7 A<(T)0> b; // { dg-error "constant|not a valid" } 8 A a; // { dg-error "constant|not a valid" } 9 }; 10 11 B 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': 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': 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': 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 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=, nt=) at ../../src/gcc/cp/pt.c:7778 which calls: cp_tree_equal (t1=, t2=) 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. 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 struct A {}; template struct B { - A<(T)0> b; // { dg-error "constant|not a valid" } - A 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 a; // { dg-error "not a valid" "" { target c++11 } } }; B b; -- 1.8.5.3