Skip to content

Commit 21a8c92

Browse files
authored
[clang][bytecode] Add special handling for union copy assign operators (llvm#125476)
1 parent 76e73ae commit 21a8c92

File tree

3 files changed

+55
-5
lines changed

3 files changed

+55
-5
lines changed

clang/lib/AST/ByteCode/Compiler.cpp

+25-4
Original file line numberDiff line numberDiff line change
@@ -4676,7 +4676,7 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
46764676
OCE && OCE->isAssignmentOp()) {
46774677
// Just like with regular assignments, we need to special-case assignment
46784678
// operators here and evaluate the RHS (the second arg) before the LHS (the
4679-
// first arg. We fix this by using a Flip op later.
4679+
// first arg). We fix this by using a Flip op later.
46804680
assert(Args.size() == 2);
46814681
IsAssignmentOperatorCall = true;
46824682
std::reverse(Args.begin(), Args.end());
@@ -5664,6 +5664,21 @@ bool Compiler<Emitter>::compileDestructor(const CXXDestructorDecl *Dtor) {
56645664
return this->emitPopPtr(Dtor) && this->emitRetVoid(Dtor);
56655665
}
56665666

5667+
template <class Emitter>
5668+
bool Compiler<Emitter>::compileUnionCopyAssignmentOperator(
5669+
const CXXMethodDecl *MD) {
5670+
if (!this->emitThis(MD))
5671+
return false;
5672+
5673+
auto PVD = MD->getParamDecl(0);
5674+
ParamOffset PO = this->Params[PVD]; // Must exist.
5675+
5676+
if (!this->emitGetParam(PT_Ptr, PO.Offset, MD))
5677+
return false;
5678+
5679+
return this->emitMemcpy(MD) && this->emitRet(PT_Ptr, MD);
5680+
}
5681+
56675682
template <class Emitter>
56685683
bool Compiler<Emitter>::visitFunc(const FunctionDecl *F) {
56695684
// Classify the return type.
@@ -5675,9 +5690,15 @@ bool Compiler<Emitter>::visitFunc(const FunctionDecl *F) {
56755690
return this->compileDestructor(Dtor);
56765691

56775692
// Emit custom code if this is a lambda static invoker.
5678-
if (const auto *MD = dyn_cast<CXXMethodDecl>(F);
5679-
MD && MD->isLambdaStaticInvoker())
5680-
return this->emitLambdaStaticInvokerBody(MD);
5693+
if (const auto *MD = dyn_cast<CXXMethodDecl>(F)) {
5694+
const RecordDecl *RD = MD->getParent();
5695+
5696+
if (RD->isUnion() && MD->isCopyAssignmentOperator())
5697+
return this->compileUnionCopyAssignmentOperator(MD);
5698+
5699+
if (MD->isLambdaStaticInvoker())
5700+
return this->emitLambdaStaticInvokerBody(MD);
5701+
}
56815702

56825703
// Regular functions.
56835704
if (const auto *Body = F->getBody())

clang/lib/AST/ByteCode/Compiler.h

+1
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
383383
bool emitBuiltinBitCast(const CastExpr *E);
384384
bool compileConstructor(const CXXConstructorDecl *Ctor);
385385
bool compileDestructor(const CXXDestructorDecl *Dtor);
386+
bool compileUnionCopyAssignmentOperator(const CXXMethodDecl *MD);
386387

387388
bool checkLiteralType(const Expr *E);
388389

clang/test/AST/ByteCode/unions.cpp

+29-1
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,6 @@ namespace UnionInBase {
402402
static_assert(return_uninit().a.x == 2);
403403
}
404404

405-
/// FIXME: Our diagnostic here is a little off.
406405
namespace One {
407406
struct A { long x; };
408407

@@ -421,4 +420,33 @@ namespace One {
421420
// both-note {{constinit}}
422421
}
423422

423+
namespace CopyAssign {
424+
union A {
425+
int a;
426+
int b;
427+
};
428+
429+
constexpr int f() {
430+
A a{12};
431+
A b{13};
432+
433+
b.b = 32;
434+
b = a ;
435+
return b.a;
436+
}
437+
static_assert(f()== 12);
438+
439+
440+
constexpr int f2() {
441+
A a{12};
442+
A b{13};
443+
444+
b.b = 32;
445+
b = a ;
446+
return b.b; // both-note {{read of member 'b' of union with active member 'a'}}
447+
}
448+
static_assert(f2() == 12); // both-error {{not an integral constant expression}} \
449+
// both-note {{in call to}}
450+
451+
}
424452
#endif

0 commit comments

Comments
 (0)