From 6853b04cdd6269c596bf4dd24b41eee2170caef3 Mon Sep 17 00:00:00 2001 From: Paolo Carlini Date: Tue, 1 Sep 2015 08:39:47 +0000 Subject: [PATCH] re PR c++/61753 (poor diagnostic for constructor definition that starts with 'const') /cp 2015-09-01 Paolo Carlini PR c++/61753 * decl.c (smallest_type_quals_location): New. (check_special_function_return_type): Use the latter; add int and const location_t* parameters. (grokdeclarator): Adjust check_special_function_return_type call. /testsuite 2015-09-01 Paolo Carlini PR c++/61753 * g++.dg/other/pr61753.C: New. From-SVN: r227361 --- gcc/cp/ChangeLog | 8 +++ gcc/cp/decl.c | 85 ++++++++++++++++++++-------- gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/g++.dg/other/pr61753.C | 31 ++++++++++ 4 files changed, 105 insertions(+), 24 deletions(-) create mode 100644 gcc/testsuite/g++.dg/other/pr61753.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 7cbfa6591f1..477bb209388 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2015-09-01 Paolo Carlini + + PR c++/61753 + * decl.c (smallest_type_quals_location): New. + (check_special_function_return_type): Use the latter; add int and + const location_t* parameters. + (grokdeclarator): Adjust check_special_function_return_type call. + 2015-08-29 Markus Trippelsdorf PR c++/67371 diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 205febc1dad..96d735a3692 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -113,7 +113,7 @@ static void end_cleanup_fn (void); static tree cp_make_fname_decl (location_t, tree, int); static void initialize_predefined_identifiers (void); static tree check_special_function_return_type - (special_function_kind, tree, tree); + (special_function_kind, tree, tree, int, const location_t*); static tree push_cp_library_fn (enum tree_code, tree, int); static tree build_cp_library_fn (tree, enum tree_code, tree, int); static void store_parm_decls (tree); @@ -8924,24 +8924,51 @@ create_array_type_for_decl (tree name, tree type, tree size) return build_cplus_array_type (type, itype); } -/* Check that it's OK to declare a function with the indicated TYPE. - SFK indicates the kind of special function (if any) that this - function is. OPTYPE is the type given in a conversion operator - declaration, or the class type for a constructor/destructor. - Returns the actual return type of the function; that - may be different than TYPE if an error occurs, or for certain - special functions. */ +/* Returns the smallest location != UNKNOWN_LOCATION among the + three stored in LOCATIONS[ds_const], LOCATIONS[ds_volatile], + and LOCATIONS[ds_restrict]. */ + +static location_t +smallest_type_quals_location (int type_quals, const location_t* locations) +{ + location_t loc = UNKNOWN_LOCATION; + + if (type_quals & TYPE_QUAL_CONST) + loc = locations[ds_const]; + + if ((type_quals & TYPE_QUAL_VOLATILE) + && (loc == UNKNOWN_LOCATION || locations[ds_volatile] < loc)) + loc = locations[ds_volatile]; + + if ((type_quals & TYPE_QUAL_RESTRICT) + && (loc == UNKNOWN_LOCATION || locations[ds_restrict] < loc)) + loc = locations[ds_restrict]; + + return loc; +} + +/* Check that it's OK to declare a function with the indicated TYPE + and TYPE_QUALS. SFK indicates the kind of special function (if any) + that this function is. OPTYPE is the type given in a conversion + operator declaration, or the class type for a constructor/destructor. + Returns the actual return type of the function; that may be different + than TYPE if an error occurs, or for certain special functions. */ static tree check_special_function_return_type (special_function_kind sfk, tree type, - tree optype) + tree optype, + int type_quals, + const location_t* locations) { switch (sfk) { case sfk_constructor: if (type) error ("return type specification for constructor invalid"); + else if (type_quals != TYPE_UNQUALIFIED) + error_at (smallest_type_quals_location (type_quals, locations), + "qualifiers are not allowed on constructor declaration"); if (targetm.cxx.cdtor_returns_this () && !TYPE_FOR_JAVA (optype)) type = build_pointer_type (optype); @@ -8952,6 +8979,10 @@ check_special_function_return_type (special_function_kind sfk, case sfk_destructor: if (type) error ("return type specification for destructor invalid"); + else if (type_quals != TYPE_UNQUALIFIED) + error_at (smallest_type_quals_location (type_quals, locations), + "qualifiers are not allowed on destructor declaration"); + /* We can't use the proper return type here because we run into problems with ambiguous bases and covariant returns. Java classes are left unchanged because (void *) isn't a valid @@ -8964,7 +8995,12 @@ check_special_function_return_type (special_function_kind sfk, case sfk_conversion: if (type) - error ("return type specified for %", optype); + error ("return type specified for %", optype); + else if (type_quals != TYPE_UNQUALIFIED) + error_at (smallest_type_quals_location (type_quals, locations), + "qualifiers are not allowed on declaration of " + "%", optype); + type = optype; break; @@ -9090,7 +9126,7 @@ grokdeclarator (const cp_declarator *declarator, a member function. */ cp_ref_qualifier rqual = REF_QUAL_NONE; /* cv-qualifiers that apply to the type specified by the DECLSPECS. */ - int type_quals; + int type_quals = TYPE_UNQUALIFIED; tree raises = NULL_TREE; int template_count = 0; tree returned_attrs = NULL_TREE; @@ -9137,6 +9173,13 @@ grokdeclarator (const cp_declarator *declarator, if (concept_p) constexpr_p = true; + if (decl_spec_seq_has_spec_p (declspecs, ds_const)) + type_quals |= TYPE_QUAL_CONST; + if (decl_spec_seq_has_spec_p (declspecs, ds_volatile)) + type_quals |= TYPE_QUAL_VOLATILE; + if (decl_spec_seq_has_spec_p (declspecs, ds_restrict)) + type_quals |= TYPE_QUAL_RESTRICT; + if (decl_context == FUNCDEF) funcdef_flag = true, decl_context = NORMAL; else if (decl_context == MEMFUNCDEF) @@ -9462,8 +9505,13 @@ grokdeclarator (const cp_declarator *declarator, ctor_return_type = ctype; if (sfk != sfk_none) - type = check_special_function_return_type (sfk, type, - ctor_return_type); + { + type = check_special_function_return_type (sfk, type, + ctor_return_type, + type_quals, + declspecs->locations); + type_quals = TYPE_UNQUALIFIED; + } else if (type == NULL_TREE) { int is_main; @@ -9648,17 +9696,6 @@ grokdeclarator (const cp_declarator *declarator, type = build_complex_type (type); } - type_quals = TYPE_UNQUALIFIED; - if (decl_spec_seq_has_spec_p (declspecs, ds_const)) - type_quals |= TYPE_QUAL_CONST; - if (decl_spec_seq_has_spec_p (declspecs, ds_volatile)) - type_quals |= TYPE_QUAL_VOLATILE; - if (decl_spec_seq_has_spec_p (declspecs, ds_restrict)) - type_quals |= TYPE_QUAL_RESTRICT; - if (sfk == sfk_conversion && type_quals != TYPE_UNQUALIFIED) - error ("qualifiers are not allowed on declaration of %", - ctor_return_type); - /* If we're using the injected-class-name to form a compound type or a declaration, replace it with the underlying class so we don't get redundant typedefs in the debug output. But if we are returning the diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 15dc00dd211..b9d9f84ba74 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2015-09-01 Paolo Carlini + + PR c++/61753 + * g++.dg/other/pr61753.C: New. + 2015-08-31 Marc Glisse * gcc.dg/tree-ssa/cmp-1.c: New file. diff --git a/gcc/testsuite/g++.dg/other/pr61753.C b/gcc/testsuite/g++.dg/other/pr61753.C new file mode 100644 index 00000000000..6c6a738e07e --- /dev/null +++ b/gcc/testsuite/g++.dg/other/pr61753.C @@ -0,0 +1,31 @@ +// PR c++/61753 + +class Rulec { + Rulec(); +}; + +const Rulec::Rulec() { } // { dg-error "1:qualifiers" } + +class Rulev { + Rulev(); +}; + +volatile Rulev::Rulev() { } // { dg-error "1:qualifiers" } + +class Ruler { + Ruler(); +}; + +__restrict Ruler::Ruler() { } // { dg-error "1:qualifiers" } + +class Rulecvr { + Rulecvr(); +}; + +const volatile __restrict Rulecvr::Rulecvr() { } // { dg-error "1:qualifiers" } + +class Rulervc { + Rulervc(); +}; + +__restrict volatile const Rulervc::Rulervc() { } // { dg-error "1:qualifiers" } -- 2.30.2