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.

llvm-svn: 150789
This commit is contained in:
Richard Smith 2012-02-17 03:35:37 +00:00
parent a729c62b81
commit 14a941380a
3 changed files with 49 additions and 46 deletions

View File

@ -1499,6 +1499,20 @@ static unsigned getBaseIndex(const CXXRecordDecl *Derived,
llvm_unreachable("base class missing from derived class's bases list"); 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. /// Extract the designated sub-object of an rvalue.
static bool ExtractSubobject(EvalInfo &Info, const Expr *E, static bool ExtractSubobject(EvalInfo &Info, const Expr *E,
CCValue &Obj, QualType ObjType, CCValue &Obj, QualType ObjType,
@ -1518,7 +1532,6 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E,
// This object might be initialized later. // This object might be initialized later.
return false; return false;
assert(!Obj.isLValue() && "extracting subobject of lvalue");
const APValue *O = &Obj; const APValue *O = &Obj;
// Walk the designator's path to find the subobject. // Walk the designator's path to find the subobject.
for (unsigned I = 0, N = Sub.Entries.size(); I != N; ++I) { for (unsigned I = 0, N = Sub.Entries.size(); I != N; ++I) {
@ -1535,7 +1548,15 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E,
(unsigned)diag::note_invalid_subexpr_in_const_expr); (unsigned)diag::note_invalid_subexpr_in_const_expr);
return false; 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); O = &O->getArrayInitializedElt(Index);
else else
O = &O->getArrayFiller(); O = &O->getArrayFiller();
@ -1800,33 +1821,6 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
return false; 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 (Frame) {
// If this is a temporary expression with a nontrivial initializer, grab the // If this is a temporary expression with a nontrivial initializer, grab the
// value from the relevant stack frame. // value from the relevant stack frame.
@ -1839,6 +1833,13 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?"); assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?");
if (!Evaluate(RVal, Info, CLE->getInitializer())) if (!Evaluate(RVal, Info, CLE->getInitializer()))
return false; 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 { } else {
Info.Diag(Conv->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); Info.Diag(Conv->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
return false; return false;
@ -3777,7 +3778,8 @@ namespace {
: ExprEvaluatorBaseTy(Info), This(This), Result(Result) {} : ExprEvaluatorBaseTy(Info), This(This), Result(Result) {}
bool Success(const APValue &V, const Expr *E) { 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; Result = V;
return true; return true;
} }
@ -3822,22 +3824,9 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
LValue LV; LValue LV;
if (!EvaluateLValue(E->getInit(0), LV, Info)) if (!EvaluateLValue(E->getInit(0), LV, Info))
return false; return false;
uint64_t NumElements = CAT->getSize().getZExtValue(); CCValue Val;
Result = APValue(APValue::UninitArray(), NumElements, NumElements); LV.moveInto(Val);
return Success(Val, E);
// 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;
} }
bool Success = true; bool Success = true;

View File

@ -94,6 +94,14 @@ namespace Array {
// CHECK: @_ZN5Array1dE = constant {{.*}} { [2 x i32] [i32 1, i32 2], [3 x i32] [i32 3, i32 4, i32 5] } // 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 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 { namespace MemberPtr {

View File

@ -408,6 +408,12 @@ struct U {
} constexpr u = { { L"test" }, 0 }; } constexpr u = { { L"test" }, 0 };
static_assert(u.chars[2] == L's', ""); 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 { namespace Array {