@@ -1758,20 +1758,20 @@ class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr, St
1758
1758
private TranslatedExpr getDestructorCall ( ) { result = getTranslatedExpr ( expr .getExpr ( ) ) }
1759
1759
}
1760
1760
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 {
1762
1767
override ConditionalExpr expr ;
1763
1768
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
-
1774
1769
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`.
1775
1775
not resultIsVoid ( ) and
1776
1776
(
1777
1777
(
@@ -1866,13 +1866,13 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
1866
1866
)
1867
1867
}
1868
1868
1869
- override predicate hasTempVariable ( TempVariableTag tag , CppType type ) {
1869
+ final override predicate hasTempVariable ( TempVariableTag tag , CppType type ) {
1870
1870
not resultIsVoid ( ) and
1871
1871
tag = ConditionValueTempVar ( ) and
1872
1872
type = getResultType ( )
1873
1873
}
1874
1874
1875
- override IRVariable getInstructionVariable ( InstructionTag tag ) {
1875
+ final override IRVariable getInstructionVariable ( InstructionTag tag ) {
1876
1876
not resultIsVoid ( ) and
1877
1877
(
1878
1878
tag = ConditionValueTrueTempAddressTag ( ) or
@@ -1882,25 +1882,75 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
1882
1882
result = getTempVariable ( ConditionValueTempVar ( ) )
1883
1883
}
1884
1884
1885
- override Instruction getResult ( ) {
1885
+ final override Instruction getResult ( ) {
1886
1886
not resultIsVoid ( ) and
1887
1887
result = getInstruction ( ConditionValueResultLoadTag ( ) )
1888
1888
}
1889
1889
1890
1890
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
1891
1948
(
1892
1949
child = getThen ( ) and
1893
1950
if thenIsVoid ( )
1894
1951
then result = getParent ( ) .getChildSuccessor ( this )
1895
1952
else result = getInstruction ( ConditionValueTrueTempAddressTag ( ) )
1896
1953
)
1897
- or
1898
- (
1899
- child = getElse ( ) and
1900
- if elseIsVoid ( )
1901
- then result = getParent ( ) .getChildSuccessor ( this )
1902
- else result = getInstruction ( ConditionValueFalseTempAddressTag ( ) )
1903
- )
1904
1954
}
1905
1955
1906
1956
override Instruction getChildTrueSuccessor ( TranslatedCondition child ) {
@@ -1917,31 +1967,81 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
1917
1967
result = getTranslatedCondition ( expr .getCondition ( ) .getFullyConverted ( ) )
1918
1968
}
1919
1969
1920
- private TranslatedExpr getThen ( ) {
1970
+ final override TranslatedExpr getThen ( ) {
1921
1971
result = getTranslatedExpr ( expr .getThen ( ) .getFullyConverted ( ) )
1922
1972
}
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 ( ) }
1923
1984
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 ( )
1926
1991
}
1927
1992
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 )
1930
1997
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 ( )
1934
2002
}
1935
2003
1936
- private predicate elseIsVoid ( ) {
1937
- getElse ( ) . getResultType ( ) . getIRType ( ) instanceof IRVoidType
2004
+ override Instruction getInstructionSuccessor ( InstructionTag tag , EdgeKind kind ) {
2005
+ result = super . getInstructionSuccessor ( tag , kind )
1938
2006
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
+ )
1942
2015
}
1943
2016
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
+ }
1945
2045
}
1946
2046
1947
2047
/**
0 commit comments