Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does an unmaterialized temporary needs the destructor to be accessible?

GCC 7.2 and Clang 5.0 do not agree in this case:

struct A;

A foo();

struct A
  {
  static void bar()
     {
     foo();
     }
  private:
  ~A()=default;
  };

A foo()
  {
  return {};
  //GCC error: A::~A() is private in this context.
  };

This behavior is part of the "c++17 guaranteed (copy elision and is not related RVO or NRVO)."

GCC does not compile this code but Clang does. Which one is wrong?

Maybe this paragraph says that the bot Clang and GCC are standard compliant [class.temporary]:

When an object of class type X is passed to or returned from a function, if each copy constructor, move constructor, and destructor of X is either trivial or deleted, and X has at least one non-deleted copy or move constructor, implementations are permitted to create a temporary object to hold the function parameter or result object. The temporary object is constructed from the function argument or return value, respectively, and the function’s parameter or return object is initialized as if by using the non-deleted trivial constructor to copy the temporary (even if that constructor is inaccessible or would not be selected by overload resolution to perform a copy or move of the object). [ Note: This latitude is granted to allow objects of class type to be passed to or returned from functions in registers. — end note ]

like image 657
Oliv Avatar asked Nov 07 '22 16:11

Oliv


1 Answers

I believe this is a clang bug.

From [class.temporary]:

Temporary objects are created [...] when needed by the implementation to pass or return an object of trivially-copyable type (see below), and [...]

Even when the creation of the temporary object is unevaluated ([expr.prop]), all the semantic restrictions shall be respected as if the temporary object had been created and later destroyed. [ Note: This includes accessibility and whether it is deleted, for the constructor selected and for the destructor. However, in the special case of the operand of a decltype-specifier ([expr.call]), no temporary is introduced, so the foregoing does not apply to such a prvalue. — end note ]

The copy-initialization of the return of foo is a context that creates a temporary object, so the semantic restrictions must still be followed - which include the accessibility of the destructor (as the note helps make clear). ~A() must be accessible in this context, and isn't, so the program should be ill-formed. gcc is correct to reject.

like image 50
Barry Avatar answered Nov 14 '22 20:11

Barry