diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -8643,9 +8643,13 @@ case SK_ArrayLoopIndex: { Expr *Cur = CurInit.get(); - Expr *BaseExpr = new (S.Context) - OpaqueValueExpr(Cur->getExprLoc(), Cur->getType(), - Cur->getValueKind(), Cur->getObjectKind(), Cur); + // Prevent nested OpaqueValueExprs. + Expr *BaseExpr = dyn_cast(Cur); + if (!BaseExpr) { + BaseExpr = new (S.Context) + OpaqueValueExpr(Cur->getExprLoc(), Cur->getType(), + Cur->getValueKind(), Cur->getObjectKind(), Cur); + } Expr *IndexExpr = new (S.Context) ArrayInitIndexExpr(S.Context.getSizeType()); CurInit = S.CreateBuiltinArraySubscriptExpr( diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -10511,7 +10511,18 @@ TreeTransform::TransformOpaqueValueExpr(OpaqueValueExpr *E) { assert((!E->getSourceExpr() || getDerived().AlreadyTransformed(E->getType())) && "opaque value expression requires transformation"); - return E; + + // Note that SourceExpr can be nullptr. + ExprResult SourceExpr = TransformExpr(E->getSourceExpr()); + if (SourceExpr.isInvalid()) + return ExprError(); + if (SourceExpr.get() == E->getSourceExpr() && !getDerived().AlwaysRebuild()) + return E; + + OpaqueValueExpr *New = new (SemaRef.Context) + OpaqueValueExpr(E->getExprLoc(), E->getType(), E->getValueKind(), + E->getObjectKind(), SourceExpr.get()); + return New; } template diff --git a/clang/test/CodeGenCXX/pr45964-decomp-transform.cpp b/clang/test/CodeGenCXX/pr45964-decomp-transform.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/pr45964-decomp-transform.cpp @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -std=c++1z -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s + +int a[1]; +// CHECK: @a = global [1 x i32] zeroinitializer +template +void test_transform() { + auto [b] = a; +} +void (*d)(){test_transform<0>}; +// CHECK-LABEL: define {{.*}} @_Z14test_transformILi0EEvv +// CHECK: [[ENTRY:.*]]: +// CHECK-NEXT: [[ARR:%.*]] = alloca [1 x i32] +// CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [1 x i32], [1 x i32]* [[ARR]], i64 0, i64 0 +// CHECK-NEXT: br label %[[BODY:.*]] +// CHECK-EMPTY: +// CHECK-NEXT: [[BODY]]: +// CHECK-NEXT: [[CUR:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[NEXT:%.*]], %[[BODY]] ] +// CHECK-NEXT: [[DEST:%.*]] = getelementptr inbounds i32, i32* [[BEGIN]], i64 [[CUR]] +// CHECK-NEXT: [[SRC:%.*]] = getelementptr inbounds [1 x i32], [1 x i32]* @a, i64 0, i64 [[CUR]] +// CHECK-NEXT: [[X:%.*]] = load i32, i32* [[SRC]] +// CHECK-NEXT: store i32 [[X]], i32* [[DEST]] +// CHECK-NEXT: [[NEXT]] = add nuw i64 [[CUR]], 1 +// CHECK-NEXT: [[EQ:%.*]] = icmp eq i64 [[NEXT]], 1 +// CHECK-NEXT: br i1 [[EQ]], label %[[FIN:.*]], label %[[BODY]] +// CHECK-EMPTY: +// CHECK-NEXT: [[FIN]]: +// CHECK-NEXT: ret void