@@ -1758,19 +1758,14 @@ 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 ) {
17751770 not resultIsVoid ( ) and
17761771 (
@@ -1866,13 +1861,13 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
18661861 )
18671862 }
18681863
1869- override predicate hasTempVariable ( TempVariableTag tag , CppType type ) {
1864+ final override predicate hasTempVariable ( TempVariableTag tag , CppType type ) {
18701865 not resultIsVoid ( ) and
18711866 tag = ConditionValueTempVar ( ) and
18721867 type = getResultType ( )
18731868 }
18741869
1875- override IRVariable getInstructionVariable ( InstructionTag tag ) {
1870+ final override IRVariable getInstructionVariable ( InstructionTag tag ) {
18761871 not resultIsVoid ( ) and
18771872 (
18781873 tag = ConditionValueTrueTempAddressTag ( ) or
@@ -1882,25 +1877,75 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
18821877 result = getTempVariable ( ConditionValueTempVar ( ) )
18831878 }
18841879
1885- override Instruction getResult ( ) {
1880+ final override Instruction getResult ( ) {
18861881 not resultIsVoid ( ) and
18871882 result = getInstruction ( ConditionValueResultLoadTag ( ) )
18881883 }
18891884
18901885 override Instruction getChildSuccessor ( TranslatedElement child ) {
1886+ child = getElse ( ) and
1887+ if elseIsVoid ( )
1888+ then result = getParent ( ) .getChildSuccessor ( this )
1889+ else result = getInstruction ( ConditionValueFalseTempAddressTag ( ) )
1890+ }
1891+
1892+ /**
1893+ * Gets the `TranslatedExpr` for the "then" result. Note that nothing in the base implementation
1894+ * of this class assumes that `getThen()` is disjoint from `getCondition()`.
1895+ */
1896+ abstract TranslatedExpr getThen ( ) ;
1897+
1898+ /**
1899+ * Gets the `TranslatedExpr` for the "else" result.
1900+ */
1901+ final TranslatedExpr getElse ( ) { result = getTranslatedExpr ( expr .getElse ( ) .getFullyConverted ( ) ) }
1902+
1903+ final predicate thenIsVoid ( ) {
1904+ getThen ( ) .getResultType ( ) .getIRType ( ) instanceof IRVoidType
1905+ or
1906+ // A `ThrowExpr.getType()` incorrectly returns the type of exception being
1907+ // thrown, rather than `void`. Handle that case here.
1908+ expr .getThen ( ) instanceof ThrowExpr
1909+ }
1910+
1911+ private predicate elseIsVoid ( ) {
1912+ getElse ( ) .getResultType ( ) .getIRType ( ) instanceof IRVoidType
1913+ or
1914+ // A `ThrowExpr.getType()` incorrectly returns the type of exception being
1915+ // thrown, rather than `void`. Handle that case here.
1916+ expr .getElse ( ) instanceof ThrowExpr
1917+ }
1918+
1919+ private predicate resultIsVoid ( ) { getResultType ( ) .getIRType ( ) instanceof IRVoidType }
1920+ }
1921+
1922+ /**
1923+ * The IR translation of the ternary conditional operator (`a ? b : c`).
1924+ * For this version, we expand the condition as a `TranslatedCondition`, rather than a
1925+ * `TranslatedExpr`, to simplify the control flow in the presence of short-ciruit logical operators.
1926+ */
1927+ class TranslatedTernaryConditionalExpr extends TranslatedConditionalExpr , ConditionContext {
1928+ TranslatedTernaryConditionalExpr ( ) { not expr .isTwoOperand ( ) }
1929+
1930+ final override TranslatedElement getChild ( int id ) {
1931+ id = 0 and result = getCondition ( )
1932+ or
1933+ id = 1 and result = getThen ( )
1934+ or
1935+ id = 2 and result = getElse ( )
1936+ }
1937+
1938+ override Instruction getFirstInstruction ( ) { result = getCondition ( ) .getFirstInstruction ( ) }
1939+
1940+ override Instruction getChildSuccessor ( TranslatedElement child ) {
1941+ result = TranslatedConditionalExpr .super .getChildSuccessor ( child )
1942+ or
18911943 (
18921944 child = getThen ( ) and
18931945 if thenIsVoid ( )
18941946 then result = getParent ( ) .getChildSuccessor ( this )
18951947 else result = getInstruction ( ConditionValueTrueTempAddressTag ( ) )
18961948 )
1897- or
1898- (
1899- child = getElse ( ) and
1900- if elseIsVoid ( )
1901- then result = getParent ( ) .getChildSuccessor ( this )
1902- else result = getInstruction ( ConditionValueFalseTempAddressTag ( ) )
1903- )
19041949 }
19051950
19061951 override Instruction getChildTrueSuccessor ( TranslatedCondition child ) {
@@ -1917,31 +1962,81 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
19171962 result = getTranslatedCondition ( expr .getCondition ( ) .getFullyConverted ( ) )
19181963 }
19191964
1920- private TranslatedExpr getThen ( ) {
1965+ final override TranslatedExpr getThen ( ) {
19211966 result = getTranslatedExpr ( expr .getThen ( ) .getFullyConverted ( ) )
19221967 }
1968+ }
1969+
1970+ /**
1971+ * The IR translation of a two-operand conditional operator (`a ?: b`). This is a GCC language
1972+ * extension.
1973+ * This version of the conditional expression returns its first operand (the condition) if that
1974+ * condition is non-zero. Since we'll be reusing the value of the condition, we'll compute that
1975+ * value directly before branching, even if that value was a short-circuit logical expression.
1976+ */
1977+ class TranslatedBinaryConditionalExpr extends TranslatedConditionalExpr {
1978+ TranslatedBinaryConditionalExpr ( ) { expr .isTwoOperand ( ) }
19231979
1924- private TranslatedExpr getElse ( ) {
1925- result = getTranslatedExpr ( expr .getElse ( ) .getFullyConverted ( ) )
1980+ final override TranslatedElement getChild ( int id ) {
1981+ // We only truly have two children, because our "condition" and "then" are the same as far as
1982+ // the extractor is concerned.
1983+ id = 0 and result = getCondition ( )
1984+ or
1985+ id = 1 and result = getElse ( )
19261986 }
19271987
1928- private predicate thenIsVoid ( ) {
1929- getThen ( ) .getResultType ( ) .getIRType ( ) instanceof IRVoidType
1988+ override Instruction getFirstInstruction ( ) { result = getCondition ( ) .getFirstInstruction ( ) }
1989+
1990+ override predicate hasInstruction ( Opcode opcode , InstructionTag tag , CppType resultType ) {
1991+ super .hasInstruction ( opcode , tag , resultType )
19301992 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
1993+ // For the binary variant, we create our own conditional branch.
1994+ tag = ValueConditionConditionalBranchTag ( ) and
1995+ opcode instanceof Opcode:: ConditionalBranch and
1996+ resultType = getVoidType ( )
19341997 }
19351998
1936- private predicate elseIsVoid ( ) {
1937- getElse ( ) . getResultType ( ) . getIRType ( ) instanceof IRVoidType
1999+ override Instruction getInstructionSuccessor ( InstructionTag tag , EdgeKind kind ) {
2000+ result = super . getInstructionSuccessor ( tag , kind )
19382001 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
2002+ tag = ValueConditionConditionalBranchTag ( ) and
2003+ (
2004+ kind instanceof TrueEdge and
2005+ result = getInstruction ( ConditionValueTrueTempAddressTag ( ) )
2006+ or
2007+ kind instanceof FalseEdge and
2008+ result = getElse ( ) .getFirstInstruction ( )
2009+ )
19422010 }
19432011
1944- private predicate resultIsVoid ( ) { getResultType ( ) .getIRType ( ) instanceof IRVoidType }
2012+ override Instruction getInstructionOperand ( InstructionTag tag , OperandTag operandTag ) {
2013+ result = super .getInstructionOperand ( tag , operandTag )
2014+ or
2015+ tag = ValueConditionConditionalBranchTag ( ) and
2016+ operandTag instanceof ConditionOperandTag and
2017+ result = getCondition ( ) .getResult ( )
2018+ }
2019+
2020+ override Instruction getChildSuccessor ( TranslatedElement child ) {
2021+ result = super .getChildSuccessor ( child )
2022+ or
2023+ child = getCondition ( ) and result = getInstruction ( ValueConditionConditionalBranchTag ( ) )
2024+ }
2025+
2026+ private TranslatedExpr getCondition ( ) {
2027+ result = getTranslatedExpr ( expr .getCondition ( ) .getFullyConverted ( ) )
2028+ }
2029+
2030+ final override TranslatedExpr getThen ( ) {
2031+ // The extractor returns the exact same expression for `ConditionalExpr::getCondition()` and
2032+ // `ConditionalExpr::getThen()`, even though the condition may have been converted to `bool`,
2033+ // and the "then" may have been converted to the result type. We'll strip the top-level implicit
2034+ // conversions from this, to skip any conversion to `bool`. We don't have enough information to
2035+ // know how to convert the result to the destination type, especially in the class pointer case,
2036+ // so we'll still sometimes wind up with one operand as the wrong type. This is better than
2037+ // always converting the "then" operand to `bool`, which is almost always the wrong type.
2038+ result = getTranslatedExpr ( expr .getThen ( ) .getExplicitlyConverted ( ) )
2039+ }
19452040}
19462041
19472042/**
0 commit comments