Index: clang/lib/AST/Interp/ByteCodeExprGen.h =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.h +++ clang/lib/AST/Interp/ByteCodeExprGen.h @@ -179,6 +179,9 @@ return this->emitPopPtr(I); } + template + bool visitConditional(const AbstractConditionalOperator *E, Visitor V); + /// Creates a local primitive value. unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsMutable, bool IsExtended = false); Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -589,32 +589,12 @@ template bool ByteCodeExprGen::VisitAbstractConditionalOperator( const AbstractConditionalOperator *E) { - const Expr *Condition = E->getCond(); - const Expr *TrueExpr = E->getTrueExpr(); - const Expr *FalseExpr = E->getFalseExpr(); - - LabelTy LabelEnd = this->getLabel(); // Label after the operator. - LabelTy LabelFalse = this->getLabel(); // Label for the false expr. - - if (!this->visit(Condition)) - return false; - if (!this->jumpFalse(LabelFalse)) - return false; - - if (!this->visit(TrueExpr)) - return false; - if (!this->jump(LabelEnd)) - return false; - - this->emitLabel(LabelFalse); - - if (!this->visit(FalseExpr)) - return false; - - this->fallthrough(LabelEnd); - this->emitLabel(LabelEnd); - - return true; + struct Visitor { + ByteCodeExprGen *BEG; + bool visit(const Expr *E) { return BEG->visit(E); } + }; + Visitor V{this}; + return this->visitConditional(E, V); } template @@ -929,6 +909,41 @@ } } +/// Visit a conditional operator, i.e. `A ? B : C`. +/// \V determines what function to call for the B and C expressions. +template +template +bool ByteCodeExprGen::visitConditional( + const AbstractConditionalOperator *E, Visitor V) { + + const Expr *Condition = E->getCond(); + const Expr *TrueExpr = E->getTrueExpr(); + const Expr *FalseExpr = E->getFalseExpr(); + + LabelTy LabelEnd = this->getLabel(); // Label after the operator. + LabelTy LabelFalse = this->getLabel(); // Label for the false expr. + + if (!this->visit(Condition)) + return false; + if (!this->jumpFalse(LabelFalse)) + return false; + + if (!V.visit(TrueExpr)) + return false; + if (!this->jump(LabelEnd)) + return false; + + this->emitLabel(LabelFalse); + + if (!V.visit(FalseExpr)) + return false; + + this->fallthrough(LabelEnd); + this->emitLabel(LabelEnd); + + return true; +} + template bool ByteCodeExprGen::visitZeroInitializer(PrimType T, const Expr *E) { switch (T) { @@ -1419,6 +1434,14 @@ return this->visitInitializer(CE->getSubExpr()); } else if (const auto *CE = dyn_cast(Initializer)) { return this->visitInitializer(CE->getSubExpr()); + } else if (const auto *ACO = + dyn_cast(Initializer)) { + struct Visitor { + ByteCodeExprGen *BEG; + bool visit(const Expr *E) { return BEG->visitRecordInitializer(E); } + }; + Visitor V{this}; + return this->visitConditional(ACO, V); } // Explictly reject these. They only get generated for invalid code. Index: clang/test/AST/Interp/records.cpp =================================================================== --- clang/test/AST/Interp/records.cpp +++ clang/test/AST/Interp/records.cpp @@ -335,3 +335,14 @@ constexpr piecewise_construct_t piecewise_construct = piecewise_construct_t(); }; + +namespace ConditionalInit { + struct S { int a; }; + + constexpr S getS(bool b) { + return b ? S{12} : S{13}; + } + + static_assert(getS(true).a == 12, ""); + static_assert(getS(false).a == 13, ""); +};