@@ -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