diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll index 58456476f6a2..7e9f7760b5a8 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll @@ -430,14 +430,18 @@ private predicate mustTransformToGLValue(Expr expr) { } /** - * Holds if `expr` has an lvalue-to-rvalue conversion that should be ignored - * when generating IR. This occurs for conversion from an lvalue of function type - * to an rvalue of function pointer type. The conversion is represented in the - * AST as an lvalue-to-rvalue conversion, but the IR represents both a function + * Holds if `expr` has an explicit or implicit load that should be ignored + * when generating IR. For example, this occurs for conversion from an lvalue of + * function type to an rvalue of function pointer type. The conversion is represented + * in the AST as an lvalue-to-rvalue conversion, but the IR represents both a function * lvalue and a function pointer prvalue the same. */ predicate ignoreLoad(Expr expr) { - expr.hasLValueToRValueConversion() and + ( + expr.hasLValueToRValueConversion() + or + isPRValueFieldAccessWithImplicitLoad(expr) + ) and ( expr instanceof ThisExpr or @@ -517,8 +521,11 @@ predicate hasTranslatedLoad(Expr expr) { predicate hasTranslatedSyntheticTemporaryObject(Expr expr) { not ignoreExpr(expr) and mustTransformToGLValue(expr) and - // If it's a load, we'll just ignore the load in `ignoreLoad()`. - not expr.hasLValueToRValueConversion() + // If it's an explicit or implicit field load, reuse the existing address by + // ignoring the load in `ignoreLoad` instead of materializing another + // temporary. + not expr.hasLValueToRValueConversion() and + not isPRValueFieldAccessWithImplicitLoad(expr) } Opcode comparisonOpcode(ComparisonOperation expr) { diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected index f8a9e70fec7c..67e3c03d8f1f 100644 --- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected +++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected @@ -25804,6 +25804,30 @@ ir.cpp: # 2919| Conversion = [FloatingPointToIntegralConversion] floating point to integral conversion # 2919| Type = [IntType] int # 2919| ValueCategory = prvalue +# 2921| [CopyAssignmentOperator] PointerWrapper& PointerWrapper::operator=(PointerWrapper const&) +# 2921| : +#-----| getParameter(0): [Parameter] (unnamed parameter 0) +#-----| Type = [LValueReferenceType] const PointerWrapper & +# 2921| [MoveAssignmentOperator] PointerWrapper& PointerWrapper::operator=(PointerWrapper&&) +# 2921| : +#-----| getParameter(0): [Parameter] (unnamed parameter 0) +#-----| Type = [RValueReferenceType] PointerWrapper && +# 2925| [TopLevelFunction] PointerWrapper get_wrapper() +# 2925| : +# 2927| [TopLevelFunction] void test() +# 2927| : +# 2927| getEntryPoint(): [BlockStmt] { ... } +# 2928| getStmt(0): [ExprStmt] ExprStmt +# 2928| getExpr(): [ValueFieldAccess] x +# 2928| Type = [IntType] int +# 2928| ValueCategory = prvalue +# 2928| getQualifier(): [ValueFieldAccess] point +# 2928| Type = [Struct] Point +# 2928| ValueCategory = prvalue +# 2928| getQualifier(): [FunctionCall] call to get_wrapper +# 2928| Type = [Struct] PointerWrapper +# 2928| ValueCategory = prvalue +# 2929| getStmt(1): [ReturnStmt] return ... ir23.cpp: # 1| [TopLevelFunction] bool consteval_1() # 1| : diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected index 96035c165331..6efd5067acd1 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected @@ -21772,6 +21772,26 @@ ir.cpp: # 2919| v2919_13(void) = AliasedUse : ~m2919_11 # 2919| v2919_14(void) = ExitFunction : +# 2927| void test() +# 2927| Block 0 +# 2927| v2927_1(void) = EnterFunction : +# 2927| m2927_2(unknown) = AliasedDefinition : +# 2927| m2927_3(unknown) = InitializeNonLocal : +# 2927| m2927_4(unknown) = Chi : total:m2927_2, partial:m2927_3 +# 2928| r2928_1(glval) = FunctionAddress[get_wrapper] : +# 2928| r2928_2(PointerWrapper) = Call[get_wrapper] : func:r2928_1 +# 2928| m2928_3(unknown) = ^CallSideEffect : ~m2927_4 +# 2928| m2928_4(unknown) = Chi : total:m2927_4, partial:m2928_3 +# 2928| r2928_5(glval) = VariableAddress[#temp2928:3] : +# 2928| m2928_6(PointerWrapper) = Store[#temp2928:3] : &:r2928_5, r2928_2 +# 2928| r2928_7(glval) = FieldAddress[point] : r2928_5 +# 2928| r2928_8(glval) = FieldAddress[x] : r2928_7 +# 2928| r2928_9(int) = Load[?] : &:r2928_8, ~m2928_6 +# 2929| v2929_1(void) = NoOp : +# 2927| v2927_5(void) = ReturnVoid : +# 2927| v2927_6(void) = AliasedUse : ~m2928_4 +# 2927| v2927_7(void) = ExitFunction : + ir23.cpp: # 1| bool consteval_1() # 1| Block 0 diff --git a/cpp/ql/test/library-tests/ir/ir/ir.cpp b/cpp/ql/test/library-tests/ir/ir/ir.cpp index 1d2d4d5a79e3..7bab60fbb21e 100644 --- a/cpp/ql/test/library-tests/ir/ir/ir.cpp +++ b/cpp/ql/test/library-tests/ir/ir/ir.cpp @@ -2918,4 +2918,14 @@ T VariableTemplateFunc(T x) { int VariableTemplateFuncUse = VariableTemplateFunc(2.3); +struct PointerWrapper { + Point point; +}; + +PointerWrapper get_wrapper(); + +void test() { + get_wrapper().point.x; +} + // semmle-extractor-options: -std=c++20 --clang diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 05ab6c50d703..be7d41ad09a4 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -19777,6 +19777,24 @@ ir.cpp: # 2919| v2919_11(void) = AliasedUse : ~m? # 2919| v2919_12(void) = ExitFunction : +# 2927| void test() +# 2927| Block 0 +# 2927| v2927_1(void) = EnterFunction : +# 2927| mu2927_2(unknown) = AliasedDefinition : +# 2927| mu2927_3(unknown) = InitializeNonLocal : +# 2928| r2928_1(glval) = FunctionAddress[get_wrapper] : +# 2928| r2928_2(PointerWrapper) = Call[get_wrapper] : func:r2928_1 +# 2928| mu2928_3(unknown) = ^CallSideEffect : ~m? +# 2928| r2928_4(glval) = VariableAddress[#temp2928:3] : +# 2928| mu2928_5(PointerWrapper) = Store[#temp2928:3] : &:r2928_4, r2928_2 +# 2928| r2928_6(glval) = FieldAddress[point] : r2928_4 +# 2928| r2928_7(glval) = FieldAddress[x] : r2928_6 +# 2928| r2928_8(int) = Load[?] : &:r2928_7, ~m? +# 2929| v2929_1(void) = NoOp : +# 2927| v2927_4(void) = ReturnVoid : +# 2927| v2927_5(void) = AliasedUse : ~m? +# 2927| v2927_6(void) = ExitFunction : + ir23.cpp: # 1| bool consteval_1() # 1| Block 0