mirror of
https://github.com/intel/llvm.git
synced 2026-01-24 17:01:00 +08:00
Fix non-determinism issue with implicit lambda captures.
We were using llvm::SmallPtrSet for our ODR-use set which was also used for instantiating the implicit lambda captures. The order in which the captures are added depends on this, so the lambda's layout ended up changing. The test just uses floats, but this was noticed with other types as well. This test replaces the short-lived SmallPtrSet (it lasts only for an expression, which, though is a long time for lambdas, is at least not forever) with a SmallSetVector.
This commit is contained in:
@@ -627,7 +627,7 @@ public:
|
||||
/// we won't know until all lvalue-to-rvalue and discarded value conversions
|
||||
/// have been applied to all subexpressions of the enclosing full expression.
|
||||
/// This is cleared at the end of each full expression.
|
||||
using MaybeODRUseExprSet = llvm::SmallPtrSet<Expr *, 2>;
|
||||
using MaybeODRUseExprSet = llvm::SmallSetVector<Expr *, 2>;
|
||||
MaybeODRUseExprSet MaybeODRUseExprs;
|
||||
|
||||
std::unique_ptr<sema::FunctionScopeInfo> CachedFunctionScope;
|
||||
|
||||
@@ -17553,7 +17553,7 @@ static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E,
|
||||
|
||||
// Mark that this expression does not constitute an odr-use.
|
||||
auto MarkNotOdrUsed = [&] {
|
||||
S.MaybeODRUseExprs.erase(E);
|
||||
S.MaybeODRUseExprs.remove(E);
|
||||
if (LambdaScopeInfo *LSI = S.getCurLambda())
|
||||
LSI->markVariableExprAsNonODRUsed(E);
|
||||
};
|
||||
|
||||
33
clang/test/CodeGenCXX/lambda-deterministic-captures.cpp
Normal file
33
clang/test/CodeGenCXX/lambda-deterministic-captures.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm --std=c++17 %s -o - | FileCheck %s
|
||||
|
||||
struct stream {
|
||||
friend const stream &operator<<(const stream &, const float &);
|
||||
};
|
||||
|
||||
void foo() {
|
||||
constexpr float f_zero = 0.0f;
|
||||
constexpr float f_one = 1.0f;
|
||||
constexpr float f_two = 2.0f;
|
||||
|
||||
stream s;
|
||||
[=]() {
|
||||
s << f_zero << f_one << f_two;
|
||||
}();
|
||||
}
|
||||
|
||||
// CHECK: define void @_Z3foov
|
||||
// CHECK: getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i32 0, i32 0
|
||||
// CHECK-NEXT: getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i32 0, i32 1
|
||||
// CHECK-NEXT: store float 0.000
|
||||
// CHECK-NEXT: getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i32 0, i32 2
|
||||
// CHECK-NEXT: store float 1.000
|
||||
// CHECK-NEXT: getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i32 0, i32 3
|
||||
// CHECK-NEXT: store float 2.000
|
||||
|
||||
// The lambda body. Reverse iteration when the captures aren't deterministic
|
||||
// causes these to be laid out differently in the lambda.
|
||||
// CHECK: define internal void
|
||||
// CHECK: getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i32 0, i32 0
|
||||
// CHECK: getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i32 0, i32 1
|
||||
// CHECK: getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i32 0, i32 2
|
||||
// CHECK: getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i32 0, i32 3
|
||||
Reference in New Issue
Block a user