From ccb05613cfd1d37ce6473244e28c56e75d1d0e66 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 8 Oct 2009 12:09:22 -0400 Subject: [PATCH] re PR c++/37177 ([c++0x] ICE on decltype(rel_ops::operator>);) PR c++/37177 * pt.c (resolve_nondeduced_context): New. * cvt.c (convert_to_void): Call it. * semantics.c (finish_decltype_type): Likewise. * typeck.c (decay_conversion): Here too. * pt.c (tsubst_decl): Don't clobber input_location. Don't register a bad specialization. From-SVN: r152564 --- gcc/cp/ChangeLog | 10 ++ gcc/cp/cp-tree.h | 4 +- gcc/cp/cvt.c | 1 + gcc/cp/pt.c | 144 ++++++++++++++++++++++--- gcc/cp/semantics.c | 7 +- gcc/cp/typeck.c | 1 + gcc/testsuite/ChangeLog | 8 ++ gcc/testsuite/g++.dg/cpp0x/variadic-throw.C | 4 +- gcc/testsuite/g++.dg/template/explicit-args2.C | 38 +++++++ gcc/testsuite/g++.dg/template/explicit-args3.C | 12 +++ gcc/testsuite/g++.old-deja/g++.pt/crash58.C | 12 +-- 11 files changed, 214 insertions(+), 27 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/explicit-args2.C create mode 100644 gcc/testsuite/g++.dg/template/explicit-args3.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 5cf2373..5f67204 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,13 @@ +2009-10-08 Jason Merrill + + PR c++/37177 + * pt.c (resolve_nondeduced_context): New. + * cvt.c (convert_to_void): Call it. + * semantics.c (finish_decltype_type): Likewise. + * typeck.c (decay_conversion): Here too. + * pt.c (tsubst_decl): Don't clobber input_location. + Don't register a bad specialization. + 2009-10-07 Gabriel Dos Reis * cp-tree.h: Fix location of documentation for DECL_LANG_FLAG_7. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 208bbe2..3d826b9 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4845,7 +4845,9 @@ bool template_template_parameter_p (const_tree); extern tree get_primary_template_innermost_parameters (const_tree); extern tree get_template_innermost_arguments (const_tree); extern tree get_template_argument_pack_elems (const_tree); -extern tree get_function_template_decl (const_tree); +extern tree get_function_template_decl (const_tree); +extern tree resolve_nondeduced_context (tree); + /* in repo.c */ extern void init_repo (void); extern int repo_emit_p (tree); diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index aff002d..8c5b001 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -956,6 +956,7 @@ convert_to_void (tree expr, const char *implicit, tsubst_flags_t complain) default:; } + expr = resolve_nondeduced_context (expr); { tree probe = expr; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 9ef3f79..19d8c9a 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -8461,6 +8461,7 @@ tsubst_default_arguments (tree fn) static tree tsubst_decl (tree t, tree args, tsubst_flags_t complain) { +#define RETURN(EXP) do { r = (EXP); goto out; } while(0) location_t saved_loc; tree r = NULL_TREE; tree in_decl = t; @@ -8486,7 +8487,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) /* Template template parameter is treated here. */ tree new_type = tsubst (TREE_TYPE (t), args, complain, in_decl); if (new_type == error_mark_node) - return error_mark_node; + RETURN (error_mark_node); r = copy_decl (t); TREE_CHAIN (r) = NULL_TREE; @@ -8517,12 +8518,12 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) complain, in_decl); --processing_template_decl; if (full_args == error_mark_node) - return error_mark_node; + RETURN (error_mark_node); /* If this is a default template template argument, tsubst might not have changed anything. */ if (full_args == tmpl_args) - return t; + RETURN (t); hash = hash_tmpl_and_args (t, full_args); spec = retrieve_specialization (t, full_args, hash); @@ -8550,7 +8551,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) new_type = tsubst (TREE_TYPE (t), args, complain, in_decl); --processing_template_decl; if (new_type == error_mark_node) - return error_mark_node; + RETURN (error_mark_node); TREE_TYPE (r) = new_type; CLASSTYPE_TI_TEMPLATE (new_type) = r; @@ -8565,7 +8566,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) new_decl = tsubst (decl, args, complain, in_decl); --processing_template_decl; if (new_decl == error_mark_node) - return error_mark_node; + RETURN (error_mark_node); DECL_TEMPLATE_RESULT (r) = new_decl; DECL_TI_TEMPLATE (new_decl) = r; @@ -8623,7 +8624,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) dependent_p = value_dependent_expression_p (t); --processing_template_decl; if (!dependent_p) - return t; + RETURN (t); /* Calculate the most general template of which R is a specialization, and the complete set of arguments used to @@ -8714,7 +8715,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) } type = tsubst (TREE_TYPE (t), args, complain, in_decl); if (type == error_mark_node) - return error_mark_node; + RETURN (error_mark_node); /* We do NOT check for matching decls pushed separately at this point, as they may not represent instantiations of this @@ -8757,6 +8758,13 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) /* We'll re-clone as appropriate in instantiate_template. */ DECL_CLONED_FUNCTION (r) = NULL_TREE; + /* If we aren't complaining now, return on error before we register + the specialization so that we'll complain eventually. */ + if ((complain & tf_error) == 0 + && IDENTIFIER_OPNAME_P (DECL_NAME (r)) + && !grok_op_properties (r, /*complain=*/false)) + RETURN (error_mark_node); + /* Set up the DECL_TEMPLATE_INFO for R. There's no need to do this in the special friend case mentioned above where GEN_TMPL is NULL. */ @@ -8808,9 +8816,10 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) if (PRIMARY_TEMPLATE_P (gen_tmpl)) clone_function_decl (r, /*update_method_vec_p=*/0); } - else if (IDENTIFIER_OPNAME_P (DECL_NAME (r)) - && !grok_op_properties (r, (complain & tf_error) != 0)) - return error_mark_node; + else if ((complain & tf_error) != 0 + && IDENTIFIER_OPNAME_P (DECL_NAME (r)) + && !grok_op_properties (r, /*complain=*/true)) + RETURN (error_mark_node); if (DECL_FRIEND_P (t) && DECL_FRIEND_CONTEXT (t)) SET_DECL_FRIEND_CONTEXT (r, @@ -8851,7 +8860,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) if (spec && TREE_CODE (spec) == PARM_DECL && TREE_CODE (TREE_TYPE (spec)) != TYPE_PACK_EXPANSION) - return spec; + RETURN (spec); /* Expand the TYPE_PACK_EXPANSION that provides the types for the parameters in this function parameter pack. */ @@ -8864,8 +8873,8 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) /* Zero-length parameter packs are boring. Just substitute into the chain. */ if (len == 0) - return tsubst (TREE_CHAIN (t), args, complain, - TREE_CHAIN (t)); + RETURN (tsubst (TREE_CHAIN (t), args, complain, + TREE_CHAIN (t))); } else { @@ -8955,7 +8964,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) r = copy_decl (t); type = tsubst (TREE_TYPE (t), args, complain, in_decl); if (type == error_mark_node) - return error_mark_node; + RETURN (error_mark_node); TREE_TYPE (r) = type; cp_apply_type_quals_to_decl (cp_type_quals (type), r); @@ -9018,7 +9027,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) we've copied the type for a typedef. */ type = tsubst (TREE_TYPE (t), args, complain, in_decl); if (type == error_mark_node) - return error_mark_node; + RETURN (error_mark_node); r = TYPE_NAME (type); break; } @@ -9091,7 +9100,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) DECL_INITIALIZED_P (r) = 0; DECL_TEMPLATE_INSTANTIATED (r) = 0; if (type == error_mark_node) - return error_mark_node; + RETURN (error_mark_node); if (TREE_CODE (type) == FUNCTION_TYPE) { /* It may seem that this case cannot occur, since: @@ -9111,7 +9120,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) /* R is not yet sufficiently initialized, so we just use its name. */ DECL_NAME (r)); - return error_mark_node; + RETURN (error_mark_node); } type = complete_type (type); DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (r) @@ -9207,7 +9216,9 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) default: gcc_unreachable (); } +#undef RETURN + out: /* Restore the file and line information. */ input_location = saved_loc; @@ -13307,6 +13318,105 @@ resolve_overloaded_unification (tree tparms, return false; } +/* Core DR 115: In contexts where deduction is done and fails, or in + contexts where deduction is not done, if a template argument list is + specified and it, along with any default template arguments, identifies + a single function template specialization, then the template-id is an + lvalue for the function template specialization. */ + +tree +resolve_nondeduced_context (tree orig_expr) +{ + tree expr, offset, baselink; + bool addr; + + if (!type_unknown_p (orig_expr)) + return orig_expr; + + expr = orig_expr; + addr = false; + offset = NULL_TREE; + baselink = NULL_TREE; + + if (TREE_CODE (expr) == ADDR_EXPR) + { + expr = TREE_OPERAND (expr, 0); + addr = true; + } + if (TREE_CODE (expr) == OFFSET_REF) + { + offset = expr; + expr = TREE_OPERAND (expr, 1); + } + if (TREE_CODE (expr) == BASELINK) + { + baselink = expr; + expr = BASELINK_FUNCTIONS (expr); + } + + if (TREE_CODE (expr) == TEMPLATE_ID_EXPR) + { + int good = 0; + tree goodfn = NULL_TREE; + + /* If we got some explicit template args, we need to plug them into + the affected templates before we try to unify, in case the + explicit args will completely resolve the templates in question. */ + + tree expl_subargs = TREE_OPERAND (expr, 1); + tree arg = TREE_OPERAND (expr, 0); + tree badfn = NULL_TREE; + tree badargs = NULL_TREE; + + for (; arg; arg = OVL_NEXT (arg)) + { + tree fn = OVL_CURRENT (arg); + tree subargs, elem; + + if (TREE_CODE (fn) != TEMPLATE_DECL) + continue; + + ++processing_template_decl; + subargs = get_bindings (fn, DECL_TEMPLATE_RESULT (fn), + expl_subargs, /*check_ret=*/false); + if (subargs && !any_dependent_template_arguments_p (subargs)) + { + elem = instantiate_template (fn, subargs, tf_none); + if (elem == error_mark_node) + { + badfn = fn; + badargs = subargs; + } + else if (elem && (!goodfn || !decls_match (goodfn, elem))) + { + goodfn = elem; + ++good; + } + } + --processing_template_decl; + } + if (good == 1) + { + expr = goodfn; + if (baselink) + expr = build_baselink (BASELINK_BINFO (baselink), + BASELINK_ACCESS_BINFO (baselink), + expr, BASELINK_OPTYPE (baselink)); + if (offset) + expr = build2 (OFFSET_REF, TREE_TYPE (expr), + TREE_OPERAND (offset, 0), expr); + if (addr) + expr = build_address (expr); + return expr; + } + else if (good == 0 && badargs) + /* There were no good options and at least one bad one, so let the + user know what the problem is. */ + instantiate_template (badfn, badargs, tf_warning_or_error); + } + return orig_expr; +} + /* Subroutine of resolve_overloaded_unification; does deduction for a single overload. Fills TARGS with any deduced arguments, or error_mark_node if different overloads deduce different arguments for a given parm. diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 391228b..6cf2220 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4741,6 +4741,7 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p) /* The type denoted by decltype(e) is defined as follows: */ + expr = resolve_nondeduced_context (expr); if (id_expression_or_member_access_p) { /* If e is an id-expression or a class member access (5.2.5 @@ -4766,9 +4767,13 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p) /* See through BASELINK nodes to the underlying functions. */ expr = BASELINK_FUNCTIONS (expr); + if (TREE_CODE (expr) == TEMPLATE_ID_EXPR) + expr = TREE_OPERAND (expr, 0); + if (TREE_CODE (expr) == OVERLOAD) { - if (OVL_CHAIN (expr)) + if (OVL_CHAIN (expr) + || TREE_CODE (OVL_FUNCTION (expr)) == TEMPLATE_DECL) { error ("%qE refers to a set of overloaded functions", orig_expr); return error_mark_node; diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 79b0201..526e706 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1613,6 +1613,7 @@ decay_conversion (tree exp) if (type == error_mark_node) return error_mark_node; + exp = resolve_nondeduced_context (exp); if (type_unknown_p (exp)) { cxx_incomplete_type_error (exp, TREE_TYPE (exp)); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index bf7e5ba..edfbe1d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2009-10-08 Jason Merrill + + PR c++/37177 + * g++.dg/cpp0x/variadic-throw.C: Adjust errors. + * g++.dg/template/explicit-args2.C: New. + * g++.dg/template/explicit-args3.C: New. + * g++.old-deja/g++.pt/crash58.C: Remove some errors. + 2009-10-08 Michael Matz PR middle-end/41573 diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-throw.C b/gcc/testsuite/g++.dg/cpp0x/variadic-throw.C index f2ff652..ee85bf2 100644 --- a/gcc/testsuite/g++.dg/cpp0x/variadic-throw.C +++ b/gcc/testsuite/g++.dg/cpp0x/variadic-throw.C @@ -8,7 +8,7 @@ template struct pair template struct S { - template static int foo() throw (pair ...) // { dg-error "mismatched|no matching" } + template static int foo() throw (pair ...) // { dg-error "mismatched" } { return 1; } @@ -21,5 +21,5 @@ int bar () int wibble() { - return S<0, 1, 2>::foo<0, 1> (); + return S<0, 1, 2>::foo<0, 1> (); // { dg-error "no matching" } } diff --git a/gcc/testsuite/g++.dg/template/explicit-args2.C b/gcc/testsuite/g++.dg/template/explicit-args2.C new file mode 100644 index 0000000..cd53b45 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/explicit-args2.C @@ -0,0 +1,38 @@ +// PR c++/37177 +// { dg-options -std=c++0x } + +namespace N1 +{ + template bool foo(); +} + +struct S +{ + template + static bool foo(); + + template + bool bar(); +}; + +template bool foo(); + +int main() +{ + (void)(&S::bar); + decltype(&S::bar) a; + + (void*)(&S::foo); + (void)(&S::foo); + decltype(&S::foo) b; + + (void*)(&N1::foo); + (void)(&N1::foo); + decltype(&N1::foo) c; + + (void*)(&foo); + (void)(&foo); + decltype(&foo) d; + + &foo == 0; +} diff --git a/gcc/testsuite/g++.dg/template/explicit-args3.C b/gcc/testsuite/g++.dg/template/explicit-args3.C new file mode 100644 index 0000000..c095e66 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/explicit-args3.C @@ -0,0 +1,12 @@ +// PR c++/37177 + +template +struct A { }; + +template +void operator+(T, T); // { dg-error "class or enum" } + +int main() +{ + operator+; // { dg-error "cannot resolve" } +} diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash58.C b/gcc/testsuite/g++.old-deja/g++.pt/crash58.C index 315f3e0..0ce3d81 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/crash58.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/crash58.C @@ -15,16 +15,16 @@ struct MatrixC { void foo () { EManip::do_assign (0); - &EManip::do_assign; // { dg-error "" } unresolved - &do_assign; // { dg-error "" } unresolved - EManip::do_assign; // { dg-error "" } unresolved - do_assign; // { dg-error "" } unresolved + &EManip::do_assign; // { dg-bogus "" } unresolved + &do_assign; // { dg-bogus "" } unresolved + EManip::do_assign; // { dg-bogus "" } unresolved + do_assign; // { dg-bogus "" } unresolved } }; void foo(MatrixC *ptr) { - EManip::do_assign; // { dg-error "" } unresolved - &EManip::do_assign; // { dg-error "" } unresolved + EManip::do_assign; // { dg-bogus "" } unresolved + &EManip::do_assign; // { dg-bogus "" } unresolved ptr->foo (); void (*p1) (int *) = &do_assign; // { dg-error "" } cannot convert void (*p2) (int *) = &EManip::do_assign; // { dg-error "" } cannot convert -- 2.7.4