diff options
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/AST/APValue.cpp | 45 | ||||
| -rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 160 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGExprConstant.cpp | 3 |
3 files changed, 173 insertions, 35 deletions
diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp index e2f7c619376..af34642bead 100644 --- a/clang/lib/AST/APValue.cpp +++ b/clang/lib/AST/APValue.cpp @@ -55,6 +55,13 @@ struct APValue::LV : LVBase { } }; +// FIXME: Reduce the malloc traffic here. + +APValue::Arr::Arr(unsigned NumElts, unsigned Size) : + Elts(new APValue[NumElts + (NumElts != Size ? 1 : 0)]), + NumElts(NumElts), ArrSize(Size) {} +APValue::Arr::~Arr() { delete [] Elts; } + APValue::APValue(const Expr* B) : Kind(Uninitialized) { MakeLValue(); setLValue(B, CharUnits::Zero(), ArrayRef<LValuePathEntry>()); @@ -75,6 +82,8 @@ const APValue &APValue::operator=(const APValue &RHS) { MakeComplexFloat(); else if (RHS.isLValue()) MakeLValue(); + else if (RHS.isArray()) + MakeArray(RHS.getArrayInitializedElts(), RHS.getArraySize()); } if (isInt()) setInt(RHS.getInt()); @@ -92,6 +101,11 @@ const APValue &APValue::operator=(const APValue &RHS) { setLValue(RHS.getLValueBase(), RHS.getLValueOffset(),RHS.getLValuePath()); else setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), NoLValuePath()); + } else if (isArray()) { + for (unsigned I = 0, N = RHS.getArrayInitializedElts(); I != N; ++I) + getArrayInitializedElt(I) = RHS.getArrayInitializedElt(I); + if (RHS.hasArrayFiller()) + getArrayFiller() = RHS.getArrayFiller(); } return *this; } @@ -107,9 +121,10 @@ void APValue::MakeUninit() { ((ComplexAPSInt*)(char*)Data)->~ComplexAPSInt(); else if (Kind == ComplexFloat) ((ComplexAPFloat*)(char*)Data)->~ComplexAPFloat(); - else if (Kind == LValue) { + else if (Kind == LValue) ((LV*)(char*)Data)->~LV(); - } + else if (Kind == Array) + ((Arr*)(char*)Data)->~Arr(); Kind = Uninitialized; } @@ -149,9 +164,20 @@ void APValue::print(raw_ostream &OS) const { case ComplexFloat: OS << "ComplexFloat: " << GetApproxValue(getComplexFloatReal()) << ", " << GetApproxValue(getComplexFloatImag()); + return; case LValue: OS << "LValue: <todo>"; return; + case Array: + OS << "Array: "; + for (unsigned I = 0, N = getArrayInitializedElts(); I != N; ++I) { + OS << getArrayInitializedElt(I); + if (I != getArraySize() - 1) OS << ", "; + } + if (hasArrayFiller()) + OS << getArraySize() - getArrayInitializedElts() << " x " + << getArrayFiller(); + return; } } @@ -187,6 +213,15 @@ static void WriteShortAPValueToStream(raw_ostream& Out, case APValue::LValue: Out << "LValue: <todo>"; break; + case APValue::Array: + Out << '{'; + if (unsigned N = V.getArrayInitializedElts()) { + Out << V.getArrayInitializedElt(0); + for (unsigned I = 1; I != N; ++I) + Out << ", " << V.getArrayInitializedElt(I); + } + Out << '}'; + break; } } @@ -244,3 +279,9 @@ void APValue::MakeLValue() { new ((void*)(char*)Data) LV(); Kind = LValue; } + +void APValue::MakeArray(unsigned InitElts, unsigned Size) { + assert(isUninit() && "Bad state change"); + new ((void*)(char*)Data) Arr(InitElts, Size); + Kind = Array; +} diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index a9408f6384c..746b094619c 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -132,6 +132,7 @@ namespace { void adjustIndex(uint64_t N) { if (Invalid) return; if (ArrayElement) { + // FIXME: Make sure the index stays within bounds, or one past the end. Entries.back().ArrayIndex += N; return; } @@ -475,6 +476,7 @@ static bool HandleConversionToBool(const CCValue &Val, bool &Result) { return EvalPointerValueAsBool(PointerResult, Result); } case APValue::Vector: + case APValue::Array: return false; } @@ -569,6 +571,13 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const VarDecl *VD, // expression. If not, we should propagate up a diagnostic. APValue EvalResult; if (!EvaluateConstantExpression(EvalResult, InitInfo, Init)) { + // FIXME: If the evaluation failure was not permanent (for instance, if we + // hit a variable with no declaration yet, or a constexpr function with no + // definition yet), the standard is unclear as to how we should behave. + // + // Either the initializer should be evaluated when the variable is defined, + // or a failed evaluation of the initializer should be reattempted each time + // it is used. VD->setEvaluatedValue(APValue()); return false; } @@ -583,8 +592,48 @@ static bool IsConstNonVolatile(QualType T) { return Quals.hasConst() && !Quals.hasVolatile(); } -bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type, - const LValue &LVal, CCValue &RVal) { +/// Extract the designated sub-object of an rvalue. +static bool ExtractSubobject(EvalInfo &Info, CCValue &Obj, QualType ObjType, + const SubobjectDesignator &Sub, QualType SubType) { + if (Sub.Invalid || Sub.OnePastTheEnd) + return false; + if (Sub.Entries.empty()) { + assert(Info.Ctx.hasSameUnqualifiedType(ObjType, SubType) && + "Unexpected subobject type"); + return true; + } + + assert(!Obj.isLValue() && "extracting subobject of lvalue"); + const APValue *O = &Obj; + for (unsigned I = 0, N = Sub.Entries.size(); I != N; ++I) { + if (O->isUninit()) + return false; + if (ObjType->isArrayType()) { + const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(ObjType); + if (!CAT) + return false; + uint64_t Index = Sub.Entries[I].ArrayIndex; + if (CAT->getSize().ule(Index)) + return false; + if (O->getArrayInitializedElts() > Index) + O = &O->getArrayInitializedElt(Index); + else + O = &O->getArrayFiller(); + ObjType = CAT->getElementType(); + } else { + // FIXME: Support handling of subobjects of structs and unions. Also + // for vector elements, if we want to support those? + } + } + + assert(Info.Ctx.hasSameUnqualifiedType(ObjType, SubType) && + "Unexpected subobject type"); + Obj = CCValue(*O, CCValue::GlobalValue()); + return true; +} + +static bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type, + const LValue &LVal, CCValue &RVal) { const Expr *Base = LVal.Base; CallStackFrame *Frame = LVal.Frame; @@ -620,10 +669,7 @@ bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type, return false; if (isa<ParmVarDecl>(VD) || !VD->getAnyInitializer()->isLValue()) - // If the lvalue refers to a subobject or has been cast to some other - // type, don't use it. - return LVal.Offset.isZero() && - Info.Ctx.hasSameUnqualifiedType(Type, VT); + return ExtractSubobject(Info, RVal, VT, LVal.Designator, Type); // The declaration was initialized by an lvalue, with no lvalue-to-rvalue // conversion. This happens when the declaration and the lvalue should be @@ -654,31 +700,22 @@ bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type, return true; } - // FIXME: Support accessing subobjects of objects of literal types. A simple - // byte offset is insufficient for C++11 semantics: we need to know how the - // reference was formed (which union member was named, for instance). - - // Beyond this point, we don't support accessing subobjects. - if (!LVal.Offset.isZero() || - !Info.Ctx.hasSameUnqualifiedType(Type, Base->getType())) - return false; - - // If this is a temporary expression with a nontrivial initializer, grab the - // value from the relevant stack frame. if (Frame) { + // If this is a temporary expression with a nontrivial initializer, grab the + // value from the relevant stack frame. RVal = Frame->Temporaries[Base]; - return true; - } - - // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the - // initializer until now for such expressions. Such an expression can't be - // an ICE in C, so this only matters for fold. - if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(Base)) { + } else if (const CompoundLiteralExpr *CLE + = dyn_cast<CompoundLiteralExpr>(Base)) { + // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the + // initializer until now for such expressions. Such an expression can't be + // an ICE in C, so this only matters for fold. assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?"); - return Evaluate(RVal, Info, CLE->getInitializer()); - } + if (!Evaluate(RVal, Info, CLE->getInitializer())) + return false; + } else + return false; - return false; + return ExtractSubobject(Info, RVal, Base->getType(), LVal.Designator, Type); } namespace { @@ -1600,6 +1637,55 @@ bool VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) { } //===----------------------------------------------------------------------===// +// Array Evaluation +//===----------------------------------------------------------------------===// + +namespace { + class ArrayExprEvaluator + : public ExprEvaluatorBase<ArrayExprEvaluator, bool> { + APValue &Result; + public: + + ArrayExprEvaluator(EvalInfo &Info, APValue &Result) + : ExprEvaluatorBaseTy(Info), Result(Result) {} + + bool Success(const APValue &V, const Expr *E) { + assert(V.isArray() && "Expected array type"); + Result = V; + return true; + } + bool Error(const Expr *E) { return false; } + + bool VisitInitListExpr(const InitListExpr *E); + }; +} // end anonymous namespace + +static bool EvaluateArray(const Expr* E, APValue& Result, EvalInfo &Info) { + assert(E->isRValue() && E->getType()->isArrayType() && + E->getType()->isLiteralType() && "not a literal array rvalue"); + return ArrayExprEvaluator(Info, Result).Visit(E); +} + +bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { + const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(E->getType()); + if (!CAT) + return false; + + Result = APValue(APValue::UninitArray(), E->getNumInits(), + CAT->getSize().getZExtValue()); + for (InitListExpr::const_iterator I = E->begin(), End = E->end(); + I != End; ++I) + if (!EvaluateConstantExpression(Result.getArrayInitializedElt(I-E->begin()), + Info, cast<Expr>(*I))) + return false; + + if (!Result.hasArrayFiller()) return true; + assert(E->hasArrayFiller() && "no array filler for incomplete init list"); + return EvaluateConstantExpression(Result.getArrayFiller(), Info, + E->getArrayFiller()); +} + +//===----------------------------------------------------------------------===// // Integer Evaluation // // As a GNU extension, we support casting pointers to sufficiently-wide integer @@ -2173,6 +2259,10 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { return Success(E->getOpcode() == BO_NE, E); } + // FIXME: Implement the C++11 restrictions: + // - Pointer subtractions must be on elements of the same array. + // - Pointer comparisons must be between members with the same access. + if (E->getOpcode() == BO_Sub) { QualType Type = E->getLHS()->getType(); QualType ElementType = Type->getAs<PointerType>()->getPointeeType(); @@ -3258,8 +3348,8 @@ static bool Evaluate(CCValue &Result, EvalInfo &Info, const Expr *E) { // FIXME: Implement evaluation of pointer-to-member types. return false; } else if (E->getType()->isArrayType() && E->getType()->isLiteralType()) { - // FIXME: Implement evaluation of array rvalues. - return false; + if (!EvaluateArray(E, Result, Info)) + return false; } else if (E->getType()->isRecordType() && E->getType()->isLiteralType()) { // FIXME: Implement evaluation of record rvalues. return false; @@ -3278,10 +3368,10 @@ static bool EvaluateConstantExpression(APValue &Result, EvalInfo &Info, if (E->isRValue() && E->getType()->isLiteralType()) { // Evaluate arrays and record types in-place, so that later initializers can // refer to earlier-initialized members of the object. - if (E->getType()->isArrayType()) - // FIXME: Implement evaluation of array rvalues. - return false; - else if (E->getType()->isRecordType()) + if (E->getType()->isArrayType()) { + if (!EvaluateArray(E, Result, Info)) + return false; + } else if (E->getType()->isRecordType()) // FIXME: Implement evaluation of record rvalues. return false; } @@ -3312,6 +3402,10 @@ bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const { return false; } + // Don't produce array constants until CodeGen is taught to handle them. + if (Value.isArray()) + return false; + // Check this core constant expression is a constant expression, and if so, // convert it to one. return CheckConstantExpression(Value, Result.Val); diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index 7a1cbdeb1eb..897ea02e584 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -1070,6 +1070,9 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, } return llvm::ConstantVector::get(Inits); } + case APValue::Array: + assert(0 && "shouldn't see array constants here yet"); + break; } } |

