@@ -227,6 +227,24 @@ private predicate usedAsCondition(Expr expr) {
227227 )
228228}
229229
230+ /**
231+ * Holds if `conv` is an `InheritanceConversion` that requires a `TranslatedLoad`, despite not being
232+ * marked as having an lvalue-to-rvalue conversion.
233+ *
234+ * This is necessary for an `InheritanceConversion` that is originally modeled as a
235+ * prvalue-to-prvalue conversion, since we transform it into a glvalue-to-glvalue conversion. If it
236+ * is actually consumed as a prvalue, such as on the right hand side of an assignment, we need to
237+ * load the resulting glvalue.
238+ */
239+ private predicate isInheritanceConversionWithImplicitLoad ( InheritanceConversion conv ) {
240+ // Must have originally been a prvalue-to-prvalue conversion.
241+ isClassPRValue ( conv .getExpr ( ) ) and
242+ not conv .hasLValueToRValueConversion ( ) and
243+ // Exclude that case where this will be consumed as a glvalue, such as when used as the qualifier
244+ // of a field access.
245+ not isPRValueConversionOnGLValue ( conv )
246+ }
247+
230248/**
231249 * Holds if `expr` is the result of a field access whose qualifier was a prvalue and whose result is
232250 * a prvalue. These accesses are not marked as having loads, but we do need a load in the IR.
@@ -241,35 +259,93 @@ private predicate isPRValueFieldAccessWithImplicitLoad(Expr expr) {
241259}
242260
243261/**
244- * Holds if `expr` is a prvalue of class type that is used directly as the qualifier for a member
245- * access, or is used after undergoing a prvalue adjustment conversion.
262+ * Holds if `expr` is a prvalue of class type.
263+ *
264+ * This same test is used in several places.
265+ */
266+ pragma [ inline]
267+ private predicate isClassPRValue ( Expr expr ) {
268+ expr .isPRValueCategory ( ) and
269+ expr .getUnspecifiedType ( ) instanceof Class
270+ }
271+
272+ /**
273+ * Holds if `expr` is consumed as a glvalue by its parent. If `expr` is actually a prvalue, it will
274+ * have any lvalue-to-rvalue conversion ignored. If it does not have an lvalue-to-rvalue conversion,
275+ * it will be materialized into a temporary object.
246276 */
247- private predicate isClassPRValueForMemberAccessQualifier ( Expr expr ) {
248- exists ( Expr qualifier |
249- exists ( FieldAccess access | qualifier = access .getQualifier ( ) .getFullyConverted ( ) )
277+ private predicate consumedAsGLValue ( Expr expr ) {
278+ isClassPRValue ( expr ) and
279+ (
280+ // Qualifier of a field access.
281+ expr = any ( FieldAccess a ) .getQualifier ( ) .getFullyConverted ( )
250282 or
251- exists ( Call call | qualifier = call .getQualifier ( ) .getFullyConverted ( ) )
252- |
253- // The qualifier is a prvalue of class type.
254- qualifier .getUnspecifiedType ( ) instanceof Class and
255- qualifier .isPRValueCategory ( ) and
283+ // Qualifier of a member function call.
284+ expr = any ( Call c ) .getQualifier ( ) .getFullyConverted ( )
285+ or
286+ // The operand of an inheritance conversion.
287+ expr = any ( InheritanceConversion c ) .getExpr ( )
288+ )
289+ }
290+
291+ /**
292+ * Holds if `expr` is a conversion that is originally a prvalue-to-prvalue conversion, but which is
293+ * applied to a prvalue that will actually be consumed as a glvalue.
294+ */
295+ predicate isPRValueConversionOnGLValue ( Conversion conv ) {
296+ exists ( Expr consumed |
297+ consumedAsGLValue ( consumed ) and
298+ isClassPRValue ( conv .getExpr ( ) ) and
299+ (
300+ // Example: The conversion of `std::string` to `const std::string` when evaluating
301+ // `std::string("foo").c_str()`.
302+ conv instanceof PrvalueAdjustmentConversion
303+ or
304+ // Parentheses are transparent.
305+ conv instanceof ParenthesisExpr
306+ or
307+ // Example: The base class conversion in `f().m()`, when `m` is member function of a base
308+ // class of the return type of `f()`.
309+ conv instanceof InheritanceConversion
310+ ) and
256311 (
257- expr = qualifier and not expr instanceof PrvalueAdjustmentConversion
312+ // Base case: The conversion is consumed directly.
313+ conv = consumed
258314 or
259- // If the qualifier is a prvalue adjustment conversion, the actual object with be provided by
260- // the operand of that conversion. For example:
261- // ```c++
262- // std::string("s").c_str();
263- // ```
264- // The object for the qualifier is a prvalue(load) of type `std::string`, but the actual
265- // fully-converted qualifier of the call to `c_str()` is a prvalue adjustment conversion that
266- // converts the type to `const std::string` to match the type of the `this` pointer of the
267- // member function.
268- expr = qualifier .( PrvalueAdjustmentConversion ) .getExpr ( )
315+ // Recursive case: The conversion is the operand of another prvalue conversion.
316+ isPRValueConversionOnGLValue ( conv .getConversion ( ) )
269317 )
270318 )
271319}
272320
321+ /**
322+ * Holds if `expr` is a prvalue of class type that is used in a context that requires a glvalue.
323+ *
324+ * Any conversions between `expr` and the ancestor that consumes the glvalue will also be treated
325+ * as glvalues, but are not part of this relation.
326+ *
327+ * For example:
328+ * ```c++
329+ * std::string("s").c_str();
330+ * ```
331+ * The object for the qualifier is a prvalue(load) of type `std::string`, but the actual
332+ * fully-converted qualifier of the call to `c_str()` is a prvalue adjustment conversion that
333+ * converts the type to `const std::string` to match the type of the `this` pointer of the
334+ * member function. In this case, `mustTransformToGLValue()` will hold for the temporary
335+ * `std::string` object, but not the prvalue adjustment on top of it.
336+ * `isPRValueConversionOnGLValue()` would hold for the prvalue adjustment.
337+ */
338+ private predicate mustTransformToGLValue ( Expr expr ) {
339+ not isPRValueConversionOnGLValue ( expr ) and
340+ (
341+ // The expression is the fully converted qualifier, with no prvalue adjustments on top.
342+ consumedAsGLValue ( expr )
343+ or
344+ // The expression has conversions on top, but they are all prvalue adjustments.
345+ isPRValueConversionOnGLValue ( expr .getConversion ( ) )
346+ )
347+ }
348+
273349/**
274350 * Holds if `expr` has an lvalue-to-rvalue conversion that should be ignored
275351 * when generating IR. This occurs for conversion from an lvalue of function type
@@ -294,7 +370,7 @@ predicate ignoreLoad(Expr expr) {
294370 // the temporary object if the original qualifier was a prvalue. For IR purposes, we always want
295371 // to use the address of the temporary object as the qualifier of a field access or the `this`
296372 // argument to a member function call.
297- isClassPRValueForMemberAccessQualifier ( expr )
373+ mustTransformToGLValue ( expr )
298374 )
299375}
300376
@@ -332,6 +408,8 @@ predicate hasTranslatedLoad(Expr expr) {
332408 needsLoadForParentExpr ( expr )
333409 or
334410 isPRValueFieldAccessWithImplicitLoad ( expr )
411+ or
412+ isInheritanceConversionWithImplicitLoad ( expr )
335413 ) and
336414 not ignoreExpr ( expr ) and
337415 not isNativeCondition ( expr ) and
@@ -344,7 +422,7 @@ predicate hasTranslatedLoad(Expr expr) {
344422 */
345423predicate hasTranslatedSyntheticTemporaryObject ( Expr expr ) {
346424 not ignoreExpr ( expr ) and
347- isClassPRValueForMemberAccessQualifier ( expr ) and
425+ mustTransformToGLValue ( expr ) and
348426 // If it's a load, we'll just ignore the load in `ignoreLoad()`.
349427 not expr .hasLValueToRValueConversion ( )
350428}
0 commit comments