@@ -1758,19 +1758,14 @@ 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 ) {
1775
1770
not resultIsVoid ( ) and
1776
1771
(
@@ -1866,13 +1861,13 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
1866
1861
)
1867
1862
}
1868
1863
1869
- override predicate hasTempVariable ( TempVariableTag tag , CppType type ) {
1864
+ final override predicate hasTempVariable ( TempVariableTag tag , CppType type ) {
1870
1865
not resultIsVoid ( ) and
1871
1866
tag = ConditionValueTempVar ( ) and
1872
1867
type = getResultType ( )
1873
1868
}
1874
1869
1875
- override IRVariable getInstructionVariable ( InstructionTag tag ) {
1870
+ final override IRVariable getInstructionVariable ( InstructionTag tag ) {
1876
1871
not resultIsVoid ( ) and
1877
1872
(
1878
1873
tag = ConditionValueTrueTempAddressTag ( ) or
@@ -1882,25 +1877,75 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
1882
1877
result = getTempVariable ( ConditionValueTempVar ( ) )
1883
1878
}
1884
1879
1885
- override Instruction getResult ( ) {
1880
+ final override Instruction getResult ( ) {
1886
1881
not resultIsVoid ( ) and
1887
1882
result = getInstruction ( ConditionValueResultLoadTag ( ) )
1888
1883
}
1889
1884
1890
1885
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
1891
1943
(
1892
1944
child = getThen ( ) and
1893
1945
if thenIsVoid ( )
1894
1946
then result = getParent ( ) .getChildSuccessor ( this )
1895
1947
else result = getInstruction ( ConditionValueTrueTempAddressTag ( ) )
1896
1948
)
1897
- or
1898
- (
1899
- child = getElse ( ) and
1900
- if elseIsVoid ( )
1901
- then result = getParent ( ) .getChildSuccessor ( this )
1902
- else result = getInstruction ( ConditionValueFalseTempAddressTag ( ) )
1903
- )
1904
1949
}
1905
1950
1906
1951
override Instruction getChildTrueSuccessor ( TranslatedCondition child ) {
@@ -1917,31 +1962,81 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
1917
1962
result = getTranslatedCondition ( expr .getCondition ( ) .getFullyConverted ( ) )
1918
1963
}
1919
1964
1920
- private TranslatedExpr getThen ( ) {
1965
+ final override TranslatedExpr getThen ( ) {
1921
1966
result = getTranslatedExpr ( expr .getThen ( ) .getFullyConverted ( ) )
1922
1967
}
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 ( ) }
1923
1979
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 ( )
1926
1986
}
1927
1987
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 )
1930
1992
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 ( )
1934
1997
}
1935
1998
1936
- private predicate elseIsVoid ( ) {
1937
- getElse ( ) . getResultType ( ) . getIRType ( ) instanceof IRVoidType
1999
+ override Instruction getInstructionSuccessor ( InstructionTag tag , EdgeKind kind ) {
2000
+ result = super . getInstructionSuccessor ( tag , kind )
1938
2001
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
+ )
1942
2010
}
1943
2011
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
+ }
1945
2040
}
1946
2041
1947
2042
/**
0 commit comments