Bug 52755 - G++ misses ill-formed trivial implicitly-defined operator= in C++98 mode
Summary: G++ misses ill-formed trivial implicitly-defined operator= in C++98 mode
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.6.4
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: accepts-invalid
Depends on:
Blocks:
 
Reported: 2012-03-28 15:41 UTC by Holger Hopp
Modified: 2021-07-24 23:17 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2021-07-24 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Holger Hopp 2012-03-28 15:41:11 UTC
Following code compiles fine with every gcc, with every g++ -std=c++98, 
with g++-4.5 -std=c++0x, but not with g++ -std=c++0x (or -std=c++11) since 4.6.

typedef volatile struct t1s { int a; } t1;
typedef struct t2s { t1 b; } t2;
t2 x, y;

void foo(void)
{
  x = y;
}

compile with: g++ -std=c++0x vola.cpp

vola.cpp: In function 'void foo()':
vola.cpp:7:7: error: use of deleted function 't2s& t2s::operator=(const t2s&)'
vola.cpp:2:16: error: 't2s& t2s::operator=(const t2s&)' is implicitly deleted because the default definition would be ill-formed:
vola.cpp:2:16: error: no matching function for call to 't1s::operator=(const volatile t1&) volatile'
vola.cpp:2:16: note: candidates are:
vola.cpp:1:25: note: t1s& t1s::operator=(const t1s&)
vola.cpp:1:25: note:   no known conversion for argument 1 from 'const volatile t1' to 'const t1s&'
vola.cpp:1:25: note: t1s& t1s::operator=(t1s&&)
vola.cpp:1:25: note:   no known conversion for argument 1 from 'const volatile t1' to 't1s&&'
Comment 1 Jonathan Wakely 2012-03-28 17:39:52 UTC
(In reply to comment #0)
> Following code compiles fine with every gcc, with every g++ -std=c++98, 
> with g++-4.5 -std=c++0x, but not with g++ -std=c++0x (or -std=c++11) since 4.6.

That's because G++ 4.6 was changed to reject your invalid program, it's supposed to do that, and it means G++ 4.6 is better than G++ 4.5 :)

Isn't the error quite clear?

Assigning t2s needs to use the assignment operator, but that function can't be implicitly-defined because assigning the volatile member requires t1s::operator=(const volatile t1s&) which doesn't exist, because the implicit-declared copy assignment operator has the signature t1s::operator=(const t1s&)

To fix your code you should either define copy assignment for t1s so it works on volatile objects, or define assignment for t2s so it doesn't need t1s::operator= e.g.

  t2s& operator=(const t2s& t) { b.a = t.b.a; return *this; }
Comment 2 Jonathan Wakely 2012-03-28 17:45:24 UTC
(In reply to comment #1)
> Assigning t2s needs to use the assignment operator, but that function can't be
> implicitly-defined because assigning the volatile member requires
> t1s::operator=(const volatile t1s&) which doesn't exist, 

Actually that should say:

"t1s::operator=(const volatile t1s&) volatile" which doesn't exist,
Comment 3 Holger Hopp 2012-03-29 11:50:25 UTC
I agree that it is possible to define operator= for each struct that
is using t1 (in the original code (C code, but compiled as C++ code)
there is not only t2, and in all of them there are more members).

There are simpler methods to fix the code, e.g. to define  
  typedef struct t1s { volatile int a; } t1;
It should be equivalent in the volatile qualifier behavior when the
volatile qualifier is set for each member of t1. This compiles also
fine with gcc-4.6 and does not need several operator= definitions.

But that is not the question. The question is if that is a gcc bug or
not. If C++11 is really different compared to C++98 here (I'm not sure
about that), then I would prefer _one_ clear error message like
"error: C++11 does not allow ..." or "error: C++11 demands ..." or
similar, and not that weird 3 error messages plus 5 notes about
implicitly deleted simple assignments operators.
Comment 4 Jonathan Wakely 2012-03-29 13:31:00 UTC
(In reply to comment #3)
> But that is not the question. The question is if that is a gcc bug or
> not. If C++11 is really different compared to C++98 here (I'm not sure

It's certainly different because there are no deleted functions in C++98, but I'm not sure if the code is valid in C++98 or not, G++ and EDG accept it but clang++ doesn't.  As far as I can see C++98 should have the same behaviour, assigning t2 requires assigning a volatile t1, which can't use the implicitly-declared assignment operator.  Maybe Jason can clarify.

> about that), then I would prefer _one_ clear error message like
> "error: C++11 does not allow ..." or "error: C++11 demands ..." or
> similar, and not that weird 3 error messages plus 5 notes about
> implicitly deleted simple assignments operators.

That's not possible in general, and I actually prefer the explanation of which rules caused the error.  What do you suggest it prints?  There's no easy answer. Attempting to turn that into natural language would go wrong too often and give misleading errors.

The problem is that you tried to use the implicit assignment operator, which is deleted, so the compiler tells you why it's deleted.  The message is great IMHO, a huge improvement on the diagnostics given by older versions of GCC.
Comment 5 Jason Merrill 2012-03-29 14:37:26 UTC
clang is correct in this case; the testcase should be rejected in c++98 mode as well.  operator= is defined as memberwise assignment even if it's trivial.  So the C++98 mode behavior is the bug.