From: Nathan Sidwell Date: Sat, 22 Mar 2003 15:34:41 +0000 (+0000) Subject: PR c++/9978, c++/9708 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=3e4a35628b614d3e155ae9853888d69c5e89a354;p=gcc.git PR c++/9978, c++/9708 cp: PR c++/9978, c++/9708 * cp-tree.h (instantiate_template): Add tsubst_flags parameter. * call.c (add_template_candidate_real): Adjust instantiate_template call. * class.c (resolve_address_of_overloaded_function): Likewise. * decl.c (build_enumerator): Set TREE_CONSTANT. * pt.c (check_instantiated_args): New. (push_inline_template_parms_recursive): Set TREE_CONSTANT, TREE_READONLY. (build_template_parm_index): Copy TREE_CONSTANT, TREE_READONLY. (reduce_template_parm_level): Likewise. (process_template_parm): Likewise. (check_explicit_specialization): Adjust instantiate_template call. (convert_template_argument): Don't check non-type argument here. (lookup_template_class): Check them here. (tsubst_friend_function): Adjust instantiate_template call. (instantiate_template): Add tsubst_flags parameter, use it. Check instantiated args. testsuite: PR c++/9978, c++/9708 * g++.dg/ext/vlm1.C: Adjust expected error. * g++.dg/ext/vla2.C: New test. * g++.dg/template/arg1.C: New test. * g++.dg/template/arg2.C: New test. From-SVN: r64714 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 616078ab272..ecc9bdaa214 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,24 @@ +2003-03-22 Nathan Sidwell + + PR c++/9978, c++/9708 + * cp-tree.h (instantiate_template): Add tsubst_flags parameter. + * call.c (add_template_candidate_real): Adjust + instantiate_template call. + * class.c (resolve_address_of_overloaded_function): Likewise. + * decl.c (build_enumerator): Set TREE_CONSTANT. + * pt.c (check_instantiated_args): New. + (push_inline_template_parms_recursive): Set TREE_CONSTANT, + TREE_READONLY. + (build_template_parm_index): Copy TREE_CONSTANT, TREE_READONLY. + (reduce_template_parm_level): Likewise. + (process_template_parm): Likewise. + (check_explicit_specialization): Adjust instantiate_template call. + (convert_template_argument): Don't check non-type argument here. + (lookup_template_class): Check them here. + (tsubst_friend_function): Adjust instantiate_template call. + (instantiate_template): Add tsubst_flags parameter, use it. Check + instantiated args. + 2003-03-21 Zack Weinberg * decl.c: Update calls to shadow_warning. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 09a06567f58..3d8e17f67fe 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -2275,7 +2275,7 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl, if (i != 0) return NULL; - fn = instantiate_template (tmpl, targs); + fn = instantiate_template (tmpl, targs, tf_none); if (fn == error_mark_node) return NULL; diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 0df87ae71af..e899c571406 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -5989,7 +5989,8 @@ cannot resolve overloaded function `%D' based on conversion to type `%T'", continue; /* Instantiate the template. */ - instantiation = instantiate_template (fn, targs); + instantiation = instantiate_template (fn, targs, + complain ? tf_error : tf_none); if (instantiation == error_mark_node) /* Instantiation failed. */ continue; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 2a207a1a7f9..1c871e8fcdc 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4016,7 +4016,7 @@ extern tree lookup_template_class (tree, tree, tree, tree, int, tsubst_flags_t) extern tree lookup_template_function (tree, tree); extern int uses_template_parms (tree); extern tree instantiate_class_template (tree); -extern tree instantiate_template (tree, tree); +extern tree instantiate_template (tree, tree, tsubst_flags_t); extern int fn_type_unification (tree, tree, tree, tree, tree, unification_kind_t, int); extern tree tinst_for_decl (void); extern void mark_decl_instantiated (tree, int); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 99898d02b95..4756cdce902 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -13286,8 +13286,8 @@ build_enumerator (tree name, tree value, tree enumtype) decl = build_decl (CONST_DECL, name, type); DECL_CONTEXT (decl) = FROB_CONTEXT (context); + TREE_CONSTANT (decl) = TREE_READONLY (decl) = 1; DECL_INITIAL (decl) = value; - TREE_READONLY (decl) = 1; if (context && context == current_class_type) /* In something like `struct S { enum E { i = 7 }; };' we put `i' diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 8523c9671cc..aa9a2c72802 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -110,6 +110,7 @@ static tree coerce_template_parms PARAMS ((tree, tree, tree, static void tsubst_enum PARAMS ((tree, tree, tree)); static tree add_to_template_args PARAMS ((tree, tree)); static tree add_outermost_template_args PARAMS ((tree, tree)); +static bool check_instantiated_args PARAMS ((tree, tree, tsubst_flags_t)); static int maybe_adjust_types_for_deduction PARAMS ((unification_kind_t, tree*, tree*)); static int type_unification_real PARAMS ((tree, tree, tree, tree, @@ -429,6 +430,7 @@ push_inline_template_parms_recursive (parmlist, levels) tree decl = build_decl (CONST_DECL, DECL_NAME (parm), TREE_TYPE (parm)); DECL_ARTIFICIAL (decl) = 1; + TREE_CONSTANT (decl) = TREE_READONLY (decl) = 1; DECL_INITIAL (decl) = DECL_INITIAL (parm); SET_DECL_TEMPLATE_PARM_P (decl); pushdecl (decl); @@ -1839,7 +1841,7 @@ check_explicit_specialization (declarator, decl, template_count, flags) targs = new_targs; } - return instantiate_template (tmpl, targs); + return instantiate_template (tmpl, targs, tf_error); } /* If this is a specialization of a member template of a @@ -2050,6 +2052,8 @@ build_template_parm_index (index, level, orig_level, decl, type) TEMPLATE_PARM_ORIG_LEVEL (t) = orig_level; TEMPLATE_PARM_DECL (t) = decl; TREE_TYPE (t) = type; + TREE_CONSTANT (t) = TREE_CONSTANT (decl); + TREE_READONLY (t) = TREE_READONLY (decl); return t; } @@ -2069,20 +2073,21 @@ reduce_template_parm_level (index, type, levels) || (TEMPLATE_PARM_LEVEL (TEMPLATE_PARM_DESCENDANTS (index)) != TEMPLATE_PARM_LEVEL (index) - levels)) { - tree decl - = build_decl (TREE_CODE (TEMPLATE_PARM_DECL (index)), - DECL_NAME (TEMPLATE_PARM_DECL (index)), - type); - tree t - = build_template_parm_index (TEMPLATE_PARM_IDX (index), + tree orig_decl = TEMPLATE_PARM_DECL (index); + tree decl, t; + + decl = build_decl (TREE_CODE (orig_decl), DECL_NAME (orig_decl), type); + TREE_CONSTANT (decl) = TREE_CONSTANT (orig_decl); + TREE_READONLY (decl) = TREE_READONLY (orig_decl); + DECL_ARTIFICIAL (decl) = 1; + SET_DECL_TEMPLATE_PARM_P (decl); + + t = build_template_parm_index (TEMPLATE_PARM_IDX (index), TEMPLATE_PARM_LEVEL (index) - levels, TEMPLATE_PARM_ORIG_LEVEL (index), decl, type); TEMPLATE_PARM_DESCENDANTS (index) = t; - DECL_ARTIFICIAL (decl) = 1; - SET_DECL_TEMPLATE_PARM_P (decl); - /* Template template parameters need this. */ DECL_TEMPLATE_PARMS (decl) = DECL_TEMPLATE_PARMS (TEMPLATE_PARM_DECL (index)); @@ -2137,10 +2142,11 @@ process_template_parm (list, next) TREE_TYPE (parm) = TYPE_MAIN_VARIANT (TREE_TYPE (parm)); /* A template parameter is not modifiable. */ - TREE_READONLY (parm) = 1; + TREE_READONLY (parm) = TREE_CONSTANT (parm) = 1; if (invalid_nontype_parm_type_p (TREE_TYPE (parm), 1)) TREE_TYPE (parm) = void_type_node; decl = build_decl (CONST_DECL, DECL_NAME (parm), TREE_TYPE (parm)); + TREE_CONSTANT (decl) = TREE_READONLY (decl) = 1; DECL_INITIAL (parm) = DECL_INITIAL (decl) = build_template_parm_index (idx, processing_template_decl, processing_template_decl, @@ -3632,39 +3638,7 @@ convert_template_argument (parm, arg, args, complain, i, in_decl) } } else - { - val = groktypename (arg); - if (! processing_template_decl) - { - /* [basic.link]: A name with no linkage (notably, the - name of a class or enumeration declared in a local - scope) shall not be used to declare an entity with - linkage. This implies that names with no linkage - cannot be used as template arguments. */ - tree t = no_linkage_check (val); - if (t) - { - if (TYPE_ANONYMOUS_P (t)) - pedwarn - ("template-argument `%T' uses anonymous type", val); - else - error - ("template-argument `%T' uses local type `%T'", - val, t); - return error_mark_node; - } - - /* In order to avoid all sorts of complications, we do - not allow variably-modified types as template - arguments. */ - if (variably_modified_type_p (val)) - { - error ("template-argument `%T' is a variably modified type", - val); - return error_mark_node; - } - } - } + val = groktypename (arg); } else { @@ -3704,9 +3678,7 @@ convert_template_argument (parm, arg, args, complain, i, in_decl) /* Convert all template arguments to their appropriate types, and return a vector containing the innermost resulting template arguments. If any error occurs, return error_mark_node. Error and - warning messages are issued under control of COMPLAIN. Some error - messages are issued even if COMPLAIN is zero; for instance, if a - template argument is composed from a local class. + warning messages are issued under control of COMPLAIN. If REQUIRE_ALL_ARGUMENTS is nonzero, all arguments must be provided in ARGLIST, or else trailing parameters must have default @@ -4207,7 +4179,9 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope, complain) arglist2 = coerce_template_parms (parmlist, arglist, template, complain, /*require_all_args=*/1); - if (arglist2 == error_mark_node) + if (arglist2 == error_mark_node + || (!processing_template_decl + && check_instantiated_args (template, arglist2, complain))) POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node); parm = bind_template_template_parm (TREE_TYPE (template), arglist2); @@ -4296,7 +4270,11 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope, complain) template, complain, /*require_all_args=*/1); - if (arglist == error_mark_node) + if (arglist == error_mark_node + || (!processing_template_decl + && check_instantiated_args (template, + INNERMOST_TEMPLATE_ARGS (arglist), + complain))) /* We were unable to bind the arguments. */ POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node); @@ -4919,7 +4897,7 @@ tsubst_friend_function (decl, args) tmpl = determine_specialization (template_id, new_friend, &new_args, /*need_member_template=*/0); - new_friend = instantiate_template (tmpl, new_args); + new_friend = instantiate_template (tmpl, new_args, tf_error); goto done; } @@ -8394,18 +8372,78 @@ tsubst_copy_and_build (t, args, complain, in_decl) } } +/* Verify that the instantiated ARGS are valid. For type arguments, + make sure that the type's linkage is ok. For non-type arguments, + make sure they are constants if they are integral or enumarations. + Emit an error under control of COMPLAIN, and return TRUE on error. */ + +static bool +check_instantiated_args (tmpl, args, complain) + tree tmpl, args; + tsubst_flags_t complain; +{ + int ix, len = DECL_NTPARMS (tmpl); + bool result = false; + + for (ix = 0; ix != len; ix++) + { + tree t = TREE_VEC_ELT (args, ix); + + if (TYPE_P (t)) + { + /* [basic.link]: A name with no linkage (notably, the name + of a class or enumeration declared in a local scope) + shall not be used to declare an entity with linkage. + This implies that names with no linkage cannot be used as + template arguments. */ + tree nt = no_linkage_check (t); + + if (nt) + { + if (!(complain & tf_error)) + /*OK*/; + else if (TYPE_ANONYMOUS_P (nt)) + error ("`%T' uses anonymous type", t); + else + error ("`%T' uses local type `%T'", t, nt); + result = true; + } + /* In order to avoid all sorts of complications, we do not + allow variably-modified types as template arguments. */ + else if (variably_modified_type_p (t)) + { + if (complain & tf_error) + error ("`%T' is a variably modified type", t); + result = true; + } + } + /* A non-type argument of integral or enumerated type must be a + constant. */ + else if (TREE_TYPE (t) + && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (t)) + && !TREE_CONSTANT (t)) + { + if (complain & tf_error) + error ("integral expression `%E' is not constant", t); + result = true; + } + } + if (result && complain & tf_error) + error (" trying to instantiate `%D'", tmpl); + return result; +} + /* Instantiate the indicated variable or function template TMPL with the template arguments in TARG_PTR. */ tree -instantiate_template (tmpl, targ_ptr) +instantiate_template (tmpl, targ_ptr, complain) tree tmpl, targ_ptr; + tsubst_flags_t complain; { tree fndecl; tree gen_tmpl; tree spec; - int i, len; - tree inner_args; if (tmpl == error_mark_node) return error_mark_node; @@ -8415,7 +8453,8 @@ instantiate_template (tmpl, targ_ptr) /* If this function is a clone, handle it specially. */ if (DECL_CLONED_FUNCTION_P (tmpl)) { - tree spec = instantiate_template (DECL_CLONED_FUNCTION (tmpl), targ_ptr); + tree spec = instantiate_template (DECL_CLONED_FUNCTION (tmpl), targ_ptr, + complain); tree clone; /* Look for the clone. */ @@ -8449,34 +8488,20 @@ instantiate_template (tmpl, targ_ptr) return spec; } - len = DECL_NTPARMS (gen_tmpl); - inner_args = INNERMOST_TEMPLATE_ARGS (targ_ptr); - i = len; - while (i--) - { - tree t = TREE_VEC_ELT (inner_args, i); - if (TYPE_P (t)) - { - tree nt = target_type (t); - if (IS_AGGR_TYPE (nt) && decl_function_context (TYPE_MAIN_DECL (nt))) - { - error ("type `%T' composed from a local class is not a valid template-argument", t); - error (" trying to instantiate `%D'", gen_tmpl); - return error_mark_node; - } - } - } - + if (check_instantiated_args (gen_tmpl, INNERMOST_TEMPLATE_ARGS (targ_ptr), + complain)) + return error_mark_node; + /* Make sure that we can see identifiers, and compute access correctly. The desired FUNCTION_DECL for FNDECL may or may not be created earlier. Let push_access_scope_real figure that out. */ push_access_scope_real (gen_tmpl, targ_ptr, tsubst (DECL_CONTEXT (gen_tmpl), targ_ptr, - tf_error, gen_tmpl)); + complain, gen_tmpl)); /* substitute template parameters */ fndecl = tsubst (DECL_TEMPLATE_RESULT (gen_tmpl), - targ_ptr, tf_error, gen_tmpl); + targ_ptr, complain, gen_tmpl); pop_access_scope (gen_tmpl); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 25baba31661..901d52bb558 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2003-03-22 Nathan Sidwell + + PR c++/9978, c++/9708 + * g++.dg/ext/vlm1.C: Adjust expected error. + * g++.dg/ext/vla2.C: New test. + * g++.dg/template/arg1.C: New test. + * g++.dg/template/arg2.C: New test. + 2003-03-22 Bud Davis * g77.f-torture/execute/select.f: New test. diff --git a/gcc/testsuite/g++.dg/ext/vla2.C b/gcc/testsuite/g++.dg/ext/vla2.C new file mode 100644 index 00000000000..c17dc860910 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/vla2.C @@ -0,0 +1,18 @@ +// { dg-do compile } +// { dg-options "" } + +// Copyright (C) 2003 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 21 Mar 2003 + +// PR 9708. We unified a VLA size as a constant. Then issued bogus +// errors. + +template +char* begin(char (&a) [N] ); + +void bar(int i) +{ + char d[i] ; + + begin(d); // { dg-error "no matching function" "" } +} diff --git a/gcc/testsuite/g++.dg/ext/vlm1.C b/gcc/testsuite/g++.dg/ext/vlm1.C index 61628e6bba4..13f67027710 100644 --- a/gcc/testsuite/g++.dg/ext/vlm1.C +++ b/gcc/testsuite/g++.dg/ext/vlm1.C @@ -4,7 +4,7 @@ template struct A {}; struct B { static const int s; - A a; // { dg-error "variably modified|no type" } + A a; // { dg-error "variably modified|no type|trying to instantiate" } }; const int B::s=16; diff --git a/gcc/testsuite/g++.dg/template/arg1.C b/gcc/testsuite/g++.dg/template/arg1.C new file mode 100644 index 00000000000..f7a8b3150c6 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/arg1.C @@ -0,0 +1,15 @@ +// { dg-do compile } + +// Copyright (C) 2003 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 21 Mar 2003 + +// PR 9978. We rejected a constant expression. + +enum { val = 1 }; + +template +struct Bar +{ + static const int A = val; + static const int B = A + 1; +}; diff --git a/gcc/testsuite/g++.dg/template/arg2.C b/gcc/testsuite/g++.dg/template/arg2.C new file mode 100644 index 00000000000..5a4ff275cf3 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/arg2.C @@ -0,0 +1,14 @@ +// { dg-do compile } + +// Copyright (C) 2003 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 21 Mar 2003 + +// PR 9708. We accepted a local class + +template class X {}; + +void fn () +{ + class L {}; + X f; // { dg-error "uses local type|trying to instantiate|expected" "" } +}