@@ -1758,20 +1758,20 @@ class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr, St
17581758 private TranslatedExpr getDestructorCall() { result = getTranslatedExpr(expr.getExpr()) }
17591759}
17601760
1761- class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionContext {
1761+ /**
1762+ * The IR translation of the `?:` operator. This class has the portions of the implementation that
1763+ * are shared between the standard three-operand form (`a ? b : c`) and the GCC-extension
1764+ * two-operand form (`a ?: c`).
1765+ */
1766+ abstract class TranslatedConditionalExpr extends TranslatedNonConstantExpr {
17621767 override ConditionalExpr expr;
17631768
1764- final override TranslatedElement getChild(int id) {
1765- id = 0 and result = getCondition()
1766- or
1767- id = 1 and result = getThen()
1768- or
1769- id = 2 and result = getElse()
1770- }
1771-
1772- override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() }
1773-
17741769 override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
1770+ // Note that the ternary flavor needs no explicit `ConditionalBranch` instruction here, because
1771+ // the condition is a `TranslatedCondition`, which will simply connect the successor edges of
1772+ // the condition directly to the appropriate then/else block via
1773+ // `getChild[True|False]Successor()`.
1774+ // The binary flavor will override this predicate to add the `ConditionalBranch`.
17751775 not resultIsVoid() and
17761776 (
17771777 (
@@ -1866,13 +1866,13 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
18661866 )
18671867 }
18681868
1869- override predicate hasTempVariable(TempVariableTag tag, CppType type) {
1869+ final override predicate hasTempVariable(TempVariableTag tag, CppType type) {
18701870 not resultIsVoid() and
18711871 tag = ConditionValueTempVar() and
18721872 type = getResultType()
18731873 }
18741874
1875- override IRVariable getInstructionVariable(InstructionTag tag) {
1875+ final override IRVariable getInstructionVariable(InstructionTag tag) {
18761876 not resultIsVoid() and
18771877 (
18781878 tag = ConditionValueTrueTempAddressTag() or
@@ -1882,25 +1882,75 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
18821882 result = getTempVariable(ConditionValueTempVar())
18831883 }
18841884
1885- override Instruction getResult() {
1885+ final override Instruction getResult() {
18861886 not resultIsVoid() and
18871887 result = getInstruction(ConditionValueResultLoadTag())
18881888 }
18891889
18901890 override Instruction getChildSuccessor(TranslatedElement child) {
1891+ child = getElse() and
1892+ if elseIsVoid()
1893+ then result = getParent().getChildSuccessor(this)
1894+ else result = getInstruction(ConditionValueFalseTempAddressTag())
1895+ }
1896+
1897+ /**
1898+ * Gets the `TranslatedExpr` for the "then" result. Note that nothing in the base implementation
1899+ * of this class assumes that `getThen()` is disjoint from `getCondition()`.
1900+ */
1901+ abstract TranslatedExpr getThen();
1902+
1903+ /**
1904+ * Gets the `TranslatedExpr` for the "else" result.
1905+ */
1906+ final TranslatedExpr getElse() { result = getTranslatedExpr(expr.getElse().getFullyConverted()) }
1907+
1908+ final predicate thenIsVoid() {
1909+ getThen().getResultType().getIRType() instanceof IRVoidType
1910+ or
1911+ // A `ThrowExpr.getType()` incorrectly returns the type of exception being
1912+ // thrown, rather than `void`. Handle that case here.
1913+ expr.getThen() instanceof ThrowExpr
1914+ }
1915+
1916+ private predicate elseIsVoid() {
1917+ getElse().getResultType().getIRType() instanceof IRVoidType
1918+ or
1919+ // A `ThrowExpr.getType()` incorrectly returns the type of exception being
1920+ // thrown, rather than `void`. Handle that case here.
1921+ expr.getElse() instanceof ThrowExpr
1922+ }
1923+
1924+ private predicate resultIsVoid() { getResultType().getIRType() instanceof IRVoidType }
1925+ }
1926+
1927+ /**
1928+ * The IR translation of the ternary conditional operator (`a ? b : c`).
1929+ * For this version, we expand the condition as a `TranslatedCondition`, rather than a
1930+ * `TranslatedExpr`, to simplify the control flow in the presence of short-ciruit logical operators.
1931+ */
1932+ class TranslatedTernaryConditionalExpr extends TranslatedConditionalExpr, ConditionContext {
1933+ TranslatedTernaryConditionalExpr() { not expr.isTwoOperand() }
1934+
1935+ final override TranslatedElement getChild(int id) {
1936+ id = 0 and result = getCondition()
1937+ or
1938+ id = 1 and result = getThen()
1939+ or
1940+ id = 2 and result = getElse()
1941+ }
1942+
1943+ override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() }
1944+
1945+ override Instruction getChildSuccessor(TranslatedElement child) {
1946+ result = TranslatedConditionalExpr.super.getChildSuccessor(child)
1947+ or
18911948 (
18921949 child = getThen() and
18931950 if thenIsVoid()
18941951 then result = getParent().getChildSuccessor(this)
18951952 else result = getInstruction(ConditionValueTrueTempAddressTag())
18961953 )
1897- or
1898- (
1899- child = getElse() and
1900- if elseIsVoid()
1901- then result = getParent().getChildSuccessor(this)
1902- else result = getInstruction(ConditionValueFalseTempAddressTag())
1903- )
19041954 }
19051955
19061956 override Instruction getChildTrueSuccessor(TranslatedCondition child) {
@@ -1917,31 +1967,81 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
19171967 result = getTranslatedCondition(expr.getCondition().getFullyConverted())
19181968 }
19191969
1920- private TranslatedExpr getThen() {
1970+ final override TranslatedExpr getThen() {
19211971 result = getTranslatedExpr(expr.getThen().getFullyConverted())
19221972 }
1973+ }
1974+
1975+ /**
1976+ * The IR translation of a two-operand conditional operator (`a ?: b`). This is a GCC language
1977+ * extension.
1978+ * This version of the conditional expression returns its first operand (the condition) if that
1979+ * condition is non-zero. Since we'll be reusing the value of the condition, we'll compute that
1980+ * value directly before branching, even if that value was a short-circuit logical expression.
1981+ */
1982+ class TranslatedBinaryConditionalExpr extends TranslatedConditionalExpr {
1983+ TranslatedBinaryConditionalExpr() { expr.isTwoOperand() }
19231984
1924- private TranslatedExpr getElse() {
1925- result = getTranslatedExpr(expr.getElse().getFullyConverted())
1985+ final override TranslatedElement getChild(int id) {
1986+ // We only truly have two children, because our "condition" and "then" are the same as far as
1987+ // the extractor is concerned.
1988+ id = 0 and result = getCondition()
1989+ or
1990+ id = 1 and result = getElse()
19261991 }
19271992
1928- private predicate thenIsVoid() {
1929- getThen().getResultType().getIRType() instanceof IRVoidType
1993+ override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() }
1994+
1995+ override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
1996+ super.hasInstruction(opcode, tag, resultType)
19301997 or
1931- // A `ThrowExpr.getType()` incorrectly returns the type of exception being
1932- // thrown, rather than `void`. Handle that case here.
1933- expr.getThen() instanceof ThrowExpr
1998+ // For the binary variant, we create our own conditional branch.
1999+ tag = ValueConditionConditionalBranchTag() and
2000+ opcode instanceof Opcode::ConditionalBranch and
2001+ resultType = getVoidType()
19342002 }
19352003
1936- private predicate elseIsVoid( ) {
1937- getElse().getResultType().getIRType() instanceof IRVoidType
2004+ override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind ) {
2005+ result = super.getInstructionSuccessor(tag, kind)
19382006 or
1939- // A `ThrowExpr.getType()` incorrectly returns the type of exception being
1940- // thrown, rather than `void`. Handle that case here.
1941- expr.getElse() instanceof ThrowExpr
2007+ tag = ValueConditionConditionalBranchTag() and
2008+ (
2009+ kind instanceof TrueEdge and
2010+ result = getInstruction(ConditionValueTrueTempAddressTag())
2011+ or
2012+ kind instanceof FalseEdge and
2013+ result = getElse().getFirstInstruction()
2014+ )
19422015 }
19432016
1944- private predicate resultIsVoid() { getResultType().getIRType() instanceof IRVoidType }
2017+ override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
2018+ result = super.getInstructionOperand(tag, operandTag)
2019+ or
2020+ tag = ValueConditionConditionalBranchTag() and
2021+ operandTag instanceof ConditionOperandTag and
2022+ result = getCondition().getResult()
2023+ }
2024+
2025+ override Instruction getChildSuccessor(TranslatedElement child) {
2026+ result = super.getChildSuccessor(child)
2027+ or
2028+ child = getCondition() and result = getInstruction(ValueConditionConditionalBranchTag())
2029+ }
2030+
2031+ private TranslatedExpr getCondition() {
2032+ result = getTranslatedExpr(expr.getCondition().getFullyConverted())
2033+ }
2034+
2035+ final override TranslatedExpr getThen() {
2036+ // The extractor returns the exact same expression for `ConditionalExpr::getCondition()` and
2037+ // `ConditionalExpr::getThen()`, even though the condition may have been converted to `bool`,
2038+ // and the "then" may have been converted to the result type. We'll strip the top-level implicit
2039+ // conversions from this, to skip any conversion to `bool`. We don't have enough information to
2040+ // know how to convert the result to the destination type, especially in the class pointer case,
2041+ // so we'll still sometimes wind up with one operand as the wrong type. This is better than
2042+ // always converting the "then" operand to `bool`, which is almost always the wrong type.
2043+ result = getTranslatedExpr(expr.getThen().getExplicitlyConverted())
2044+ }
19452045}
19462046
19472047/**
0 commit comments