[Bug c++/80259] [5/6/7 Regression] ICE deleting friend function

2017-03-30 Thread rguenth at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80259

Richard Biener  changed:

   What|Removed |Added

   Priority|P3  |P2

[Bug c++/80259] [5/6/7 Regression] ICE deleting friend function

2017-03-30 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80259

--- Comment #3 from Jakub Jelinek  ---
With untested:
--- gcc/decl2.c.jj  2017-02-21 18:59:36.0 +0100
+++ gcc/decl2.c 2017-03-30 10:16:03.972113673 +0200
@@ -888,9 +888,18 @@ grokfield (const cp_declarator *declarat
{
  if (init == ridpointers[(int)RID_DELETE])
{
- DECL_DELETED_FN (value) = 1;
- DECL_DECLARED_INLINE_P (value) = 1;
- DECL_INITIAL (value) = error_mark_node;
+ if (friendp && decl_defined_p (value))
+   {
+ error ("redefinition of %q#D", value);
+ inform (DECL_SOURCE_LOCATION (value),
+ "%q#D previously defined here", value);
+   }
+ else
+   {
+ DECL_DELETED_FN (value) = 1;
+ DECL_DECLARED_INLINE_P (value) = 1;
+ DECL_INITIAL (value) = error_mark_node;
+   }
}
  else if (init == ridpointers[(int)RID_DEFAULT])
{
I get:
pr80259.C:5:23: error: redefinition of ‘void foo()’
   friend void foo() = delete;
   ^~
pr80259.C:1:6: note: ‘void foo()’ previously defined here
 void foo() {}
  ^~~
but no idea if you don't want to resolve it differently.

[Bug c++/80259] [5/6/7 Regression] ICE deleting friend function

2017-03-30 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80259

--- Comment #2 from Jakub Jelinek  ---
duplicate_decls is called with the DECL_INITIAL is still being NULL on the
newdecl (and olddecl has it a BLOCK).
#0  duplicate_decls (newdecl=,
olddecl=, newdecl_is_friend=true)
at ../../gcc/cp/decl.c:1401
#1  0x00a2420c in pushdecl_maybe_friend_1 (x=, is_friend=true) at ../../gcc/cp/name-lookup.c:835
#2  0x00a27940 in pushdecl_maybe_friend (x=, is_friend=true) at ../../gcc/cp/name-lookup.c:1352
#3  0x00a2aaff in pushdecl_with_scope_1 (x=, level=0x7fffefade000, is_friend=true)
at ../../gcc/cp/name-lookup.c:2349
#4  0x00a2aba2 in pushdecl_with_scope (x=, level=0x7fffefade000, is_friend=true)
at ../../gcc/cp/name-lookup.c:2363
#5  0x00a30b81 in pushdecl_namespace_level (x=, is_friend=true) at ../../gcc/cp/name-lookup.c:3978
#6  0x0097cf07 in do_friend (ctype=,
declarator=, decl=, 
attrlist=, flags=NO_SPECIAL, funcdef_flag=false) at
../../gcc/cp/friend.c:640
#7  0x007c9f6a in grokdeclarator (declarator=0x2ad2a00,
declspecs=0x7fffd830, decl_context=FIELD, initialized=1, 
attrlist=0x7fffd770) at ../../gcc/cp/decl.c:12060
#8  0x008b879f in grokfield (declarator=0x2ad2a60,
declspecs=0x7fffd830, init=, 
init_const_expr_p=true, asmspec_tree=, attrlist=) at
../../gcc/cp/decl2.c:806
And only afterwards grokfield reaches:
889   if (init == ridpointers[(int)RID_DELETE])
890 {
891   DECL_DELETED_FN (value) = 1;
892   DECL_DECLARED_INLINE_P (value) = 1;
893   DECL_INITIAL (value) = error_mark_node;
894 }
At this point I think we can't call redeclaration_error_message, because we
don't have the new decl anymore, only the merged (old one).  Perhaps custom
error message here if value is a friend and it has non-NULL (or non-NULL and
non-error_mark_node?) DECL_INITIAL and use there location_t for the new decl
from declarator->id_loc (that would be the foo) or input_location (that would
be the deleted) or something similar?

[Bug c++/80259] [5/6/7 Regression] ICE deleting friend function

2017-03-30 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80259

Jakub Jelinek  changed:

   What|Removed |Added

 Status|UNCONFIRMED |NEW
   Last reconfirmed||2017-03-30
 CC||jakub at gcc dot gnu.org,
   ||jason at gcc dot gnu.org
   Target Milestone|--- |5.5
 Ever confirmed|0   |1

--- Comment #1 from Jakub Jelinek  ---
Started with r213974.
Before that we've rejected it with:
pr80259.C:5:23: error: can’t initialize friend function ‘foo’
   friend void foo() = delete;
   ^
clang++ gives:
pr80259.C:5:15: error: inline declaration of 'foo' follows non-inline
definition
  friend void foo() = delete;
  ^
pr80259.C:1:6: note: previous definition is here
void foo() {}
 ^

So, what diagnostics would be best here?  What about:
void foo();
struct A
{
  friend void foo() = delete;
};
void foo() {}
?  With/without the first declaration we emit:
pr80259-2.C: In function ‘void foo()’:
pr80259-2.C:6:6: error: redefinition of ‘void foo()’
 void foo() {}
  ^~~
pr80259-2.C:4:15: note: ‘void foo()’ previously defined here
   friend void foo() = delete;
   ^~~
which looks fine to me.  So is the #c0 testcase a redefinition of the function
that should be diagnosed the same way?
For
void foo() {}
inline void foo () {}
we emit:
pr80259-3.C: In function ‘void foo()’:
pr80259-3.C:2:13: error: redefinition of ‘void foo()’
 inline void foo () {}
 ^~~
pr80259-3.C:1:6: note: ‘void foo()’ previously defined here
 void foo() {}
  ^~~
while clang++ emits:
pr80259-3.C:2:13: error: inline declaration of 'foo' follows non-inline
definition
inline void foo () {}
^
pr80259-3.C:1:6: note: previous definition is here
void foo() {}
 ^
so at least for now I'd say we should just emit a normal redefinition message.