https://gcc.gnu.org/g:9d27750d153dd4147eebe6b30d3e18f7cb3d7384
commit r16-6778-g9d27750d153dd4147eebe6b30d3e18f7cb3d7384 Author: David Malcolm <[email protected]> Date: Wed Jan 14 11:43:57 2026 -0500 c++: use nesting and counts in print_candidates In r15-6116-gd3dd24acd74605 I updated print_z_candidates to print a count of the number of candidates, and to show the number of each candidate in the list if there is more than one. The following patch updates print_candidates to work in a similar way, showing counts, numbering, and using nesting. Consider this test case for which we print 2 candidates: class foo { public: void test (int i, int j, void *ptr, int k); void test (int i, int j, int k); }; // Wrong "const"-ness of a param, for one of the overloads (param 3). void foo::test (int i, int j, const void *ptr, int k) { } The output before the patch is: test.cc:9:6: error: no declaration matches ‘void foo::test(int, int, const void*, int)’ 9 | void foo::test (int i, int j, const void *ptr, int k) | ^~~ test.cc:5:8: note: candidates are: ‘void foo::test(int, int, int)’ 5 | void test (int i, int j, int k); | ^~~~ test.cc:4:8: note: ‘void foo::test(int, int, void*, int)’ 4 | void test (int i, int j, void *ptr, int k); | ^~~~ test.cc:1:7: note: ‘class foo’ defined here 1 | class foo | ^~~ With the patch, the output looks like: test.cc:9:6: error: no declaration matches ‘void foo::test(int, int, const void*, int)’ 9 | void foo::test (int i, int j, const void *ptr, int k) | ^~~ • there are 2 candidates • candidate 1: ‘void foo::test(int, int, int)’ test.cc:5:8: 5 | void test (int i, int j, int k); | ^~~~ • candidate 2: ‘void foo::test(int, int, void*, int)’ test.cc:4:8: 4 | void test (int i, int j, void *ptr, int k); | ^~~~ test.cc:1:7: note: ‘class foo’ defined here 1 | class foo | ^~~ which I believe is much more readable. I dabbled with removing the "there is 1 candidate" line for the case of a single candidate, but I think I prefer it to be present. FWIW I've been experimenting with followups that * show more nested information about the problems (e.g. the "void *" vs "const void *" mismatch) - having the candidates be nested is a useful step towards that * potentially look at the "edit distance" of the type signatures to find close matches, and perhaps reordering/highlighting them (e.g. in the above candidate 2 is arguably a closer match than candidate 1, due to the "const" snafu) - gathering an auto_vec might help with that. gcc/cp/ChangeLog: * call.cc (print_z_candidates): Move inform_n call into a new inform_num_candidates function. * class.cc (check_methods): Pass location to call to print_candidates. (resolve_address_of_overloaded_function): Likewise. * cp-tree.h (print_candidates): Add location_t param. (inform_num_candidates): New decl. * decl.cc (make_typename_type): Pass location to call to print_candidates. (reshape_init_class): Likewise. (lookup_and_check_tag): Likewise. * decl2.cc (check_classfn): Likewise. * error.cc (qualified_name_lookup_error): Likewise. * init.cc (build_new_1): Likewise. * name-lookup.cc (lookup_using_decl): Likewise. (set_decl_namespace): Likewise. (push_namespace): Likewise. * parser.cc (cp_parser_nested_name_specifier_opt): Likewise. (cp_parser_lookup_name): Likewise. * pt.cc (print_candidates_1): Drop, converting the looping part into... (flatten_candidates): ...this new function. (inform_num_candidates): New function. (print_candidates): Use flatten_candidates to build an auto_vec of candidates, and use this to print them here, rather than in print_candidates_1. Eliminate the dynamic allocation of spaces for a prefix in favor of printing "candidate %i" when there is more than one candidate. Add "error_loc" param and pass it to inform_num_candidates to show a heading, and add nesting levels for it and for the candidate notes. (determine_specialization): Pass location to calls to print_candidates. * search.cc (lookup_member): Likewise. * semantics.cc (finish_id_expression_1): Likewise. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/inline-ns2.C: Make dg-message directives non-empty. * g++.dg/cpp23/explicit-obj-lambda11.C: Prune the extra note. * g++.dg/diagnostic/bad-fndef-1.C: New test. * g++.dg/lookup/decl1.C: Give the dg-message directives different messages. * g++.dg/lookup/using17.C: Update expected output. * g++.dg/parse/non-dependent2.C: Likewise. * g++.old-deja/g++.other/lineno2.C: Give the dg-message directives different messages. * g++.old-deja/g++.pt/t37.C: Likewise. Signed-off-by: David Malcolm <[email protected]> Diff: --- gcc/cp/call.cc | 5 +- gcc/cp/class.cc | 6 +- gcc/cp/cp-tree.h | 3 +- gcc/cp/decl.cc | 6 +- gcc/cp/decl2.cc | 2 +- gcc/cp/error.cc | 2 +- gcc/cp/init.cc | 2 +- gcc/cp/name-lookup.cc | 7 ++- gcc/cp/parser.cc | 5 +- gcc/cp/pt.cc | 73 ++++++++++++---------- gcc/cp/search.cc | 2 +- gcc/cp/semantics.cc | 2 +- gcc/testsuite/g++.dg/cpp0x/inline-ns2.C | 18 +++--- gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda11.C | 2 +- gcc/testsuite/g++.dg/diagnostic/bad-fndef-1.C | 15 +++++ gcc/testsuite/g++.dg/lookup/decl1.C | 8 +-- gcc/testsuite/g++.dg/lookup/using17.C | 4 +- gcc/testsuite/g++.dg/parse/non-dependent2.C | 2 +- gcc/testsuite/g++.old-deja/g++.other/lineno2.C | 8 +-- gcc/testsuite/g++.old-deja/g++.pt/t37.C | 10 +-- 20 files changed, 104 insertions(+), 78 deletions(-) diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 34d23e998490..d0386eaebcc8 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -4261,9 +4261,8 @@ print_z_candidates (location_t loc, struct z_candidate *candidates, ++num_candidates; } - inform_n (loc, - num_candidates, "there is %i candidate", "there are %i candidates", - num_candidates); + inform_num_candidates (loc, num_candidates); + auto_diagnostic_nesting_level sentinel2; int candidate_idx = 0; diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc index adffd35123c6..2a65ffb1c009 100644 --- a/gcc/cp/class.cc +++ b/gcc/cp/class.cc @@ -5138,7 +5138,7 @@ check_methods (tree t) error_at (location_of (t), "no viable destructor for %qT", t); else error_at (location_of (t), "destructor for %qT is ambiguous", t); - print_candidates (dtor); + print_candidates (location_of (t), dtor); /* Arbitrarily prune the overload set to a single function for sake of error recovery. */ @@ -9115,7 +9115,7 @@ resolve_address_of_overloaded_function (tree target_type, error ("no matches converting function %qD to type %q#T", OVL_NAME (overload), target_type); - print_candidates (overload); + print_candidates (input_location, overload); } return error_mark_node; } @@ -9147,7 +9147,7 @@ resolve_address_of_overloaded_function (tree target_type, for (match = matches; match; match = TREE_CHAIN (match)) TREE_VALUE (match) = TREE_PURPOSE (match); - print_candidates (matches); + print_candidates (input_location, matches); } return error_mark_node; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6bd5b1696c4f..0fdcb537708c 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7947,7 +7947,8 @@ extern tree maybe_process_partial_specialization (tree); extern tree most_specialized_instantiation (tree); extern tree most_specialized_partial_spec (tree, tsubst_flags_t, bool = false); extern tree most_constrained_function (tree); -extern void print_candidates (tree); +extern void inform_num_candidates (location_t, int); +extern void print_candidates (location_t, tree); extern void instantiate_pending_templates (int); extern tree tsubst_default_argument (tree, int, tree, tree, tsubst_flags_t); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 567aa7abe42a..46a17a596edc 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -5066,7 +5066,7 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, { auto_diagnostic_group d; error ("lookup of %qT in %qT is ambiguous", name, context); - print_candidates (t); + print_candidates (input_location, t); } return error_mark_node; } @@ -7775,7 +7775,7 @@ reshape_init_class (tree type, reshape_iter *d, bool first_initializer_p, auto_diagnostic_group g; error ("request for member %qD is ambiguous", d->cur->index); - print_candidates (field); + print_candidates (input_location, field); } else error ("%qT has no non-static data member named %qD", type, @@ -18105,7 +18105,7 @@ lookup_and_check_tag (enum tag_types tag_code, tree name, { auto_diagnostic_group d; error ("reference to %qD is ambiguous", name); - print_candidates (decl); + print_candidates (input_location, decl); return error_mark_node; } diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index af2b921268d6..69551e5f3741 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -917,7 +917,7 @@ check_classfn (tree ctype, tree function, tree template_parms) error_at (DECL_SOURCE_LOCATION (function), "no declaration matches %q#D", function); if (fns) - print_candidates (fns); + print_candidates (DECL_SOURCE_LOCATION (function), fns); else if (DECL_CONV_FN_P (function)) inform (DECL_SOURCE_LOCATION (function), "no conversion operators declared"); diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc index e23ea9aa48ce..c51725555a9d 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -4988,7 +4988,7 @@ qualified_name_lookup_error (tree scope, tree name, auto_diagnostic_group d; error_at (location, "reference to %<%T::%D%> is ambiguous", scope, name); - print_candidates (decl); + print_candidates (location, decl); } else { diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc index 79672e98de43..01e3d007a491 100644 --- a/gcc/cp/init.cc +++ b/gcc/cp/init.cc @@ -3430,7 +3430,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, { auto_diagnostic_group d; error ("request for member %qD is ambiguous", fnname); - print_candidates (fns); + print_candidates (input_location, fns); } return error_mark_node; } diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index eb6a18a18ad5..8847acc693c1 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -6336,7 +6336,8 @@ lookup_using_decl (tree scope, name_lookup &lookup) { auto_diagnostic_group d; error ("reference to %qD is ambiguous", lookup.name); - print_candidates (TREE_CODE (lookup.value) == TREE_LIST + print_candidates (input_location, + TREE_CODE (lookup.value) == TREE_LIST ? lookup.value : lookup.type); return NULL_TREE; } @@ -6469,7 +6470,7 @@ set_decl_namespace (tree decl, tree scope, bool friendp) auto_diagnostic_group d; DECL_CONTEXT (decl) = FROB_CONTEXT (scope); error ("reference to %qD is ambiguous", decl); - print_candidates (old); + print_candidates (input_location, old); return; } @@ -9367,7 +9368,7 @@ push_namespace (tree name, bool make_inline) if (TREE_CHAIN (lookup.value)) { error ("%<namespace %E%> is ambiguous", name); - print_candidates (lookup.value); + print_candidates (input_location, lookup.value); } } else if (TREE_CODE (lookup.value) == NAMESPACE_DECL) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index c02bd1a3fce0..2dc4863ec528 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -7607,7 +7607,8 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, error_at (token->location, "reference to %qD is ambiguous", token->u.value); - print_candidates (ambiguous_decls); + print_candidates (token->location, + ambiguous_decls); } decl = error_mark_node; } @@ -34347,7 +34348,7 @@ cp_parser_lookup_name (cp_parser *parser, tree name, auto_diagnostic_group d; error_at (name_location, "reference to %qD is ambiguous", name); - print_candidates (decl); + print_candidates (name_location, decl); } return error_mark_node; } diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index bc735cfcf602..49db5f17a545 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -2038,50 +2038,59 @@ explicit_class_specialization_p (tree type) return !uses_template_parms (CLASSTYPE_TI_ARGS (type)); } -/* Print the list of functions at FNS, going through all the overloads - for each element of the list. Alternatively, FNS cannot be a - TREE_LIST, in which case it will be printed together with all the - overloads. - - MORE and *STR should respectively be FALSE and NULL when the function - is called from the outside. They are used internally on recursive - calls. print_candidates manages the two parameters and leaves NULL - in *STR when it ends. */ +/* Populate OUT with the overload set FNS, going through all the + overloads for each element of the list. Alternatively, FNS can be a + TREE_LIST, in which case it will be added together with all the + overloads. */ static void -print_candidates_1 (tree fns, char **str, bool more = false) +flatten_candidates (tree fns, auto_vec<tree> &out) { if (TREE_CODE (fns) == TREE_LIST) for (; fns; fns = TREE_CHAIN (fns)) - print_candidates_1 (TREE_VALUE (fns), str, more || TREE_CHAIN (fns)); + flatten_candidates (TREE_VALUE (fns), out); else - for (lkp_iterator iter (fns); iter;) - { - tree cand = *iter; - ++iter; + for (tree cand : lkp_range (fns)) + out.safe_push (cand); +} - const char *pfx = *str; - if (!pfx) - { - if (more || iter) - pfx = _("candidates are:"); - else - pfx = _("candidate is:"); - *str = get_spaces (pfx); - } - inform (DECL_SOURCE_LOCATION (cand), "%s %#qD", pfx, cand); - } +/* Print a note announcing a list of candidates. */ + +void +inform_num_candidates (location_t loc, int num_candidates) +{ + inform_n (loc, + num_candidates, "there is %i candidate", "there are %i candidates", + num_candidates); } /* Print the list of candidate FNS in an error message. FNS can also be a TREE_LIST of non-functions in the case of an ambiguous lookup. */ void -print_candidates (tree fns) +print_candidates (location_t error_loc, tree fns) { - char *str = NULL; - print_candidates_1 (fns, &str); - free (str); + auto_vec<tree> candidates; + flatten_candidates (fns, candidates); + + auto_diagnostic_nesting_level sentinel; + + inform_num_candidates (error_loc, candidates.length ()); + + auto_diagnostic_nesting_level sentinel2; + + if (candidates.length () == 1) + { + tree cand = candidates[0]; + inform (DECL_SOURCE_LOCATION (cand), "candidate is: %#qD", cand); + } + else + { + int idx = 0; + for (tree cand : candidates) + inform (DECL_SOURCE_LOCATION (cand), "candidate %i: %#qD", + ++idx, cand); + } } /* Get a (possibly) constrained template declaration for the @@ -2505,7 +2514,7 @@ determine_specialization (tree template_id, "saw %d %<template<>%>, need %d for " "specializing a member function template", header_count, template_count + 1); - print_candidates (orig_fns); + print_candidates (DECL_SOURCE_LOCATION (decl), orig_fns); return error_mark_node; } else if ((templates && TREE_CHAIN (templates)) @@ -2516,7 +2525,7 @@ determine_specialization (tree template_id, error ("ambiguous template specialization %qD for %q+D", template_id, decl); candidates = chainon (candidates, templates); - print_candidates (candidates); + print_candidates (input_location, candidates); return error_mark_node; } diff --git a/gcc/cp/search.cc b/gcc/cp/search.cc index 0ded47807298..db7c2d7702a5 100644 --- a/gcc/cp/search.cc +++ b/gcc/cp/search.cc @@ -1243,7 +1243,7 @@ lookup_member (tree xbasetype, tree name, int protect, bool want_type, { auto_diagnostic_group d; error ("request for member %qD is ambiguous", name); - print_candidates (lfi.ambiguous); + print_candidates (input_location, lfi.ambiguous); } return error_mark_node; } diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 3e9da8d24396..78d717cade3b 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -4934,7 +4934,7 @@ finish_id_expression_1 (tree id_expression, auto_diagnostic_group d; error ("request for member %qD is ambiguous in " "multiple inheritance lattice", id_expression); - print_candidates (decl); + print_candidates (input_location, decl); return error_mark_node; } diff --git a/gcc/testsuite/g++.dg/cpp0x/inline-ns2.C b/gcc/testsuite/g++.dg/cpp0x/inline-ns2.C index 6ad9d65a6fbb..1dc8efeb329f 100644 --- a/gcc/testsuite/g++.dg/cpp0x/inline-ns2.C +++ b/gcc/testsuite/g++.dg/cpp0x/inline-ns2.C @@ -2,17 +2,17 @@ namespace Q { inline namespace V1 { - extern int i; // { dg-message "" } - extern int j; // { dg-message "" } - void f(); // { dg-message "" } - void g(); // { dg-message "" } + extern int i; // { dg-message "candidate" } + extern int j; // { dg-message "candidate" } + void f(); // { dg-message "candidate" } + void g(); // { dg-message "candidate" } } inline namespace V2 { - extern int j; // { dg-message "" } - void g(); // { dg-message "" } + extern int j; // { dg-message "candidate" } + void g(); // { dg-message "candidate" } } - extern int i; // { dg-message "" } - void f(); // { dg-message "" } + extern int i; // { dg-message "candidate" } + void f(); // { dg-message "candidate" } void h(); } namespace R { @@ -22,4 +22,4 @@ int Q::i = 1; // { dg-error "ambiguous" } int Q::j = 1; // { dg-error "ambiguous" } void Q::f() { } // { dg-error "ambiguous" } void Q::g() { } // { dg-error "ambiguous" } -void R::h() { } // { dg-error "" } +void R::h() { } // { dg-error "should have been declared inside 'R'" } diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda11.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda11.C index 7957ad3e1943..731caf16effa 100644 --- a/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda11.C +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda11.C @@ -40,8 +40,8 @@ void test2() int (*fp0)(decltype(f)&) = &decltype(f)::operator(); int (*fp1)(int&) = &decltype(f)::operator(); // { dg-error {no matches converting function} } + // { dg-note "there is 1 candidate" "" { target *-*-* } .-1 } } // { dg-error "a lambda with captures may not have an explicit object parameter of an unrelated type" {depends on PR112874} { xfail *-*-* } t2_f } // { dg-note "candidate is" "" { target *-*-* } t2_f } - diff --git a/gcc/testsuite/g++.dg/diagnostic/bad-fndef-1.C b/gcc/testsuite/g++.dg/diagnostic/bad-fndef-1.C new file mode 100644 index 000000000000..1156072b11f1 --- /dev/null +++ b/gcc/testsuite/g++.dg/diagnostic/bad-fndef-1.C @@ -0,0 +1,15 @@ +class foo // { dg-message "'class foo' defined here" } +{ +public: + void test (int i, int j, void *ptr, int k); // { dg-line close_decl } + void test (int i, int j, int k); // { dg-line other_decl } +}; + +// Wrong "const"-ness of a param, for one of the overloads (param 3). +void foo::test (int i, int j, const void *ptr, int k) // { dg-line defn } +{ +} + +// { dg-error "6: no declaration matches" "error" { target *-*-* } defn } +// { dg-message "8: candidate 1: " "candidate 1" { target *-*-* } other_decl } +// { dg-message "8: candidate 2: " "candidate 2" { target *-*-* } close_decl } diff --git a/gcc/testsuite/g++.dg/lookup/decl1.C b/gcc/testsuite/g++.dg/lookup/decl1.C index 205ffcff1d73..38319ba923de 100644 --- a/gcc/testsuite/g++.dg/lookup/decl1.C +++ b/gcc/testsuite/g++.dg/lookup/decl1.C @@ -20,10 +20,10 @@ C2<X>::operator C1<Y>() } struct A { // { dg-message "defined here" } - operator int (); // { dg-message "operator" } - operator float (); // { dg-message "operator" } - operator float () const; // { dg-message "operator" } - template <typename T> operator T * (); // { dg-message "operator" } + operator int (); // { dg-message "operator int" } + operator float (); // { dg-message "operator float" } + operator float () const; // { dg-message "operator float" } + template <typename T> operator T * (); // { dg-message "operator T" } }; A::operator short () { // { dg-error "no declaration matches" } diff --git a/gcc/testsuite/g++.dg/lookup/using17.C b/gcc/testsuite/g++.dg/lookup/using17.C index 55875fe9af97..374dcfa8f25a 100644 --- a/gcc/testsuite/g++.dg/lookup/using17.C +++ b/gcc/testsuite/g++.dg/lookup/using17.C @@ -3,11 +3,11 @@ // { dg-do compile } namespace M { - struct S {}; // { dg-message "candidates are: .struct M::S." "candidate 1" } + struct S {}; // { dg-message "candidate 1: 'struct M::S'" } } int S; -struct S {}; // { dg-message ".struct S." "candidate 2" } +struct S {}; // { dg-message "candidate 2: 'struct S'" } using namespace M; diff --git a/gcc/testsuite/g++.dg/parse/non-dependent2.C b/gcc/testsuite/g++.dg/parse/non-dependent2.C index c22497044e90..eb83390206c5 100644 --- a/gcc/testsuite/g++.dg/parse/non-dependent2.C +++ b/gcc/testsuite/g++.dg/parse/non-dependent2.C @@ -15,7 +15,7 @@ struct Foo { struct Baz { int j; - int k; // { dg-message "candidates" } + int k; // { dg-message "candidate" } }; diff --git a/gcc/testsuite/g++.old-deja/g++.other/lineno2.C b/gcc/testsuite/g++.old-deja/g++.other/lineno2.C index d6aca8b9cfd0..6434f9ac45ce 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/lineno2.C +++ b/gcc/testsuite/g++.old-deja/g++.other/lineno2.C @@ -2,14 +2,14 @@ // Submitted by Nathan Sidwell <[email protected]> // Bug: g++ wasn't listing candidates for a failed conversion. -void f(int, double); // { dg-message "" } candidate -void f(double, int); // { dg-message "" } candidate -void f(int); // { dg-message "" } candidate +void f(int, double); // { dg-message "candidate" } +void f(double, int); // { dg-message "candidate" } +void f(int); // { dg-message "candidate" } int main () { void (*ptr)(int, int); - ptr = &f; // { dg-error "" } no match + ptr = &f; // { dg-error "no matches" } } diff --git a/gcc/testsuite/g++.old-deja/g++.pt/t37.C b/gcc/testsuite/g++.old-deja/g++.pt/t37.C index dbf1f4403b31..ffef5e58a438 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/t37.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/t37.C @@ -1,14 +1,14 @@ // { dg-do compile } -class A { // { dg-message "A::A" } synthesized copy ctor - // { dg-message "defined here" "note" { target *-*-* } .-1 } +class A { // { dg-message "A::A\\\(const A&\\\)" } synthesized copy ctor + // { dg-message "'class A' defined here" "note" { target *-*-* } .-1 } public: - A(int); // { dg-message "A::A" } - A(float); // { dg-message "A::A" } + A(int); // { dg-message "A::A\\\(int\\\)" } + A(float); // { dg-message "A::A\\\(float\\\)" } ~A(); }; -A::A() { // { dg-error "" } +A::A() { // { dg-error "no declaration matches" } } A::A(int) {
