diff mbox

[C++] PR 58650

Message ID 548F5C8E.6000008@oracle.com
State New
Headers show

Commit Message

Paolo Carlini Dec. 15, 2014, 10:11 p.m. UTC
Hi,

avoid crashing later in build_this_parm during error recovery. Tested 
x86_64-linux.

Thanks,
Paolo.

//////////////////
/cp
2014-12-15  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/58650
	* decl.c (grokdeclarator): Avoid crashing on an initialized
	non-static data member wrongly declared friend.

/testsuite
2014-12-15  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/58650
	* g++.dg/parse/friend12.C: New.

Comments

Jason Merrill Dec. 15, 2014, 10:25 p.m. UTC | #1
Why does error recovery fail?  I would expect to be able to just drop 
the 'friend' and treat it as a normal non-static data member.

Jason
Paolo Carlini Dec. 16, 2014, 10:17 a.m. UTC | #2
Hi,

On 12/15/2014 11:25 PM, Jason Merrill wrote:
> Why does error recovery fail?  I would expect to be able to just drop 
> the 'friend' and treat it as a normal non-static data member.
I agree, that was my first thought too. Unfortunately we do non-trivial 
preparatory work *before* calling grokdeclarator based on ds_friend 
which aren't reverted by locally resetting friendp in grokdeclarator, 
and, eg, build_this_parm gets a null type even if 
declspecs->locations[ds_friend] itself is reset right at the beginning 
of grokdeclarator. I'll try the further investigate the above...

Thanks,
Paolo.
Paolo Carlini Dec. 16, 2014, 10:40 a.m. UTC | #3
Hi again,

On 12/16/2014 11:17 AM, Paolo Carlini wrote:
> Hi,
>
> On 12/15/2014 11:25 PM, Jason Merrill wrote:
>> Why does error recovery fail?  I would expect to be able to just drop 
>> the 'friend' and treat it as a normal non-static data member.
> I agree, that was my first thought too. Unfortunately we do 
> non-trivial preparatory work *before* calling grokdeclarator based on 
> ds_friend which aren't reverted by locally resetting friendp in 
> grokdeclarator, and, eg, build_this_parm gets a null type even if 
> declspecs->locations[ds_friend] itself is reset right at the beginning 
> of grokdeclarator. I'll try the further investigate the above...
In better detail: grokdeclarator is called, via grokfield, by 
cp_parser_member_declaration. The latter stores the friendship 
information in a friend_p local flag, which remains true when 
grokdeclarator returns. Then at the end of the function:

       if (decl)
         {
           /* Add DECL to the list of members.  */
           if (!friend_p)
         finish_member_declaration (decl);

makes all the difference for the crash. Now, I could try resetting in 
grokdeclarator the primary ds_friend information as stored in the 
decl_specifiers and read it back, thus update friend_p in 
cp_parser_member_declaration. It would probably work, but frankly this 
fiddling only for error recovery makes me a little nervous. What do you 
think?

Thanks,
Paolo.
Jason Merrill Dec. 16, 2014, 3:10 p.m. UTC | #4
On 12/16/2014 05:40 AM, Paolo Carlini wrote:
> In better detail: grokdeclarator is called, via grokfield, by
> cp_parser_member_declaration. The latter stores the friendship
> information in a friend_p local flag, which remains true when
> grokdeclarator returns.

Maybe check function_declarator_p in cp_parser_member_declaration?

Jason
diff mbox

Patch

Index: cp/decl.c
===================================================================
--- cp/decl.c	(revision 218764)
+++ cp/decl.c	(working copy)
@@ -10803,6 +10803,7 @@  grokdeclarator (const cp_declarator *declarator,
 		error ("%qE is neither function nor member function; "
 		       "cannot be declared friend", unqualified_id);
 		friendp = 0;
+		type = error_mark_node;
 	      }
 	    decl = NULL_TREE;
 	  }
Index: testsuite/g++.dg/parse/friend12.C
===================================================================
--- testsuite/g++.dg/parse/friend12.C	(revision 0)
+++ testsuite/g++.dg/parse/friend12.C	(working copy)
@@ -0,0 +1,7 @@ 
+// PR c++/58650
+
+struct A
+{
+  friend int i = 0;  // { dg-error "cannot be declared friend" }
+// { dg-error "non-static data member" "" { target { ! c++11 } } 5 }
+};