[PATCH] D45476: [C++2a] Implement operator<=> CodeGen and ExprConstant

John McCall via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Fri May 4 10:48:55 PDT 2018


rjmccall added a comment.

In https://reviews.llvm.org/D45476#1087487, @EricWF wrote:

> In https://reviews.llvm.org/D45476#1087446, @cfe-commits wrote:
>
> > I think you and Richard agreed that you weren’t going to synthesize a whole
> >  expression tree at every use of the operator, and I agree with that
> >  decision. That’s very different from what I’m asking you to do, which is to
> >  synthesize in isolation a call to the copy-constructor.
>
>
> Perhaps. My apologies. I'm still quite new to the Clang internals. I appreciate your patience.
>
> > There are several places in the compiler that require these implicit copies which aren’t just
> >  normal expressions; this is the common pattern for handling them. The
> >  synthesized expression can be emitted multiple times, and it can be freely
> >  re-synthesized in different translation units instead of being serialized.
>
> I'm not sure this is always the case. For example:
>
>   // foo.h -- compiled as module.
>   #include <compare>
>   struct Foo { int x; };
>   inline auto operator<=>(Foo const& LHS, Foo const& RHS) {
>     // CXXConstructExpr's would be built when initially building the expression
>     // below. But the caches in ASTContext would not be serialized.
>     return LHS.x <=> RHS.x;
>   }
>   // foo.cpp
>   #include <foo.h> // imported via module.
>   auto bar(Foo LHS, Foo RHS) {
>     // The expression below calls a user defined comparison operator,
>     // so Sema doesn't process any of the types in <compare>, but it
>     // does generate code for the inline function, which requires <compare>;
>     // but it's too late to synthesize a CXXConstructExpr. 
>     return LHS <=> RHS;
>   }
>
>
>
>
> > You’re already finding and caching a constructor; storing a
> >  CXXConstructExpr is basically thr same thing, but in a nicer form that
> >  handles more cases and doesn’t require as much redundant code in IRGen.
>
> I'm not actually caching the copy constructor. And I disagree that storing a
>  `CXXConstructExpr` is essentially the same thing. I can lookup the `CXXConstructorDecl` without `Sema`,
>  but I can't build a `CXXConstructExpr` without it.


Ah.  If you want to be able to find this thing without a Sema around in order to
handle deserialized expressions by just caching things in the ASTContext, yes,
I agree that it would be difficult to build a `CXXConstructExpr` correctly.  I don't
fully understand the goal of avoiding serialization here, though.

>> STLs *frequently* make use of default arguments on copy constructors (for
>>  allocators). I agree that it’s unlikely that that would happen here, but
>>  that’s precisely because it’s unlikely that this type would ever be
>>  non-trivial.
> 
> A couple of points. First, when I say copy constructor, I mean the special member, which
>  cannot have default arguments,

I'm sorry, but this is just not true.  The formation rules for a copy constructor are laid
out in [class.copy]p2, and they explicitly allow default arguments.

> Also note that it's always the case that at least one copy constructor participates
>  in overload resolution.

But it's not true that that copy constructor has to be selected by overload resolution.

> Second, in the synopsis for the STL types, no constructors are declared. Although I don't
>  think the standard spells it out anywhere, I believe this forbids the types from having user
>  defined constructors (though perhaps not user-declared explicitly defaulted constructors.
>  For example adding a user defined destructor would be non-conforming since it makes
>  the types non-literal).

That would certainly be helpful, but I don't think it's true; in general the standard describes
what things are guaranteed to work with library types, but it doesn't generally constrain
the existence of other operations.

> Third, the STL spec implicitly requires the comparison category types be `CopyConstructible`
>  (The comparison operators are pass by value, and the valid values are declared as const).

Yes, of course.

> Barring STL maintainers that are out of their mind, I posit that the copy constructor
>  `T(T const&)` will always be available.  However, the STL types are free to add base
>  classes and fields arbitrarily. I could imagine some weird reasons why STL's might
>  want to have non-trivial members or bases.

I think it is reasonable to assume that these types will always be copy-constructible
from a const l-value, but as mentioned above, that doesn't mean the copy-constructor
has to be declared as `T(T const &)`.

>> Mostly, though, I don’t understand the point of imposing a partial set of
>>  non-conformant restrictions on the type. It’s easy to support an arbitrary
>>  copy constructor by synthesizing a CXXConstructExpr, and this will
>>  magically take care of any constexpr issues, as well as removing the need
>>  for open-coding a constructor call.
> 
> Fully checking the validity of copy construction would be preferable. I'll
>  attempting to implement what you're suggesting, and work past the
>  problematic example given earlier.

Okay, thanks.

>> The constexpr issues are that certain references to constexpr variables of
>>  literal type (as these types are likely to be) are required to not ODR-use
>>  the variable but instead just directly produce the initializer as the
>>  expression result.
> 
> Ah, I see. So the standard already requires the category types to be literal.
>  So we can always avoid ODR use.
> 
>> That’s especially important here because (1) existing
>>  STL binaries will not define these variables, and we shouldn’t create
>>  artificial deployment problems for this feature, and (2) we’d really rather
>>  not emit these expressions as loads from externally-defined variables that
>>  the optimizer won’t be able to optimize.
> 
> The variables are declared as `inline` and `constexpr`. There won't be binary compatibility
>  issues nor problems with opaque definitions.

Ah, right, I'd forgotten that C++ finally added `inline` variables.  Yes, that would solve
the opaqueness and compatibility problems.

John.


https://reviews.llvm.org/D45476





More information about the cfe-commits mailing list