From: Richard Smith Date: Fri, 17 Feb 2012 03:35:37 +0000 (+0000) Subject: Make sure all remaining parts of the constant evaluator are aware that an array X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f3908f2ae111b1b12ade2524dda71c669ed6f121;p=clang 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 0ef7111f97..6cbb69dae5 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -1499,6 +1499,20 @@ static unsigned getBaseIndex(const CXXRecordDecl *Derived, 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(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 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E, // 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 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E, (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(), Index)); + return true; + } else if (O->getArrayInitializedElts() > Index) O = &O->getArrayInitializedElt(Index); else O = &O->getArrayFiller(); @@ -1800,33 +1821,6 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, return false; } - // FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant - if (const StringLiteral *S = dyn_cast(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 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?"); if (!Evaluate(RVal, Info, CLE->getInitializer())) return false; + } else if (isa(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 @@ namespace { : 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 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { 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 fa56f59808..14a2f87717 100644 --- a/test/CodeGenCXX/const-init-cxx11.cpp +++ b/test/CodeGenCXX/const-init-cxx11.cpp @@ -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] } 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 f5cc1b31ca..a048297bb5 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -408,6 +408,12 @@ struct U { } 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 {