[v2] c++: Fix missing NSDMI diagnostic in C++98 [PR103347]
Commit Message
On Tue, Nov 23, 2021 at 02:42:12PM -0500, Jason Merrill wrote:
> On 11/22/21 17:17, Marek Polacek wrote:
> > Here the problem is that we aren't detecting a NSDMI in C++98:
> >
> > struct A {
> > void *x = NULL;
> > };
> >
> > because maybe_warn_cpp0x uses input_location and that happens to point
> > to NULL which comes from a system header. Jakub suggested changing the
> > location to the '=', thereby avoiding the system header problem. To
> > that end, I've added a new location_t member into cp_declarator. This
> > member is used when this declarator is part of an init-declarator. The
> > rest of the changes is obvious. I've also taken the liberty of adding
> > loc_or_input_loc, since I want to avoid checking for UNKNOWN_LOCATION.
> >
> > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> >
> > PR c++/103347
> >
> > gcc/cp/ChangeLog:
> >
> > * cp-tree.h (struct cp_declarator): Add a location_t member.
> > (maybe_warn_cpp0x): Add a location_t parameter with a default argument.
> > (loc_or_input_loc): New.
> > * decl.c (grokdeclarator): Use loc_or_input_loc. Pass init_loc down
> > to maybe_warn_cpp0x.
> > * error.c (maybe_warn_cpp0x): Add a location_t parameter. Use it.
> > * parser.c (make_declarator): Initialize init_loc.
> > (cp_parser_member_declaration): Set init_loc.
> >
> > gcc/testsuite/ChangeLog:
> >
> > * g++.dg/cpp0x/nsdmi-warn1.C: New test.
> > * g++.dg/cpp0x/nsdmi-warn1.h: New file.
> > ---
> > gcc/cp/cp-tree.h | 16 +++++++++---
> > gcc/cp/decl.c | 22 +++++++++-------
> > gcc/cp/error.c | 32 ++++++++++++------------
> > gcc/cp/parser.c | 2 ++
> > gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.C | 10 ++++++++
> > gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.h | 2 ++
> > 6 files changed, 55 insertions(+), 29 deletions(-)
> > create mode 100644 gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.C
> > create mode 100644 gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.h
> >
> > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> > index 3f56cb90d14..2037082b0c7 100644
> > --- a/gcc/cp/cp-tree.h
> > +++ b/gcc/cp/cp-tree.h
> > @@ -6231,9 +6231,11 @@ struct cp_declarator {
> > /* If this declarator is parenthesized, this the open-paren. It is
> > UNKNOWN_LOCATION when not parenthesized. */
> > location_t parenthesized;
> > -
> > - location_t id_loc; /* Currently only set for cdk_id, cdk_decomp and
> > - cdk_function. */
> > + /* Currently only set for cdk_id, cdk_decomp and cdk_function. */
> > + location_t id_loc;
> > + /* If this declarator is part of an init-declarator, the location of the
> > + initializer. */
>
> Currently this comment is inaccurate because we don't set it for all
> init-declarators. That should be pretty trivial to do, even if we don't use
> the location yet in other contexts.
The following patch sets ->init_loc in a few more spots. I've looked
at every cp_parser_declarator call and if it's followed by a =/{, I
set ->init_loc. Pedantically, it's also an init-declarator if the
declarator is followed by a requires-clause, but I've not looked for
those cases.
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
-- >8 --
Here the problem is that we aren't detecting a NSDMI in C++98:
struct A {
void *x = NULL;
};
because maybe_warn_cpp0x uses input_location and that happens to point
to NULL which comes from a system header. Jakub suggested changing the
location to the '=', thereby avoiding the system header problem. To
that end, I've added a new location_t member into cp_declarator. This
member is used when this declarator is part of an init-declarator. The
rest of the changes is obvious. I've also taken the liberty of adding
loc_or_input_loc, since I want to avoid checking for UNKNOWN_LOCATION.
PR c++/103347
gcc/cp/ChangeLog:
* cp-tree.h (struct cp_declarator): Add a location_t member.
(maybe_warn_cpp0x): Add a location_t parameter with a default argument.
(loc_or_input_loc): New.
* decl.c (grokdeclarator): Use loc_or_input_loc. Pass init_loc down
to maybe_warn_cpp0x.
* error.c (maybe_warn_cpp0x): Add a location_t parameter. Use it.
* parser.c (make_declarator): Initialize init_loc.
(cp_parser_member_declaration): Set init_loc.
(cp_parser_condition): Likewise.
(cp_parser_init_declarator): Likewise.
(cp_parser_parameter_declaration): Likewise.
gcc/testsuite/ChangeLog:
* g++.dg/cpp0x/nsdmi-warn1.C: New test.
* g++.dg/cpp0x/nsdmi-warn1.h: New file.
---
gcc/cp/cp-tree.h | 16 +++++++++---
gcc/cp/decl.c | 22 +++++++++-------
gcc/cp/error.c | 32 ++++++++++++------------
gcc/cp/parser.c | 8 ++++++
gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.C | 10 ++++++++
gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.h | 2 ++
6 files changed, 61 insertions(+), 29 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.C
create mode 100644 gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.h
base-commit: c59ec55c3459fba619e05ee7f59480b71e85ffd7
Comments
On 11/23/21 17:06, Marek Polacek wrote:
> On Tue, Nov 23, 2021 at 02:42:12PM -0500, Jason Merrill wrote:
>> On 11/22/21 17:17, Marek Polacek wrote:
>>> Here the problem is that we aren't detecting a NSDMI in C++98:
>>>
>>> struct A {
>>> void *x = NULL;
>>> };
>>>
>>> because maybe_warn_cpp0x uses input_location and that happens to point
>>> to NULL which comes from a system header. Jakub suggested changing the
>>> location to the '=', thereby avoiding the system header problem. To
>>> that end, I've added a new location_t member into cp_declarator. This
>>> member is used when this declarator is part of an init-declarator. The
>>> rest of the changes is obvious. I've also taken the liberty of adding
>>> loc_or_input_loc, since I want to avoid checking for UNKNOWN_LOCATION.
>>>
>>> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
>>>
>>> PR c++/103347
>>>
>>> gcc/cp/ChangeLog:
>>>
>>> * cp-tree.h (struct cp_declarator): Add a location_t member.
>>> (maybe_warn_cpp0x): Add a location_t parameter with a default argument.
>>> (loc_or_input_loc): New.
>>> * decl.c (grokdeclarator): Use loc_or_input_loc. Pass init_loc down
>>> to maybe_warn_cpp0x.
>>> * error.c (maybe_warn_cpp0x): Add a location_t parameter. Use it.
>>> * parser.c (make_declarator): Initialize init_loc.
>>> (cp_parser_member_declaration): Set init_loc.
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>> * g++.dg/cpp0x/nsdmi-warn1.C: New test.
>>> * g++.dg/cpp0x/nsdmi-warn1.h: New file.
>>> ---
>>> gcc/cp/cp-tree.h | 16 +++++++++---
>>> gcc/cp/decl.c | 22 +++++++++-------
>>> gcc/cp/error.c | 32 ++++++++++++------------
>>> gcc/cp/parser.c | 2 ++
>>> gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.C | 10 ++++++++
>>> gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.h | 2 ++
>>> 6 files changed, 55 insertions(+), 29 deletions(-)
>>> create mode 100644 gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.C
>>> create mode 100644 gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.h
>>>
>>> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
>>> index 3f56cb90d14..2037082b0c7 100644
>>> --- a/gcc/cp/cp-tree.h
>>> +++ b/gcc/cp/cp-tree.h
>>> @@ -6231,9 +6231,11 @@ struct cp_declarator {
>>> /* If this declarator is parenthesized, this the open-paren. It is
>>> UNKNOWN_LOCATION when not parenthesized. */
>>> location_t parenthesized;
>>> -
>>> - location_t id_loc; /* Currently only set for cdk_id, cdk_decomp and
>>> - cdk_function. */
>>> + /* Currently only set for cdk_id, cdk_decomp and cdk_function. */
>>> + location_t id_loc;
>>> + /* If this declarator is part of an init-declarator, the location of the
>>> + initializer. */
>>
>> Currently this comment is inaccurate because we don't set it for all
>> init-declarators. That should be pretty trivial to do, even if we don't use
>> the location yet in other contexts.
>
> The following patch sets ->init_loc in a few more spots. I've looked
> at every cp_parser_declarator call and if it's followed by a =/{, I
> set ->init_loc. Pedantically, it's also an init-declarator if the
> declarator is followed by a requires-clause, but I've not looked for
> those cases.
>
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
OK.
> -- >8 --
> Here the problem is that we aren't detecting a NSDMI in C++98:
>
> struct A {
> void *x = NULL;
> };
>
> because maybe_warn_cpp0x uses input_location and that happens to point
> to NULL which comes from a system header. Jakub suggested changing the
> location to the '=', thereby avoiding the system header problem. To
> that end, I've added a new location_t member into cp_declarator. This
> member is used when this declarator is part of an init-declarator. The
> rest of the changes is obvious. I've also taken the liberty of adding
> loc_or_input_loc, since I want to avoid checking for UNKNOWN_LOCATION.
>
> PR c++/103347
>
> gcc/cp/ChangeLog:
>
> * cp-tree.h (struct cp_declarator): Add a location_t member.
> (maybe_warn_cpp0x): Add a location_t parameter with a default argument.
> (loc_or_input_loc): New.
> * decl.c (grokdeclarator): Use loc_or_input_loc. Pass init_loc down
> to maybe_warn_cpp0x.
> * error.c (maybe_warn_cpp0x): Add a location_t parameter. Use it.
> * parser.c (make_declarator): Initialize init_loc.
> (cp_parser_member_declaration): Set init_loc.
> (cp_parser_condition): Likewise.
> (cp_parser_init_declarator): Likewise.
> (cp_parser_parameter_declaration): Likewise.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/cpp0x/nsdmi-warn1.C: New test.
> * g++.dg/cpp0x/nsdmi-warn1.h: New file.
> ---
> gcc/cp/cp-tree.h | 16 +++++++++---
> gcc/cp/decl.c | 22 +++++++++-------
> gcc/cp/error.c | 32 ++++++++++++------------
> gcc/cp/parser.c | 8 ++++++
> gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.C | 10 ++++++++
> gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.h | 2 ++
> 6 files changed, 61 insertions(+), 29 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.C
> create mode 100644 gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.h
>
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 3f56cb90d14..2037082b0c7 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -6231,9 +6231,11 @@ struct cp_declarator {
> /* If this declarator is parenthesized, this the open-paren. It is
> UNKNOWN_LOCATION when not parenthesized. */
> location_t parenthesized;
> -
> - location_t id_loc; /* Currently only set for cdk_id, cdk_decomp and
> - cdk_function. */
> + /* Currently only set for cdk_id, cdk_decomp and cdk_function. */
> + location_t id_loc;
> + /* If this declarator is part of an init-declarator, the location of the
> + initializer. */
> + location_t init_loc;
> /* GNU Attributes that apply to this declarator. If the declarator
> is a pointer or a reference, these attribute apply to the type
> pointed to. */
> @@ -6878,7 +6880,8 @@ extern const char *lang_decl_dwarf_name (tree, int, bool);
> extern const char *language_to_string (enum languages);
> extern const char *class_key_or_enum_as_string (tree);
> extern void maybe_warn_variadic_templates (void);
> -extern void maybe_warn_cpp0x (cpp0x_warn_str str);
> +extern void maybe_warn_cpp0x (cpp0x_warn_str str,
> + location_t = input_location);
> extern bool pedwarn_cxx98 (location_t, int, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4);
> extern location_t location_of (tree);
> extern void qualified_name_lookup_error (tree, tree, tree,
> @@ -7996,6 +7999,11 @@ extern bool decl_in_std_namespace_p (tree);
> extern void require_complete_eh_spec_types (tree, tree);
> extern void cxx_incomplete_type_diagnostic (location_t, const_tree,
> const_tree, diagnostic_t);
> +inline location_t
> +loc_or_input_loc (location_t loc)
> +{
> + return loc == UNKNOWN_LOCATION ? input_location : loc;
> +}
>
> inline location_t
> cp_expr_loc_or_loc (const_tree t, location_t or_loc)
> diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
> index 9f68d1a5590..ae0e0bae9cc 100644
> --- a/gcc/cp/decl.c
> +++ b/gcc/cp/decl.c
> @@ -11522,14 +11522,18 @@ grokdeclarator (const cp_declarator *declarator,
> if (initialized == SD_DEFAULTED || initialized == SD_DELETED)
> funcdef_flag = true;
>
> - location_t typespec_loc = smallest_type_location (type_quals,
> - declspecs->locations);
> - if (typespec_loc == UNKNOWN_LOCATION)
> - typespec_loc = input_location;
> -
> - location_t id_loc = declarator ? declarator->id_loc : input_location;
> - if (id_loc == UNKNOWN_LOCATION)
> - id_loc = input_location;
> + location_t typespec_loc = loc_or_input_loc (smallest_type_location
> + (type_quals,
> + declspecs->locations));
> + location_t id_loc;
> + location_t init_loc;
> + if (declarator)
> + {
> + id_loc = loc_or_input_loc (declarator->id_loc);
> + init_loc = loc_or_input_loc (declarator->init_loc);
> + }
> + else
> + init_loc = id_loc = input_location;
>
> /* Look inside a declarator for the name being declared
> and get it as a string, for an error message. */
> @@ -14042,7 +14046,7 @@ grokdeclarator (const cp_declarator *declarator,
> {
> /* An attempt is being made to initialize a non-static
> member. This is new in C++11. */
> - maybe_warn_cpp0x (CPP0X_NSDMI);
> + maybe_warn_cpp0x (CPP0X_NSDMI, init_loc);
>
> /* If this has been parsed with static storage class, but
> errors forced staticp to be cleared, ensure NSDMI is
> diff --git a/gcc/cp/error.c b/gcc/cp/error.c
> index 872479369ab..98c1f0e4bdf 100644
> --- a/gcc/cp/error.c
> +++ b/gcc/cp/error.c
> @@ -4428,84 +4428,84 @@ cp_printer (pretty_printer *pp, text_info *text, const char *spec,
>
> /* Warn about the use of C++0x features when appropriate. */
> void
> -maybe_warn_cpp0x (cpp0x_warn_str str)
> +maybe_warn_cpp0x (cpp0x_warn_str str, location_t loc/*=input_location*/)
> {
> if (cxx_dialect == cxx98)
> switch (str)
> {
> case CPP0X_INITIALIZER_LISTS:
> - pedwarn (input_location, OPT_Wc__11_extensions,
> + pedwarn (loc, OPT_Wc__11_extensions,
> "extended initializer lists "
> "only available with %<-std=c++11%> or %<-std=gnu++11%>");
> break;
> case CPP0X_EXPLICIT_CONVERSION:
> - pedwarn (input_location, OPT_Wc__11_extensions,
> + pedwarn (loc, OPT_Wc__11_extensions,
> "explicit conversion operators "
> "only available with %<-std=c++11%> or %<-std=gnu++11%>");
> break;
> case CPP0X_VARIADIC_TEMPLATES:
> - pedwarn (input_location, OPT_Wc__11_extensions,
> + pedwarn (loc, OPT_Wc__11_extensions,
> "variadic templates "
> "only available with %<-std=c++11%> or %<-std=gnu++11%>");
> break;
> case CPP0X_LAMBDA_EXPR:
> - pedwarn (input_location, OPT_Wc__11_extensions,
> + pedwarn (loc, OPT_Wc__11_extensions,
> "lambda expressions "
> "only available with %<-std=c++11%> or %<-std=gnu++11%>");
> break;
> case CPP0X_AUTO:
> - pedwarn (input_location, OPT_Wc__11_extensions,
> + pedwarn (loc, OPT_Wc__11_extensions,
> "C++11 auto only available with %<-std=c++11%> or "
> "%<-std=gnu++11%>");
> break;
> case CPP0X_SCOPED_ENUMS:
> - pedwarn (input_location, OPT_Wc__11_extensions,
> + pedwarn (loc, OPT_Wc__11_extensions,
> "scoped enums only available with %<-std=c++11%> or "
> "%<-std=gnu++11%>");
> break;
> case CPP0X_DEFAULTED_DELETED:
> - pedwarn (input_location, OPT_Wc__11_extensions,
> + pedwarn (loc, OPT_Wc__11_extensions,
> "defaulted and deleted functions "
> "only available with %<-std=c++11%> or %<-std=gnu++11%>");
> break;
> case CPP0X_INLINE_NAMESPACES:
> if (pedantic)
> - pedwarn (input_location, OPT_Wc__11_extensions,
> + pedwarn (loc, OPT_Wc__11_extensions,
> "inline namespaces "
> "only available with %<-std=c++11%> or %<-std=gnu++11%>");
> break;
> case CPP0X_OVERRIDE_CONTROLS:
> - pedwarn (input_location, OPT_Wc__11_extensions,
> + pedwarn (loc, OPT_Wc__11_extensions,
> "override controls (override/final) "
> "only available with %<-std=c++11%> or %<-std=gnu++11%>");
> break;
> case CPP0X_NSDMI:
> - pedwarn (input_location, OPT_Wc__11_extensions,
> + pedwarn (loc, OPT_Wc__11_extensions,
> "non-static data member initializers "
> "only available with %<-std=c++11%> or %<-std=gnu++11%>");
> break;
> case CPP0X_USER_DEFINED_LITERALS:
> - pedwarn (input_location, OPT_Wc__11_extensions,
> + pedwarn (loc, OPT_Wc__11_extensions,
> "user-defined literals "
> "only available with %<-std=c++11%> or %<-std=gnu++11%>");
> break;
> case CPP0X_DELEGATING_CTORS:
> - pedwarn (input_location, OPT_Wc__11_extensions,
> + pedwarn (loc, OPT_Wc__11_extensions,
> "delegating constructors "
> "only available with %<-std=c++11%> or %<-std=gnu++11%>");
> break;
> case CPP0X_INHERITING_CTORS:
> - pedwarn (input_location, OPT_Wc__11_extensions,
> + pedwarn (loc, OPT_Wc__11_extensions,
> "inheriting constructors "
> "only available with %<-std=c++11%> or %<-std=gnu++11%>");
> break;
> case CPP0X_ATTRIBUTES:
> - pedwarn (input_location, OPT_Wc__11_extensions,
> + pedwarn (loc, OPT_Wc__11_extensions,
> "C++11 attributes "
> "only available with %<-std=c++11%> or %<-std=gnu++11%>");
> break;
> case CPP0X_REF_QUALIFIER:
> - pedwarn (input_location, OPT_Wc__11_extensions,
> + pedwarn (loc, OPT_Wc__11_extensions,
> "ref-qualifiers "
> "only available with %<-std=c++11%> or %<-std=gnu++11%>");
> break;
> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
> index e2b5d6842fc..7a6a30208ef 100644
> --- a/gcc/cp/parser.c
> +++ b/gcc/cp/parser.c
> @@ -1542,6 +1542,7 @@ make_declarator (cp_declarator_kind kind)
> declarator->declarator = NULL;
> declarator->parameter_pack_p = false;
> declarator->id_loc = UNKNOWN_LOCATION;
> + declarator->init_loc = UNKNOWN_LOCATION;
>
> return declarator;
> }
> @@ -13286,6 +13287,7 @@ cp_parser_condition (cp_parser* parser)
> attributes, prefix_attributes,
> &pushed_scope);
>
> + declarator->init_loc = cp_lexer_peek_token (parser->lexer)->location;
> /* Parse the initializer. */
> if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
> {
> @@ -22492,6 +22494,7 @@ cp_parser_init_declarator (cp_parser* parser,
> {
> is_initialized = SD_INITIALIZED;
> initialization_kind = token->type;
> + declarator->init_loc = token->location;
> if (maybe_range_for_decl)
> *maybe_range_for_decl = error_mark_node;
> tmp_init_loc = token->location;
> @@ -24751,6 +24754,8 @@ cp_parser_parameter_declaration (cp_parser *parser,
> {
> tree type = decl_specifiers.type;
> token = cp_lexer_peek_token (parser->lexer);
> + if (declarator)
> + declarator->init_loc = token->location;
> /* If we are defining a class, then the tokens that make up the
> default argument must be saved and processed later. */
> if (!template_parm_p && at_class_scope_p ()
> @@ -27143,6 +27148,7 @@ cp_parser_member_declaration (cp_parser* parser)
> constant-initializer. When we call `grokfield', it will
> perform more stringent semantics checks. */
> initializer_token_start = cp_lexer_peek_token (parser->lexer);
> + declarator->init_loc = initializer_token_start->location;
> if (function_declarator_p (declarator)
> || (decl_specifiers.type
> && TREE_CODE (decl_specifiers.type) == TYPE_DECL
> @@ -27171,6 +27177,8 @@ cp_parser_member_declaration (cp_parser* parser)
> && !function_declarator_p (declarator))
> {
> bool x;
> + declarator->init_loc
> + = cp_lexer_peek_token (parser->lexer)->location;
> if (decl_specifiers.storage_class != sc_static)
> initializer = cp_parser_save_nsdmi (parser);
> else
> diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.C
> new file mode 100644
> index 00000000000..aacc8b28255
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.C
> @@ -0,0 +1,10 @@
> +// PR c++/103347
> +// { dg-do compile { target c++11_down } }
> +
> +#include "nsdmi-warn1.h"
> +
> +struct A {
> + void *x = NULL; // { dg-error "11:only available" "" { target c++98_only } }
> + void *y{NULL}; // { dg-error "only available|extended initializer" "" { target c++98_only } }
> + int z = 1 + 2; // { dg-error "9:only available" "" { target c++98_only } }
> +};
> diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.h b/gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.h
> new file mode 100644
> index 00000000000..ee5be5a2478
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.h
> @@ -0,0 +1,2 @@
> +#pragma GCC system_header
> +#define NULL (void *)0
>
> base-commit: c59ec55c3459fba619e05ee7f59480b71e85ffd7
>
@@ -6231,9 +6231,11 @@ struct cp_declarator {
/* If this declarator is parenthesized, this the open-paren. It is
UNKNOWN_LOCATION when not parenthesized. */
location_t parenthesized;
-
- location_t id_loc; /* Currently only set for cdk_id, cdk_decomp and
- cdk_function. */
+ /* Currently only set for cdk_id, cdk_decomp and cdk_function. */
+ location_t id_loc;
+ /* If this declarator is part of an init-declarator, the location of the
+ initializer. */
+ location_t init_loc;
/* GNU Attributes that apply to this declarator. If the declarator
is a pointer or a reference, these attribute apply to the type
pointed to. */
@@ -6878,7 +6880,8 @@ extern const char *lang_decl_dwarf_name (tree, int, bool);
extern const char *language_to_string (enum languages);
extern const char *class_key_or_enum_as_string (tree);
extern void maybe_warn_variadic_templates (void);
-extern void maybe_warn_cpp0x (cpp0x_warn_str str);
+extern void maybe_warn_cpp0x (cpp0x_warn_str str,
+ location_t = input_location);
extern bool pedwarn_cxx98 (location_t, int, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4);
extern location_t location_of (tree);
extern void qualified_name_lookup_error (tree, tree, tree,
@@ -7996,6 +7999,11 @@ extern bool decl_in_std_namespace_p (tree);
extern void require_complete_eh_spec_types (tree, tree);
extern void cxx_incomplete_type_diagnostic (location_t, const_tree,
const_tree, diagnostic_t);
+inline location_t
+loc_or_input_loc (location_t loc)
+{
+ return loc == UNKNOWN_LOCATION ? input_location : loc;
+}
inline location_t
cp_expr_loc_or_loc (const_tree t, location_t or_loc)
@@ -11522,14 +11522,18 @@ grokdeclarator (const cp_declarator *declarator,
if (initialized == SD_DEFAULTED || initialized == SD_DELETED)
funcdef_flag = true;
- location_t typespec_loc = smallest_type_location (type_quals,
- declspecs->locations);
- if (typespec_loc == UNKNOWN_LOCATION)
- typespec_loc = input_location;
-
- location_t id_loc = declarator ? declarator->id_loc : input_location;
- if (id_loc == UNKNOWN_LOCATION)
- id_loc = input_location;
+ location_t typespec_loc = loc_or_input_loc (smallest_type_location
+ (type_quals,
+ declspecs->locations));
+ location_t id_loc;
+ location_t init_loc;
+ if (declarator)
+ {
+ id_loc = loc_or_input_loc (declarator->id_loc);
+ init_loc = loc_or_input_loc (declarator->init_loc);
+ }
+ else
+ init_loc = id_loc = input_location;
/* Look inside a declarator for the name being declared
and get it as a string, for an error message. */
@@ -14042,7 +14046,7 @@ grokdeclarator (const cp_declarator *declarator,
{
/* An attempt is being made to initialize a non-static
member. This is new in C++11. */
- maybe_warn_cpp0x (CPP0X_NSDMI);
+ maybe_warn_cpp0x (CPP0X_NSDMI, init_loc);
/* If this has been parsed with static storage class, but
errors forced staticp to be cleared, ensure NSDMI is
@@ -4428,84 +4428,84 @@ cp_printer (pretty_printer *pp, text_info *text, const char *spec,
/* Warn about the use of C++0x features when appropriate. */
void
-maybe_warn_cpp0x (cpp0x_warn_str str)
+maybe_warn_cpp0x (cpp0x_warn_str str, location_t loc/*=input_location*/)
{
if (cxx_dialect == cxx98)
switch (str)
{
case CPP0X_INITIALIZER_LISTS:
- pedwarn (input_location, OPT_Wc__11_extensions,
+ pedwarn (loc, OPT_Wc__11_extensions,
"extended initializer lists "
"only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
case CPP0X_EXPLICIT_CONVERSION:
- pedwarn (input_location, OPT_Wc__11_extensions,
+ pedwarn (loc, OPT_Wc__11_extensions,
"explicit conversion operators "
"only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
case CPP0X_VARIADIC_TEMPLATES:
- pedwarn (input_location, OPT_Wc__11_extensions,
+ pedwarn (loc, OPT_Wc__11_extensions,
"variadic templates "
"only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
case CPP0X_LAMBDA_EXPR:
- pedwarn (input_location, OPT_Wc__11_extensions,
+ pedwarn (loc, OPT_Wc__11_extensions,
"lambda expressions "
"only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
case CPP0X_AUTO:
- pedwarn (input_location, OPT_Wc__11_extensions,
+ pedwarn (loc, OPT_Wc__11_extensions,
"C++11 auto only available with %<-std=c++11%> or "
"%<-std=gnu++11%>");
break;
case CPP0X_SCOPED_ENUMS:
- pedwarn (input_location, OPT_Wc__11_extensions,
+ pedwarn (loc, OPT_Wc__11_extensions,
"scoped enums only available with %<-std=c++11%> or "
"%<-std=gnu++11%>");
break;
case CPP0X_DEFAULTED_DELETED:
- pedwarn (input_location, OPT_Wc__11_extensions,
+ pedwarn (loc, OPT_Wc__11_extensions,
"defaulted and deleted functions "
"only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
case CPP0X_INLINE_NAMESPACES:
if (pedantic)
- pedwarn (input_location, OPT_Wc__11_extensions,
+ pedwarn (loc, OPT_Wc__11_extensions,
"inline namespaces "
"only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
case CPP0X_OVERRIDE_CONTROLS:
- pedwarn (input_location, OPT_Wc__11_extensions,
+ pedwarn (loc, OPT_Wc__11_extensions,
"override controls (override/final) "
"only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
case CPP0X_NSDMI:
- pedwarn (input_location, OPT_Wc__11_extensions,
+ pedwarn (loc, OPT_Wc__11_extensions,
"non-static data member initializers "
"only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
case CPP0X_USER_DEFINED_LITERALS:
- pedwarn (input_location, OPT_Wc__11_extensions,
+ pedwarn (loc, OPT_Wc__11_extensions,
"user-defined literals "
"only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
case CPP0X_DELEGATING_CTORS:
- pedwarn (input_location, OPT_Wc__11_extensions,
+ pedwarn (loc, OPT_Wc__11_extensions,
"delegating constructors "
"only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
case CPP0X_INHERITING_CTORS:
- pedwarn (input_location, OPT_Wc__11_extensions,
+ pedwarn (loc, OPT_Wc__11_extensions,
"inheriting constructors "
"only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
case CPP0X_ATTRIBUTES:
- pedwarn (input_location, OPT_Wc__11_extensions,
+ pedwarn (loc, OPT_Wc__11_extensions,
"C++11 attributes "
"only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
case CPP0X_REF_QUALIFIER:
- pedwarn (input_location, OPT_Wc__11_extensions,
+ pedwarn (loc, OPT_Wc__11_extensions,
"ref-qualifiers "
"only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
@@ -1542,6 +1542,7 @@ make_declarator (cp_declarator_kind kind)
declarator->declarator = NULL;
declarator->parameter_pack_p = false;
declarator->id_loc = UNKNOWN_LOCATION;
+ declarator->init_loc = UNKNOWN_LOCATION;
return declarator;
}
@@ -13286,6 +13287,7 @@ cp_parser_condition (cp_parser* parser)
attributes, prefix_attributes,
&pushed_scope);
+ declarator->init_loc = cp_lexer_peek_token (parser->lexer)->location;
/* Parse the initializer. */
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
{
@@ -22492,6 +22494,7 @@ cp_parser_init_declarator (cp_parser* parser,
{
is_initialized = SD_INITIALIZED;
initialization_kind = token->type;
+ declarator->init_loc = token->location;
if (maybe_range_for_decl)
*maybe_range_for_decl = error_mark_node;
tmp_init_loc = token->location;
@@ -24751,6 +24754,8 @@ cp_parser_parameter_declaration (cp_parser *parser,
{
tree type = decl_specifiers.type;
token = cp_lexer_peek_token (parser->lexer);
+ if (declarator)
+ declarator->init_loc = token->location;
/* If we are defining a class, then the tokens that make up the
default argument must be saved and processed later. */
if (!template_parm_p && at_class_scope_p ()
@@ -27143,6 +27148,7 @@ cp_parser_member_declaration (cp_parser* parser)
constant-initializer. When we call `grokfield', it will
perform more stringent semantics checks. */
initializer_token_start = cp_lexer_peek_token (parser->lexer);
+ declarator->init_loc = initializer_token_start->location;
if (function_declarator_p (declarator)
|| (decl_specifiers.type
&& TREE_CODE (decl_specifiers.type) == TYPE_DECL
@@ -27171,6 +27177,8 @@ cp_parser_member_declaration (cp_parser* parser)
&& !function_declarator_p (declarator))
{
bool x;
+ declarator->init_loc
+ = cp_lexer_peek_token (parser->lexer)->location;
if (decl_specifiers.storage_class != sc_static)
initializer = cp_parser_save_nsdmi (parser);
else
new file mode 100644
@@ -0,0 +1,10 @@
+// PR c++/103347
+// { dg-do compile { target c++11_down } }
+
+#include "nsdmi-warn1.h"
+
+struct A {
+ void *x = NULL; // { dg-error "11:only available" "" { target c++98_only } }
+ void *y{NULL}; // { dg-error "only available|extended initializer" "" { target c++98_only } }
+ int z = 1 + 2; // { dg-error "9:only available" "" { target c++98_only } }
+};
new file mode 100644
@@ -0,0 +1,2 @@
+#pragma GCC system_header
+#define NULL (void *)0