nickdesaulniers updated this revision to Diff 542607.
nickdesaulniers marked an inline comment as done.
nickdesaulniers added a comment.
- force ForRef to false for CK_LValueToRValue CastExprs, as per @efriedma
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D151587/new/
https://reviews.llvm.org/D151587
Files:
clang/lib/AST/Expr.cpp
clang/lib/AST/ExprConstant.cpp
clang/lib/CodeGen/CGExprConstant.cpp
clang/test/CodeGenCXX/const-init-cxx11.cpp
clang/test/CodeGenCXX/const-init-cxx1y.cpp
clang/test/CodeGenOpenCL/amdgpu-nullptr.cl
Index: clang/test/CodeGenOpenCL/amdgpu-nullptr.cl
===================================================================
--- clang/test/CodeGenOpenCL/amdgpu-nullptr.cl
+++ clang/test/CodeGenOpenCL/amdgpu-nullptr.cl
@@ -57,7 +57,7 @@
// CHECK: @fold_generic ={{.*}} local_unnamed_addr addrspace(1) global ptr null, align 8
generic int *fold_generic = (global int*)(generic float*)(private char*)0;
-// CHECK: @fold_priv ={{.*}} local_unnamed_addr addrspace(1) global ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), align 4
+// CHECK: @fold_priv ={{.*}} local_unnamed_addr addrspace(1) global ptr addrspace(5) addrspacecast (ptr addrspace(1) null to ptr addrspace(5)), align 4
private short *fold_priv = (private short*)(generic int*)(global void*)0;
// CHECK: @fold_priv_arith ={{.*}} local_unnamed_addr addrspace(1) global ptr addrspace(5) inttoptr (i32 9 to ptr addrspace(5)), align 4
Index: clang/test/CodeGenCXX/const-init-cxx1y.cpp
===================================================================
--- clang/test/CodeGenCXX/const-init-cxx1y.cpp
+++ clang/test/CodeGenCXX/const-init-cxx1y.cpp
@@ -34,8 +34,8 @@
// 'c.temporary', not the value as modified by the partial evaluation within
// the initialization of 'c.x'.
A c = { 10, (++c.temporary, b.x) };
- // CHECK: @_ZGRN21ModifyStaticTemporary1cE_ = internal global i32 10
// CHECK: @_ZN21ModifyStaticTemporary1cE ={{.*}} global {{.*}} zeroinitializer
+ // CHECK: @_ZGRN21ModifyStaticTemporary1cE_ = internal global i32 10
}
// CHECK: @_ZGRN28VariableTemplateWithConstRef1iIvEE_ = linkonce_odr constant i32 5, align 4
@@ -76,6 +76,19 @@
S *p = &s<1, 2, 3, 4>;
}
+
+// CHECK: @_ZGR1z_ ={{.*}} global [2 x i32] [i32 10, i32 2]
+// CHECK: @z = global { ptr, i32 } { ptr @_ZGR1z_, i32 10 }
+typedef int v[2];
+struct Z { int &&x, y; };
+Z z = { v{1,2}[0], z.x = 10 };
+
+// CHECK: @_ZGR2z2_ ={{.*}} global %struct.R { i64 10 }
+// @z = {{.}} global %struct.Z { ptr @_ZGR1z_, %struct.R { i64 10 } }
+struct R { mutable long x; };
+struct Z2 { const R &x, y; };
+Z2 z2 = { R{1}, z2.x.x = 10 };
+
// CHECK: __cxa_atexit({{.*}} @_ZN1BD1Ev, {{.*}} @b
// CHECK: define
Index: clang/test/CodeGenCXX/const-init-cxx11.cpp
===================================================================
--- clang/test/CodeGenCXX/const-init-cxx11.cpp
+++ clang/test/CodeGenCXX/const-init-cxx11.cpp
@@ -88,7 +88,7 @@
struct E {};
struct Test2 : X<E,0>, X<E,1>, X<E,2>, X<E,3> {};
- // CHECK: @_ZN9BaseClass2t2E ={{.*}} constant {{.*}} undef
+ // CHECK: @_ZN9BaseClass2t2E ={{.*}} constant {{.*}} zeroinitializer, align 1
extern constexpr Test2 t2 = Test2();
struct __attribute((packed)) PackedD { double y = 2; };
Index: clang/lib/CodeGen/CGExprConstant.cpp
===================================================================
--- clang/lib/CodeGen/CGExprConstant.cpp
+++ clang/lib/CodeGen/CGExprConstant.cpp
@@ -1215,11 +1215,6 @@
return Visit(E->getSubExpr(), T);
}
- llvm::Constant *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E,
- QualType T) {
- return Visit(E->getSubExpr(), T);
- }
-
llvm::Constant *EmitArrayInitialization(InitListExpr *ILE, QualType T) {
auto *CAT = CGM.getContext().getAsConstantArrayType(ILE->getType());
assert(CAT && "can't emit array init for non-constant-bound array");
@@ -1322,7 +1317,12 @@
assert(CGM.getContext().hasSameUnqualifiedType(Ty, Arg->getType()) &&
"argument to copy ctor is of wrong type");
- return Visit(Arg, Ty);
+ // Look through the temporary; it's just converting the value to an
+ // lvalue to pass it to the constructor.
+ if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Arg))
+ return Visit(MTE->getSubExpr(), Ty);
+ // Don't try to support arbitrary lvalue-to-rvalue conversions for now.
+ return nullptr;
}
return CGM.EmitNullConstant(Ty);
@@ -1654,29 +1654,22 @@
InConstantContext = D.hasConstantInitialization();
QualType destType = D.getType();
+ const Expr *E = D.getInit();
+ assert(E && "No initializer to emit");
+
+ if (!destType->isReferenceType()) {
+ QualType nonMemoryDestType = getNonMemoryType(CGM, destType);
+ if (llvm::Constant *C = ConstExprEmitter(*this).Visit(const_cast<Expr *>(E),
+ nonMemoryDestType))
+ return emitForMemory(C, destType);
+ }
// Try to emit the initializer. Note that this can allow some things that
// are not allowed by tryEmitPrivateForMemory alone.
- if (auto value = D.evaluateValue()) {
+ if (APValue *value = D.evaluateValue())
return tryEmitPrivateForMemory(*value, destType);
- }
-
- // FIXME: Implement C++11 [basic.start.init]p2: if the initializer of a
- // reference is a constant expression, and the reference binds to a temporary,
- // then constant initialization is performed. ConstExprEmitter will
- // incorrectly emit a prvalue constant in this case, and the calling code
- // interprets that as the (pointer) value of the reference, rather than the
- // desired value of the referee.
- if (destType->isReferenceType())
- return nullptr;
-
- const Expr *E = D.getInit();
- assert(E && "No initializer to emit");
- auto nonMemoryDestType = getNonMemoryType(CGM, destType);
- auto C =
- ConstExprEmitter(*this).Visit(const_cast<Expr*>(E), nonMemoryDestType);
- return (C ? emitForMemory(C, destType) : nullptr);
+ return nullptr;
}
llvm::Constant *
@@ -1743,6 +1736,10 @@
QualType destType) {
assert(!destType->isVoidType() && "can't emit a void constant");
+ if (llvm::Constant *C =
+ ConstExprEmitter(*this).Visit(const_cast<Expr *>(E), destType))
+ return C;
+
Expr::EvalResult Result;
bool Success = false;
@@ -1752,13 +1749,10 @@
else
Success = E->EvaluateAsRValue(Result, CGM.getContext(), InConstantContext);
- llvm::Constant *C;
if (Success && !Result.HasSideEffects)
- C = tryEmitPrivate(Result.Val, destType);
- else
- C = ConstExprEmitter(*this).Visit(const_cast<Expr*>(E), destType);
+ return tryEmitPrivate(Result.Val, destType);
- return C;
+ return nullptr;
}
llvm::Constant *CodeGenModule::getNullPointer(llvm::PointerType *T, QualType QT) {
Index: clang/lib/AST/ExprConstant.cpp
===================================================================
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -8381,6 +8381,9 @@
bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
const MaterializeTemporaryExpr *E) {
+ if (Info.EvalMode == EvalInfo::EM_ConstantFold)
+ return false;
+
// Walk through the expression to find the materialized temporary itself.
SmallVector<const Expr *, 2> CommaLHSs;
SmallVector<SubobjectAdjustment, 2> Adjustments;
@@ -8388,8 +8391,8 @@
E->getSubExpr()->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
// If we passed any comma operators, evaluate their LHSs.
- for (unsigned I = 0, N = CommaLHSs.size(); I != N; ++I)
- if (!EvaluateIgnoredValue(Info, CommaLHSs[I]))
+ for (const Expr *E : CommaLHSs)
+ if (!EvaluateIgnoredValue(Info, E))
return false;
// A materialized temporary with static storage duration can appear within the
@@ -15472,7 +15475,7 @@
EStatus.Diag = &Notes;
EvalInfo Info(Ctx, EStatus,
- (IsConstantInitialization && Ctx.getLangOpts().CPlusPlus11)
+ (IsConstantInitialization && Ctx.getLangOpts().CPlusPlus)
? EvalInfo::EM_ConstantExpression
: EvalInfo::EM_ConstantFold);
Info.setEvaluatingDecl(VD, Value);
Index: clang/lib/AST/Expr.cpp
===================================================================
--- clang/lib/AST/Expr.cpp
+++ clang/lib/AST/Expr.cpp
@@ -3317,16 +3317,6 @@
//
// If we ever capture reference-binding directly in the AST, we can
// kill the second parameter.
-
- if (IsForRef) {
- EvalResult Result;
- if (EvaluateAsLValue(Result, Ctx) && !Result.HasSideEffects)
- return true;
- if (Culprit)
- *Culprit = this;
- return false;
- }
-
switch (getStmtClass()) {
default: break;
case Stmt::ExprWithCleanupsClass:
@@ -3450,23 +3440,28 @@
const CastExpr *CE = cast<CastExpr>(this);
// Handle misc casts we want to ignore.
- if (CE->getCastKind() == CK_NoOp ||
- CE->getCastKind() == CK_LValueToRValue ||
- CE->getCastKind() == CK_ToUnion ||
- CE->getCastKind() == CK_ConstructorConversion ||
- CE->getCastKind() == CK_NonAtomicToAtomic ||
- CE->getCastKind() == CK_AtomicToNonAtomic ||
- CE->getCastKind() == CK_NullToPointer ||
- CE->getCastKind() == CK_IntToOCLSampler)
+ switch (CE->getCastKind()) {
+ case CK_LValueToRValue:
+ // The LValue is not a ref.
return CE->getSubExpr()->isConstantInitializer(Ctx, false, Culprit);
-
+ case CK_NoOp:
+ case CK_ToUnion:
+ case CK_ConstructorConversion:
+ case CK_NonAtomicToAtomic:
+ case CK_AtomicToNonAtomic:
+ case CK_NullToPointer:
+ case CK_IntToOCLSampler:
+ return CE->getSubExpr()->isConstantInitializer(Ctx, IsForRef, Culprit);
+ default:
+ break;
+ }
break;
}
case MaterializeTemporaryExprClass:
+ // A MaterializeTemporaryExprClass sub-expression is always an RValue.
return cast<MaterializeTemporaryExpr>(this)
->getSubExpr()
->isConstantInitializer(Ctx, false, Culprit);
-
case SubstNonTypeTemplateParmExprClass:
return cast<SubstNonTypeTemplateParmExpr>(this)->getReplacement()
->isConstantInitializer(Ctx, false, Culprit);
@@ -3477,11 +3472,17 @@
return cast<CXXDefaultInitExpr>(this)->getExpr()
->isConstantInitializer(Ctx, false, Culprit);
}
+
+ if (IsForRef) {
+ EvalResult Result;
+ if (EvaluateAsLValue(Result, Ctx) && !Result.HasSideEffects)
+ return true;
// Allow certain forms of UB in constant initializers: signed integer
// overflow and floating-point division by zero. We'll give a warning on
// these, but they're common enough that we have to accept them.
- if (isEvaluatable(Ctx, SE_AllowUndefinedBehavior))
+ } else if (isEvaluatable(Ctx, SE_AllowUndefinedBehavior))
return true;
+
if (Culprit)
*Culprit = this;
return false;
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits