Author: Balázs Benics Date: 2026-07-26T11:34:29+01:00 New Revision: f3b31871e9b8e0fe07c92c91854861365ea189a4
URL: https://github.com/llvm/llvm-project/commit/f3b31871e9b8e0fe07c92c91854861365ea189a4 DIFF: https://github.com/llvm/llvm-project/commit/f3b31871e9b8e0fe07c92c91854861365ea189a4.diff LOG: [clang][CFG] Fix lambda capture evaluation order (#211877) Previously, the captures were emitted in their spelling order - but in the CFG that gets translared in a reversed order. Because of this, we need to emit them in reversed order to get them appear in their natural order. Fixes rdar://183140177 Added: clang/test/Analysis/lambda-capture-init-order.cpp Modified: clang/lib/Analysis/CFG.cpp Removed: ################################################################################ diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index bb8e98a894dab..efd1da9c9a4db 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -3617,11 +3617,12 @@ CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, AddStmtChoice asc) { CFGBlock *CFGBuilder::VisitLambdaExpr(LambdaExpr *E, AddStmtChoice asc) { CFGBlock *LastBlock = VisitNoRecurse(E, asc); - unsigned Idx = 0; - for (LambdaExpr::capture_init_iterator it = E->capture_init_begin(), - et = E->capture_init_end(); - it != et; ++it, ++Idx) { - if (Expr *Init = *it) { + // Visit the capture initializers in reverse order so they appear in + // left-to-right (natural) order in the CFG. + unsigned Idx = E->capture_size(); + for (Expr *Init : reverse(E->capture_inits())) { + --Idx; + if (Init) { // If the initializer is an ArrayInitLoopExpr, we want to extract the // initializer, that's used for each element. auto *AILEInit = extractElementInitializerFromNestedAILE( diff --git a/clang/test/Analysis/lambda-capture-init-order.cpp b/clang/test/Analysis/lambda-capture-init-order.cpp new file mode 100644 index 0000000000000..051bab3fed8c8 --- /dev/null +++ b/clang/test/Analysis/lambda-capture-init-order.cpp @@ -0,0 +1,63 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG \ +// RUN: -std=c++14 %s 2>&1 | FileCheck %s + +// RUN: %clang_analyze_cc1 -std=c++14 -analyzer-checker=core,cplusplus.Move \ +// RUN: -analyzer-output=text -verify %s + +#include "Inputs/system-header-simulator-cxx.h" + +struct S { + int v; + int use(S &) { return v; } +}; + +void safe_useThenMove() { + S s{7}; + auto lam = [x = s.use(s), y = std::move(s)]() mutable { + (void)x; + (void)y; + }; + lam(); // no-warning: the object is used before it is moved from. +} + +// CHECK-LABEL: void safe_useThenMove() +// CHECK: 1: 7 +// CHECK-NEXT: 2: {[B1.1]} +// CHECK-NEXT: 3: S s{7}; +// CHECK-NEXT: 4: s +// CHECK-NEXT: 5: [B1.4].use +// CHECK-NEXT: 6: s +// CHECK-NEXT: 7: [B1.5]([B1.6]) +// CHECK-NEXT: 8: std::move +// CHECK-NEXT: 9: [B1.8] (ImplicitCastExpr, BuiltinFnToFnPtr, typename remove_reference<S &>::type &&(*)(struct S &)) +// CHECK-NEXT: 10: s +// CHECK-NEXT: 11: [B1.9]([B1.10]) +// CHECK-NEXT: 12: [B1.11] (CXXConstructExpr{{.*}}, typename remove_reference<S &>::type) +// CHECK-NEXT: 13: [x = [B1.7], y = [B1.12]]() mutable { + +void unsafe_moveThenUse() { + S s{7}; + auto lam = [y = std::move(s), x = s.use(s)]() mutable { + // expected-warning@-1 {{Method called on moved-from object 's'}} + // expected-note@-2 {{Method called on moved-from object 's'}} + // expected-note@-3 {{Object 's' is moved}} + (void)x; + (void)y; + }; + lam(); +} + +// CHECK-LABEL: void unsafe_moveThenUse() +// CHECK: 1: 7 +// CHECK-NEXT: 2: {[B1.1]} +// CHECK-NEXT: 3: S s{7}; +// CHECK-NEXT: 4: std::move +// CHECK-NEXT: 5: [B1.4] (ImplicitCastExpr, BuiltinFnToFnPtr, typename remove_reference<S &>::type &&(*)(struct S &)) +// CHECK-NEXT: 6: s +// CHECK-NEXT: 7: [B1.5]([B1.6]) +// CHECK-NEXT: 8: [B1.7] (CXXConstructExpr{{.*}}, typename remove_reference<S &>::type) +// CHECK-NEXT: 9: s +// CHECK-NEXT: 10: [B1.9].use +// CHECK-NEXT: 11: s +// CHECK-NEXT: 12: [B1.10]([B1.11]) +// CHECK-NEXT: 13: [y = [B1.8], x = [B1.12]]() mutable { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
