Make sure all remaining parts of the constant evaluator are aware that an array
can be represented by an LValue, and use that to simplify the code a little.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150789 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 0ef7111..6cbb69d 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -1499,6 +1499,20 @@
llvm_unreachable("base class missing from derived class's bases list");
}
+/// Extract the value of a character from a string literal.
+static APSInt ExtractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit,
+ uint64_t Index) {
+ // FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant
+ const StringLiteral *S = dyn_cast<StringLiteral>(Lit);
+ assert(S && "unexpected string literal expression kind");
+
+ APSInt Value(S->getCharByteWidth() * Info.Ctx.getCharWidth(),
+ Lit->getType()->getArrayElementTypeNoTypeQual()->isUnsignedIntegerType());
+ if (Index < S->getLength())
+ Value = S->getCodeUnit(Index);
+ return Value;
+}
+
/// Extract the designated sub-object of an rvalue.
static bool ExtractSubobject(EvalInfo &Info, const Expr *E,
CCValue &Obj, QualType ObjType,
@@ -1518,7 +1532,6 @@
// This object might be initialized later.
return false;
- assert(!Obj.isLValue() && "extracting subobject of lvalue");
const APValue *O = &Obj;
// Walk the designator's path to find the subobject.
for (unsigned I = 0, N = Sub.Entries.size(); I != N; ++I) {
@@ -1535,7 +1548,15 @@
(unsigned)diag::note_invalid_subexpr_in_const_expr);
return false;
}
- if (O->getArrayInitializedElts() > Index)
+ // An array object is represented as either an Array APValue or as an
+ // LValue which refers to a string literal.
+ if (O->isLValue()) {
+ assert(I == N - 1 && "extracting subobject of character?");
+ assert(!O->hasLValuePath() || O->getLValuePath().empty());
+ Obj = CCValue(ExtractStringLiteralCharacter(
+ Info, O->getLValueBase().get<const Expr*>(), Index));
+ return true;
+ } else if (O->getArrayInitializedElts() > Index)
O = &O->getArrayInitializedElt(Index);
else
O = &O->getArrayFiller();
@@ -1800,33 +1821,6 @@
return false;
}
- // FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant
- if (const StringLiteral *S = dyn_cast<StringLiteral>(Base)) {
- const SubobjectDesignator &Designator = LVal.Designator;
- if (Designator.Invalid || Designator.Entries.size() != 1) {
- Info.Diag(Conv->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
- return false;
- }
-
- assert(Type->isIntegerType() && "string element not integer type");
- uint64_t Index = Designator.Entries[0].ArrayIndex;
- const ConstantArrayType *CAT =
- Info.Ctx.getAsConstantArrayType(S->getType());
- if (Index >= CAT->getSize().getZExtValue()) {
- // Note, it should not be possible to form a pointer which points more
- // than one past the end of the array without producing a prior const expr
- // diagnostic.
- Info.Diag(Loc, diag::note_constexpr_read_past_end);
- return false;
- }
- APSInt Value(S->getCharByteWidth() * Info.Ctx.getCharWidth(),
- Type->isUnsignedIntegerType());
- if (Index < S->getLength())
- Value = S->getCodeUnit(Index);
- RVal = CCValue(Value);
- return true;
- }
-
if (Frame) {
// If this is a temporary expression with a nontrivial initializer, grab the
// value from the relevant stack frame.
@@ -1839,6 +1833,13 @@
assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?");
if (!Evaluate(RVal, Info, CLE->getInitializer()))
return false;
+ } else if (isa<StringLiteral>(Base)) {
+ // We represent a string literal array as an lvalue pointing at the
+ // corresponding expression, rather than building an array of chars.
+ // FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant
+ RVal = CCValue(Info.Ctx,
+ APValue(Base, CharUnits::Zero(), APValue::NoLValuePath(), 0),
+ CCValue::GlobalValue());
} else {
Info.Diag(Conv->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
return false;
@@ -3777,7 +3778,8 @@
: ExprEvaluatorBaseTy(Info), This(This), Result(Result) {}
bool Success(const APValue &V, const Expr *E) {
- assert(V.isArray() && "Expected array type");
+ assert((V.isArray() || V.isLValue()) &&
+ "expected array or string literal");
Result = V;
return true;
}
@@ -3822,22 +3824,9 @@
LValue LV;
if (!EvaluateLValue(E->getInit(0), LV, Info))
return false;
- uint64_t NumElements = CAT->getSize().getZExtValue();
- Result = APValue(APValue::UninitArray(), NumElements, NumElements);
-
- // Copy the string literal into the array. FIXME: Do this better.
- LV.addArray(Info, E, CAT);
- for (uint64_t I = 0; I < NumElements; ++I) {
- CCValue Char;
- if (!HandleLValueToRValueConversion(Info, E->getInit(0),
- CAT->getElementType(), LV, Char))
- return false;
- Result.getArrayInitializedElt(I) = Char.toAPValue();
- if (!HandleLValueArrayAdjustment(Info, E->getInit(0), LV,
- CAT->getElementType(), 1))
- return false;
- }
- return true;
+ CCValue Val;
+ LV.moveInto(Val);
+ return Success(Val, E);
}
bool Success = true;
diff --git a/test/CodeGenCXX/const-init-cxx11.cpp b/test/CodeGenCXX/const-init-cxx11.cpp
index fa56f59..14a2f87 100644
--- a/test/CodeGenCXX/const-init-cxx11.cpp
+++ b/test/CodeGenCXX/const-init-cxx11.cpp
@@ -94,6 +94,14 @@
// CHECK: @_ZN5Array1dE = constant {{.*}} { [2 x i32] [i32 1, i32 2], [3 x i32] [i32 3, i32 4, i32 5] }
struct D { int n[2]; int m[3]; } extern constexpr d = { 1, 2, 3, 4, 5 };
+
+ struct E {
+ char c[4];
+ char d[4];
+ constexpr E() : c("foo"), d("x") {}
+ };
+ // CHECK: @_ZN5Array1eE = global {{.*}} { [4 x i8] c"foo\00", [4 x i8] c"x\00\00\00" }
+ extern constexpr E e = E();
}
namespace MemberPtr {
diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp
index f5cc1b3..a048297 100644
--- a/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/test/SemaCXX/constant-expression-cxx11.cpp
@@ -408,6 +408,12 @@
} constexpr u = { { L"test" }, 0 };
static_assert(u.chars[2] == L's', "");
+struct V {
+ char c[4];
+ constexpr V() : c("hi!") {}
+};
+static_assert(V().c[1] == "i"[0], "");
+
}
namespace Array {