[v2] c++: Fix missing NSDMI diagnostic in C++98 [PR103347]

Message ID YZ1l7igXPj76+xy/@redhat.com
State Committed
Commit d71d019f63ed5d3fdb34579023bafa4dcf323f2c
Headers
Series [v2] c++: Fix missing NSDMI diagnostic in C++98 [PR103347] |

Commit Message

Marek Polacek Nov. 23, 2021, 10:06 p.m. UTC
  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

Jason Merrill Nov. 24, 2021, 5 a.m. UTC | #1
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
>
  

Patch

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