@@ -367,14 +367,18 @@ class ReturnIndirectionNode extends IndirectReturnNode, ReturnNode {
367367 }
368368}
369369
370- private Operand fullyConvertedCallStep ( Operand op ) {
370+ private Operand fullyConvertedCallStepImpl ( Operand op ) {
371371 not exists ( getANonConversionUse ( op ) ) and
372372 exists ( Instruction instr |
373373 conversionFlow ( op , instr , _, _) and
374374 result = getAUse ( instr )
375375 )
376376}
377377
378+ private Operand fullyConvertedCallStep ( Operand op ) {
379+ result = unique( | | fullyConvertedCallStepImpl ( op ) )
380+ }
381+
378382/**
379383 * Gets the instruction that uses this operand, if the instruction is not
380384 * ignored for dataflow purposes.
@@ -401,10 +405,21 @@ private Instruction getANonConversionUse(Operand operand) {
401405}
402406
403407/**
404- * Gets the operand that represents the first use of the value of `call` following
408+ * Gets an operand that represents the use of the value of `call` following
405409 * a sequence of conversion-like instructions.
410+ *
411+ * Note that `operand` is not functionally determined by `call` since there
412+ * can be multiple sequences of disjoint conversions following a call. For example,
413+ * consider an example like:
414+ * ```cpp
415+ * long f();
416+ * int y;
417+ * long x = (long)(y = (int)f());
418+ * ```
419+ * in this case, there'll be a long-to-int conversion on `f()` before the value is assigned to `y`,
420+ * and there will be an int-to-long conversion on `(int)f()` before the value is assigned to `x`.
406421 */
407- predicate operandForFullyConvertedCall ( Operand operand , CallInstruction call ) {
422+ private predicate operandForFullyConvertedCallImpl ( Operand operand , CallInstruction call ) {
408423 exists ( getANonConversionUse ( operand ) ) and
409424 (
410425 operand = getAUse ( call )
@@ -413,6 +428,25 @@ predicate operandForFullyConvertedCall(Operand operand, CallInstruction call) {
413428 )
414429}
415430
431+ /**
432+ * Gets the operand that represents the use of the value of `call` following
433+ * a sequence of conversion-like instructions, if a unique operand exists.
434+ */
435+ predicate operandForFullyConvertedCall ( Operand operand , CallInstruction call ) {
436+ operand = unique( Operand cand | operandForFullyConvertedCallImpl ( cand , call ) )
437+ }
438+
439+ private predicate instructionForFullyConvertedCallWithConversions (
440+ Instruction instr , CallInstruction call
441+ ) {
442+ // Otherwise, flow to the first non-conversion use.
443+ instr =
444+ getUse ( unique( Operand operand |
445+ operand = fullyConvertedCallStep * ( getAUse ( call ) ) and
446+ not exists ( fullyConvertedCallStep ( operand ) )
447+ ) )
448+ }
449+
416450/**
417451 * Gets the instruction that represents the first use of the value of `call` following
418452 * a sequence of conversion-like instructions.
@@ -424,13 +458,10 @@ predicate instructionForFullyConvertedCall(Instruction instr, CallInstruction ca
424458 not operandForFullyConvertedCall ( _, call ) and
425459 (
426460 // If there is no use of the call then we pick the call instruction
427- not exists ( getAUse ( call ) ) and
461+ not instructionForFullyConvertedCallWithConversions ( _ , call ) and
428462 instr = call
429463 or
430- // Otherwise, flow to the first non-conversion use.
431- exists ( Operand operand | operand = fullyConvertedCallStep * ( getAUse ( call ) ) |
432- instr = getANonConversionUse ( operand )
433- )
464+ instructionForFullyConvertedCallWithConversions ( instr , call )
434465 )
435466}
436467
0 commit comments