c/ PR c++/69733 * c-decl.c (smallest_type_quals_location): New static function. (grokdeclarator): Try to find the correct location for an ignored qualifier. cp/ PR c++/69733 * decl.c (grokdeclarator): Try to find the correct location for an ignored qualifier. testsuite/ PR c++/69733 * c-c++-common/pr69733.c: New test. * gcc.dg/pr69733.c: New test. * gcc.target/i386/pr69733.c: New test. Index: gcc/c/c-decl.c =================================================================== --- gcc/c/c-decl.c (revision 238040) +++ gcc/c/c-decl.c (working copy) @@ -5463,6 +5463,27 @@ warn_defaults_to (location_t location, i va_end (ap); } +/* Returns the smallest location != UNKNOWN_LOCATION in LOCATIONS, + considering only those c_declspec_words found in LIST, which + must be terminated by cdw_number_of_elements. */ + +static location_t +smallest_type_quals_location (const location_t *locations, + const c_declspec_word *list) +{ + location_t loc = UNKNOWN_LOCATION; + while (*list != cdw_number_of_elements) + { + location_t newloc = locations[*list]; + if (loc == UNKNOWN_LOCATION + || (newloc != UNKNOWN_LOCATION && newloc < loc)) + loc = newloc; + list++; + } + + return loc; +} + /* Given declspecs and a declarator, determine the name and type of the object declared and construct a ..._DECL node for it. @@ -6277,7 +6298,19 @@ grokdeclarator (const struct c_declarato qualify the return type, not the function type. */ if (type_quals) { - int quals_used = type_quals; + const enum c_declspec_word ignored_quals_list[] = + { + cdw_const, cdw_volatile, cdw_restrict, cdw_address_space, + cdw_atomic, cdw_number_of_elements + }; + location_t specs_loc + = smallest_type_quals_location (declspecs->locations, + ignored_quals_list); + if (specs_loc == UNKNOWN_LOCATION) + specs_loc = declspecs->locations[cdw_typedef]; + if (specs_loc == UNKNOWN_LOCATION) + specs_loc = loc; + /* Type qualifiers on a function return type are normally permitted by the standard but have no effect, so give a warning at -Wreturn-type. @@ -6287,13 +6320,14 @@ grokdeclarator (const struct c_declarato DR#423 means qualifiers (other than _Atomic) are actually removed from the return type when determining the function type. */ + int quals_used = type_quals; if (flag_isoc11) quals_used &= TYPE_QUAL_ATOMIC; if (quals_used && VOID_TYPE_P (type) && really_funcdef) - pedwarn (loc, 0, + pedwarn (specs_loc, 0, "function definition has qualified void return type"); else - warning_at (loc, OPT_Wignored_qualifiers, + warning_at (specs_loc, OPT_Wignored_qualifiers, "type qualifiers ignored on function return type"); /* Ensure an error for restrict on invalid types; the Index: gcc/cp/decl.c =================================================================== --- gcc/cp/decl.c (revision 238040) +++ gcc/cp/decl.c (working copy) @@ -10089,8 +10089,15 @@ grokdeclarator (const cp_declarator *dec if (type_quals != TYPE_UNQUALIFIED) { if (SCALAR_TYPE_P (type) || VOID_TYPE_P (type)) - warning (OPT_Wignored_qualifiers, - "type qualifiers ignored on function return type"); + { + location_t loc; + loc = smallest_type_quals_location (type_quals, + declspecs->locations); + if (loc == UNKNOWN_LOCATION) + loc = declspecs->locations[ds_type_spec]; + warning_at (loc, OPT_Wignored_qualifiers, "type " + "qualifiers ignored on function return type"); + } /* We now know that the TYPE_QUALS don't apply to the decl, but to its return type. */ type_quals = TYPE_UNQUALIFIED; Index: gcc/testsuite/c-c++-common/pr69733.c =================================================================== --- gcc/testsuite/c-c++-common/pr69733.c (revision 0) +++ gcc/testsuite/c-c++-common/pr69733.c (working copy) @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-W -fdiagnostics-show-caret" } */ + +typedef const double cd; +double val; + +const double val0() {return val;} /* { dg-warning "qualifiers ignored" } */ +/* { dg-begin-multiline-output "" } + const double val0() {return val;} + ^~~~~ +{ dg-end-multiline-output "" } */ + +volatile double val1() {return val;} /* { dg-warning "qualifiers ignored" } */ +/* { dg-begin-multiline-output "" } + volatile double val1() {return val;} + ^~~~~~~~ +{ dg-end-multiline-output "" } */ + +cd val2() {return val;} /* { dg-warning "qualifiers ignored" } */ +/* { dg-begin-multiline-output "" } + cd val2() {return val;} + ^~ +{ dg-end-multiline-output "" } */ + Index: gcc/testsuite/gcc.dg/pr69733.c =================================================================== --- gcc/testsuite/gcc.dg/pr69733.c (revision 0) +++ gcc/testsuite/gcc.dg/pr69733.c (working copy) @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-W -fdiagnostics-show-caret" } */ + +double val; + +_Atomic double val0() {return val;} /* { dg-warning "qualifiers ignored" } */ +/* { dg-begin-multiline-output "" } + _Atomic double val0() {return val;} + ^~~~~~~ +{ dg-end-multiline-output "" } */ + Index: gcc/testsuite/gcc.target/i386/pr69733.c =================================================================== --- gcc/testsuite/gcc.target/i386/pr69733.c (revision 0) +++ gcc/testsuite/gcc.target/i386/pr69733.c (working copy) @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-W -fdiagnostics-show-caret" } */ + +typedef const double cd; +double val; + +const double val0() {return val;} /* { dg-warning "qualifiers ignored" } */ +/* { dg-begin-multiline-output "" } + const double val0() {return val;} + ^~~~~ +{ dg-end-multiline-output "" } */ + +volatile double val1() {return val;} /* { dg-warning "qualifiers ignored" } */ +/* { dg-begin-multiline-output "" } + volatile double val1() {return val;} + ^~~~~~~~ +{ dg-end-multiline-output "" } */ + +cd val2() {return val;} /* { dg-warning "qualifiers ignored" } */ +/* { dg-begin-multiline-output "" } + cd val2() {return val;} + ^~ +{ dg-end-multiline-output "" } */ + +__seg_fs int val3() {return val;} /* { dg-warning "qualifiers ignored" } */ +/* { dg-begin-multiline-output "" } + __seg_fs int val3() {return val;} + ^~~~~~~~ +{ dg-end-multiline-output "" } */ +