[cfe-commits] r144265 - in /cfe/trunk: include/clang/AST/APValue.h include/clang/AST/Expr.h lib/AST/APValue.cpp lib/AST/Decl.cpp lib/AST/Expr.cpp lib/AST/ExprConstant.cpp lib/CodeGen/CGExprConstant.cpp lib/Sema/SemaChecking.cpp lib/StaticAnalyzer
Eli Friedman
eli.friedman at gmail.com
Mon Nov 14 18:32:02 PST 2011
On Wed, Nov 9, 2011 at 10:34 PM, Richard Smith
<richard-llvm at metafoo.co.uk> wrote:
> Author: rsmith
> Date: Thu Nov 10 00:34:14 2011
> New Revision: 144265
>
> URL: http://llvm.org/viewvc/llvm-project?rev=144265&view=rev
> Log:
> Constant expression evaluation: support for evaluation of structs and unions of
> literal types, as well as derived-to-base casts for lvalues and
> derived-to-virtual-base casts.
This appears to be causing a compile-time regression of roughly 10% at
-O0 on 445.gobmk from SPEC. I can try and come up with a testcase if
you don't have access to SPEC.
-Eli
> Modified:
> cfe/trunk/include/clang/AST/APValue.h
> cfe/trunk/include/clang/AST/Expr.h
> cfe/trunk/lib/AST/APValue.cpp
> cfe/trunk/lib/AST/Decl.cpp
> cfe/trunk/lib/AST/Expr.cpp
> cfe/trunk/lib/AST/ExprConstant.cpp
> cfe/trunk/lib/CodeGen/CGExprConstant.cpp
> cfe/trunk/lib/Sema/SemaChecking.cpp
> cfe/trunk/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
> cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
> cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
>
> Modified: cfe/trunk/include/clang/AST/APValue.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/APValue.h?rev=144265&r1=144264&r2=144265&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/APValue.h (original)
> +++ cfe/trunk/include/clang/AST/APValue.h Thu Nov 10 00:34:14 2011
> @@ -17,11 +17,13 @@
> #include "clang/Basic/LLVM.h"
> #include "llvm/ADT/APSInt.h"
> #include "llvm/ADT/APFloat.h"
> +#include "llvm/ADT/PointerIntPair.h"
>
> namespace clang {
> class CharUnits;
> class DiagnosticBuilder;
> class Expr;
> + class FieldDecl;
> class Decl;
>
> /// APValue - This class implements a discriminated union of [uninitialized]
> @@ -39,14 +41,21 @@
> ComplexFloat,
> LValue,
> Vector,
> - Array
> + Array,
> + Struct,
> + Union
> };
> + typedef llvm::PointerIntPair<const Decl *, 1, bool> BaseOrMemberType;
> union LValuePathEntry {
> - const Decl *BaseOrMember;
> + /// BaseOrMember - The FieldDecl or CXXRecordDecl indicating the next item
> + /// in the path. An opaque value of type BaseOrMemberType.
> + void *BaseOrMember;
> + /// ArrayIndex - The array index of the next item in the path.
> uint64_t ArrayIndex;
> };
> struct NoLValuePath {};
> struct UninitArray {};
> + struct UninitStruct {};
> private:
> ValueKind Kind;
>
> @@ -71,6 +80,19 @@
> Arr(unsigned NumElts, unsigned ArrSize);
> ~Arr();
> };
> + struct StructData {
> + APValue *Elts;
> + unsigned NumBases;
> + unsigned NumFields;
> + StructData(unsigned NumBases, unsigned NumFields);
> + ~StructData();
> + };
> + struct UnionData {
> + const FieldDecl *Field;
> + APValue *Value;
> + UnionData();
> + ~UnionData();
> + };
>
> enum {
> MaxSize = (sizeof(ComplexAPSInt) > sizeof(ComplexAPFloat) ?
> @@ -114,6 +136,13 @@
> APValue(UninitArray, unsigned InitElts, unsigned Size) : Kind(Uninitialized) {
> MakeArray(InitElts, Size);
> }
> + APValue(UninitStruct, unsigned B, unsigned M) : Kind(Uninitialized) {
> + MakeStruct(B, M);
> + }
> + explicit APValue(const FieldDecl *D, const APValue &V = APValue())
> + : Kind(Uninitialized) {
> + MakeUnion(); setUnion(D, V);
> + }
>
> ~APValue() {
> MakeUninit();
> @@ -128,6 +157,8 @@
> bool isLValue() const { return Kind == LValue; }
> bool isVector() const { return Kind == Vector; }
> bool isArray() const { return Kind == Array; }
> + bool isStruct() const { return Kind == Struct; }
> + bool isUnion() const { return Kind == Union; }
>
> void print(raw_ostream &OS) const;
> void dump() const;
> @@ -229,6 +260,41 @@
> return ((const Arr*)(const void *)Data)->ArrSize;
> }
>
> + unsigned getStructNumBases() const {
> + assert(isStruct() && "Invalid accessor");
> + return ((StructData*)(char*)Data)->NumBases;
> + }
> + unsigned getStructNumFields() const {
> + assert(isStruct() && "Invalid accessor");
> + return ((StructData*)(char*)Data)->NumFields;
> + }
> + APValue &getStructBase(unsigned i) {
> + assert(isStruct() && "Invalid accessor");
> + return ((StructData*)(char*)Data)->Elts[i];
> + }
> + APValue &getStructField(unsigned i) {
> + assert(isStruct() && "Invalid accessor");
> + return ((StructData*)(char*)Data)->Elts[getStructNumBases() + i];
> + }
> + const APValue &getStructBase(unsigned i) const {
> + return const_cast<APValue*>(this)->getStructBase(i);
> + }
> + const APValue &getStructField(unsigned i) const {
> + return const_cast<APValue*>(this)->getStructField(i);
> + }
> +
> + const FieldDecl *getUnionField() const {
> + assert(isUnion() && "Invalid accessor");
> + return ((UnionData*)(char*)Data)->Field;
> + }
> + APValue &getUnionValue() {
> + assert(isUnion() && "Invalid accessor");
> + return *((UnionData*)(char*)Data)->Value;
> + }
> + const APValue &getUnionValue() const {
> + return const_cast<APValue*>(this)->getUnionValue();
> + }
> +
> void setInt(const APSInt &I) {
> assert(isInt() && "Invalid accessor");
> *(APSInt*)(char*)Data = I;
> @@ -261,6 +327,11 @@
> void setLValue(const Expr *B, const CharUnits &O, NoLValuePath);
> void setLValue(const Expr *B, const CharUnits &O,
> ArrayRef<LValuePathEntry> Path);
> + void setUnion(const FieldDecl *Field, const APValue &Value) {
> + assert(isUnion() && "Invalid accessor");
> + ((UnionData*)(char*)Data)->Field = Field;
> + *((UnionData*)(char*)Data)->Value = Value;
> + }
>
> const APValue &operator=(const APValue &RHS);
>
> @@ -293,6 +364,16 @@
> }
> void MakeLValue();
> void MakeArray(unsigned InitElts, unsigned Size);
> + void MakeStruct(unsigned B, unsigned M) {
> + assert(isUninit() && "Bad state change");
> + new ((void*)(char*)Data) StructData(B, M);
> + Kind = Struct;
> + }
> + void MakeUnion() {
> + assert(isUninit() && "Bad state change");
> + new ((void*)(char*)Data) UnionData();
> + Kind = Union;
> + }
> };
>
> inline raw_ostream &operator<<(raw_ostream &OS, const APValue &V) {
>
> Modified: cfe/trunk/include/clang/AST/Expr.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=144265&r1=144264&r2=144265&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/Expr.h (original)
> +++ cfe/trunk/include/clang/AST/Expr.h Thu Nov 10 00:34:14 2011
> @@ -2049,7 +2049,7 @@
>
> /// isBuiltinCall - If this is a call to a builtin, return the builtin ID. If
> /// not, return 0.
> - unsigned isBuiltinCall(const ASTContext &Context) const;
> + unsigned isBuiltinCall() const;
>
> /// getCallReturnType - Get the return type of the call expr. This is not
> /// always the type of the expr itself, if the return type is a reference
>
> Modified: cfe/trunk/lib/AST/APValue.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/APValue.cpp?rev=144265&r1=144264&r2=144265&view=diff
> ==============================================================================
> --- cfe/trunk/lib/AST/APValue.cpp (original)
> +++ cfe/trunk/lib/AST/APValue.cpp Thu Nov 10 00:34:14 2011
> @@ -45,6 +45,7 @@
> void allocPath() {
> if (hasPathPtr()) PathPtr = new LValuePathEntry[PathLength];
> }
> + void freePath() { if (hasPathPtr()) delete [] PathPtr; }
>
> bool hasPath() const { return PathLength != (unsigned)-1; }
> bool hasPathPtr() const { return hasPath() && PathLength > InlinePathSpace; }
> @@ -62,13 +63,27 @@
> NumElts(NumElts), ArrSize(Size) {}
> APValue::Arr::~Arr() { delete [] Elts; }
>
> +APValue::StructData::StructData(unsigned NumBases, unsigned NumFields) :
> + Elts(new APValue[NumBases+NumFields]),
> + NumBases(NumBases), NumFields(NumFields) {}
> +APValue::StructData::~StructData() {
> + delete [] Elts;
> +}
> +
> +APValue::UnionData::UnionData() : Field(0), Value(new APValue) {}
> +APValue::UnionData::~UnionData () {
> + delete Value;
> +}
> +
> APValue::APValue(const Expr* B) : Kind(Uninitialized) {
> MakeLValue();
> setLValue(B, CharUnits::Zero(), ArrayRef<LValuePathEntry>());
> }
>
> const APValue &APValue::operator=(const APValue &RHS) {
> - if (Kind != RHS.Kind) {
> + if (this == &RHS)
> + return *this;
> + if (Kind != RHS.Kind || Kind == Array || Kind == Struct) {
> MakeUninit();
> if (RHS.isInt())
> MakeInt();
> @@ -84,6 +99,10 @@
> MakeLValue();
> else if (RHS.isArray())
> MakeArray(RHS.getArrayInitializedElts(), RHS.getArraySize());
> + else if (RHS.isStruct())
> + MakeStruct(RHS.getStructNumBases(), RHS.getStructNumFields());
> + else if (RHS.isUnion())
> + MakeUnion();
> }
> if (isInt())
> setInt(RHS.getInt());
> @@ -106,7 +125,13 @@
> getArrayInitializedElt(I) = RHS.getArrayInitializedElt(I);
> if (RHS.hasArrayFiller())
> getArrayFiller() = RHS.getArrayFiller();
> - }
> + } else if (isStruct()) {
> + for (unsigned I = 0, N = RHS.getStructNumBases(); I != N; ++I)
> + getStructBase(I) = RHS.getStructBase(I);
> + for (unsigned I = 0, N = RHS.getStructNumFields(); I != N; ++I)
> + getStructField(I) = RHS.getStructField(I);
> + } else if (isUnion())
> + setUnion(RHS.getUnionField(), RHS.getUnionValue());
> return *this;
> }
>
> @@ -125,6 +150,10 @@
> ((LV*)(char*)Data)->~LV();
> else if (Kind == Array)
> ((Arr*)(char*)Data)->~Arr();
> + else if (Kind == Struct)
> + ((StructData*)(char*)Data)->~StructData();
> + else if (Kind == Union)
> + ((UnionData*)(char*)Data)->~UnionData();
> Kind = Uninitialized;
> }
>
> @@ -143,7 +172,6 @@
>
> void APValue::print(raw_ostream &OS) const {
> switch (getKind()) {
> - default: llvm_unreachable("Unknown APValue kind!");
> case Uninitialized:
> OS << "Uninitialized";
> return;
> @@ -178,22 +206,38 @@
> OS << getArraySize() - getArrayInitializedElts() << " x "
> << getArrayFiller();
> return;
> + case Struct:
> + OS << "Struct ";
> + if (unsigned N = getStructNumBases()) {
> + OS << " bases: " << getStructBase(0);
> + for (unsigned I = 1; I != N; ++I)
> + OS << ", " << getStructBase(I);
> + }
> + if (unsigned N = getStructNumFields()) {
> + OS << " fields: " << getStructField(0);
> + for (unsigned I = 1; I != N; ++I)
> + OS << ", " << getStructField(I);
> + }
> + return;
> + case Union:
> + OS << "Union: " << getUnionValue();
> + return;
> }
> + llvm_unreachable("Unknown APValue kind!");
> }
>
> static void WriteShortAPValueToStream(raw_ostream& Out,
> const APValue& V) {
> switch (V.getKind()) {
> - default: llvm_unreachable("Unknown APValue kind!");
> case APValue::Uninitialized:
> Out << "Uninitialized";
> - break;
> + return;
> case APValue::Int:
> Out << V.getInt();
> - break;
> + return;
> case APValue::Float:
> Out << GetApproxValue(V.getFloat());
> - break;
> + return;
> case APValue::Vector:
> Out << '[';
> WriteShortAPValueToStream(Out, V.getVectorElt(0));
> @@ -202,17 +246,17 @@
> WriteShortAPValueToStream(Out, V.getVectorElt(i));
> }
> Out << ']';
> - break;
> + return;
> case APValue::ComplexInt:
> Out << V.getComplexIntReal() << "+" << V.getComplexIntImag() << "i";
> - break;
> + return;
> case APValue::ComplexFloat:
> Out << GetApproxValue(V.getComplexFloatReal()) << "+"
> << GetApproxValue(V.getComplexFloatImag()) << "i";
> - break;
> + return;
> case APValue::LValue:
> Out << "LValue: <todo>";
> - break;
> + return;
> case APValue::Array:
> Out << '{';
> if (unsigned N = V.getArrayInitializedElts()) {
> @@ -221,8 +265,28 @@
> Out << ", " << V.getArrayInitializedElt(I);
> }
> Out << '}';
> - break;
> + return;
> + case APValue::Struct:
> + Out << '{';
> + if (unsigned N = V.getStructNumBases()) {
> + Out << V.getStructBase(0);
> + for (unsigned I = 1; I != N; ++I)
> + Out << ", " << V.getStructBase(I);
> + if (V.getStructNumFields())
> + Out << ", ";
> + }
> + if (unsigned N = V.getStructNumFields()) {
> + Out << V.getStructField(0);
> + for (unsigned I = 1; I != N; ++I)
> + Out << ", " << V.getStructField(I);
> + }
> + Out << '}';
> + return;
> + case APValue::Union:
> + Out << '{' << V.getUnionValue() << '}';
> + return;
> }
> + llvm_unreachable("Unknown APValue kind!");
> }
>
> const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
> @@ -257,6 +321,7 @@
> void APValue::setLValue(const Expr *B, const CharUnits &O, NoLValuePath) {
> assert(isLValue() && "Invalid accessor");
> LV &LVal = *((LV*)(char*)Data);
> + LVal.freePath();
> LVal.Base = B;
> LVal.Offset = O;
> LVal.PathLength = (unsigned)-1;
> @@ -266,6 +331,7 @@
> ArrayRef<LValuePathEntry> Path) {
> assert(isLValue() && "Invalid accessor");
> LV &LVal = *((LV*)(char*)Data);
> + LVal.freePath();
> LVal.Base = B;
> LVal.Offset = O;
> LVal.PathLength = Path.size();
>
> Modified: cfe/trunk/lib/AST/Decl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=144265&r1=144264&r2=144265&view=diff
> ==============================================================================
> --- cfe/trunk/lib/AST/Decl.cpp (original)
> +++ cfe/trunk/lib/AST/Decl.cpp Thu Nov 10 00:34:14 2011
> @@ -2186,31 +2186,27 @@
> unsigned FieldDecl::getFieldIndex() const {
> if (CachedFieldIndex) return CachedFieldIndex - 1;
>
> - unsigned index = 0;
> + unsigned Index = 0;
> const RecordDecl *RD = getParent();
> const FieldDecl *LastFD = 0;
> bool IsMsStruct = RD->hasAttr<MsStructAttr>();
> -
> - RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
> - while (true) {
> - assert(i != e && "failed to find field in parent!");
> - if (*i == this)
> - break;
> +
> + for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
> + I != E; ++I, ++Index) {
> + (*I)->CachedFieldIndex = Index + 1;
>
> if (IsMsStruct) {
> // Zero-length bitfields following non-bitfield members are ignored.
> - if (getASTContext().ZeroBitfieldFollowsNonBitfield((*i), LastFD)) {
> - ++i;
> + if (getASTContext().ZeroBitfieldFollowsNonBitfield((*I), LastFD)) {
> + --Index;
> continue;
> }
> - LastFD = (*i);
> + LastFD = (*I);
> }
> - ++i;
> - ++index;
> }
>
> - CachedFieldIndex = index + 1;
> - return index;
> + assert(CachedFieldIndex && "failed to find field in parent");
> + return CachedFieldIndex - 1;
> }
>
> SourceRange FieldDecl::getSourceRange() const {
>
> Modified: cfe/trunk/lib/AST/Expr.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=144265&r1=144264&r2=144265&view=diff
> ==============================================================================
> --- cfe/trunk/lib/AST/Expr.cpp (original)
> +++ cfe/trunk/lib/AST/Expr.cpp Thu Nov 10 00:34:14 2011
> @@ -834,7 +834,7 @@
>
> /// isBuiltinCall - If this is a call to a builtin, return the builtin ID. If
> /// not, return 0.
> -unsigned CallExpr::isBuiltinCall(const ASTContext &Context) const {
> +unsigned CallExpr::isBuiltinCall() const {
> // All simple function calls (e.g. func()) are implicitly cast to pointer to
> // function. As a result, we try and obtain the DeclRefExpr from the
> // ImplicitCastExpr.
> @@ -2475,15 +2475,20 @@
> const CXXConstructExpr *CE = cast<CXXConstructExpr>(this);
>
> // Only if it's
> - // 1) an application of the trivial default constructor or
> - if (!CE->getConstructor()->isTrivial()) return false;
> - if (!CE->getNumArgs()) return true;
> -
> - // 2) an elidable trivial copy construction of an operand which is
> - // itself a constant initializer. Note that we consider the
> - // operand on its own, *not* as a reference binding.
> - return CE->isElidable() &&
> - CE->getArg(0)->isConstantInitializer(Ctx, false);
> + if (CE->getConstructor()->isTrivial()) {
> + // 1) an application of the trivial default constructor or
> + if (!CE->getNumArgs()) return true;
> +
> + // 2) an elidable trivial copy construction of an operand which is
> + // itself a constant initializer. Note that we consider the
> + // operand on its own, *not* as a reference binding.
> + if (CE->isElidable() &&
> + CE->getArg(0)->isConstantInitializer(Ctx, false))
> + return true;
> + }
> +
> + // 3) a foldable constexpr constructor.
> + break;
> }
> case CompoundLiteralExprClass: {
> // This handles gcc's extension that allows global initializers like
>
> Modified: cfe/trunk/lib/AST/ExprConstant.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=144265&r1=144264&r2=144265&view=diff
> ==============================================================================
> --- cfe/trunk/lib/AST/ExprConstant.cpp (original)
> +++ cfe/trunk/lib/AST/ExprConstant.cpp Thu Nov 10 00:34:14 2011
> @@ -43,9 +43,32 @@
> /// evaluate the expression regardless of what the RHS is, but C only allows
> /// certain things in certain situations.
> namespace {
> + struct LValue;
> struct CallStackFrame;
> struct EvalInfo;
>
> + /// Get an LValue path entry, which is known to not be an array index, as a
> + /// field declaration.
> + const FieldDecl *getAsField(APValue::LValuePathEntry E) {
> + APValue::BaseOrMemberType Value;
> + Value.setFromOpaqueValue(E.BaseOrMember);
> + return dyn_cast<FieldDecl>(Value.getPointer());
> + }
> + /// Get an LValue path entry, which is known to not be an array index, as a
> + /// base class declaration.
> + const CXXRecordDecl *getAsBaseClass(APValue::LValuePathEntry E) {
> + APValue::BaseOrMemberType Value;
> + Value.setFromOpaqueValue(E.BaseOrMember);
> + return dyn_cast<CXXRecordDecl>(Value.getPointer());
> + }
> + /// Determine whether this LValue path entry for a base class names a virtual
> + /// base class.
> + bool isVirtualBaseClass(APValue::LValuePathEntry E) {
> + APValue::BaseOrMemberType Value;
> + Value.setFromOpaqueValue(E.BaseOrMember);
> + return Value.getInt();
> + }
> +
> /// Determine whether the described subobject is an array element.
> static bool SubobjectIsArrayElement(QualType Base,
> ArrayRef<APValue::LValuePathEntry> Path) {
> @@ -55,7 +78,7 @@
> IsArrayElement = T && T->isArrayType();
> if (IsArrayElement)
> T = T->getBaseElementTypeUnsafe();
> - else if (const FieldDecl *FD = dyn_cast<FieldDecl>(Path[I].BaseOrMember))
> + else if (const FieldDecl *FD = getAsField(Path[I]))
> T = FD->getType().getTypePtr();
> else
> // Path[I] describes a base class.
> @@ -117,14 +140,15 @@
> }
> /// Update this designator to refer to the given base or member of this
> /// object.
> - void addDecl(const Decl *D) {
> + void addDecl(const Decl *D, bool Virtual = false) {
> if (Invalid) return;
> if (OnePastTheEnd) {
> setInvalid();
> return;
> }
> PathEntry Entry;
> - Entry.BaseOrMember = D;
> + APValue::BaseOrMemberType Value(D, Virtual);
> + Entry.BaseOrMember = Value.getOpaqueValue();
> Entries.push_back(Entry);
> ArrayElement = false;
> }
> @@ -192,6 +216,9 @@
> /// Parent - The caller of this stack frame.
> CallStackFrame *Caller;
>
> + /// This - The binding for the this pointer in this call, if any.
> + const LValue *This;
> +
> /// ParmBindings - Parameter bindings for this function call, indexed by
> /// parameters' function scope indices.
> const CCValue *Arguments;
> @@ -201,7 +228,8 @@
> /// Temporaries - Temporary lvalues materialized within this stack frame.
> MapTy Temporaries;
>
> - CallStackFrame(EvalInfo &Info, const CCValue *Arguments);
> + CallStackFrame(EvalInfo &Info, const LValue *This,
> + const CCValue *Arguments);
> ~CallStackFrame();
> };
>
> @@ -229,10 +257,18 @@
> /// initialized last.
> CallStackFrame BottomFrame;
>
> + /// EvaluatingDecl - This is the declaration whose initializer is being
> + /// evaluated, if any.
> + const VarDecl *EvaluatingDecl;
> +
> + /// EvaluatingDeclValue - This is the value being constructed for the
> + /// declaration whose initializer is being evaluated, if any.
> + APValue *EvaluatingDeclValue;
> +
>
> EvalInfo(const ASTContext &C, Expr::EvalStatus &S)
> : Ctx(C), EvalStatus(S), CurrentCall(0), NumCalls(0), CallStackDepth(0),
> - BottomFrame(*this, 0) {}
> + BottomFrame(*this, 0, 0), EvaluatingDecl(0), EvaluatingDeclValue(0) {}
>
> const CCValue *getOpaqueValue(const OpaqueValueExpr *e) const {
> MapTy::const_iterator i = OpaqueValues.find(e);
> @@ -240,11 +276,17 @@
> return &i->second;
> }
>
> + void setEvaluatingDecl(const VarDecl *VD, APValue &Value) {
> + EvaluatingDecl = VD;
> + EvaluatingDeclValue = &Value;
> + }
> +
> const LangOptions &getLangOpts() { return Ctx.getLangOptions(); }
> };
>
> - CallStackFrame::CallStackFrame(EvalInfo &Info, const CCValue *Arguments)
> - : Info(Info), Caller(Info.CurrentCall), Arguments(Arguments) {
> + CallStackFrame::CallStackFrame(EvalInfo &Info, const LValue *This,
> + const CCValue *Arguments)
> + : Info(Info), Caller(Info.CurrentCall), This(This), Arguments(Arguments) {
> Info.CurrentCall = this;
> ++Info.CallStackDepth;
> }
> @@ -330,7 +372,7 @@
>
> static bool Evaluate(CCValue &Result, EvalInfo &Info, const Expr *E);
> static bool EvaluateConstantExpression(APValue &Result, EvalInfo &Info,
> - const Expr *E);
> + const LValue &This, const Expr *E);
> static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info);
> static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info);
> static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info);
> @@ -343,24 +385,52 @@
> // Misc utilities
> //===----------------------------------------------------------------------===//
>
> +/// Should this call expression be treated as a string literal?
> +static bool IsStringLiteralCall(const CallExpr *E) {
> + unsigned Builtin = E->isBuiltinCall();
> + return (Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||
> + Builtin == Builtin::BI__builtin___NSStringMakeConstantString);
> +}
> +
> static bool IsGlobalLValue(const Expr* E) {
> + // C++11 [expr.const]p3 An address constant expression is a prvalue core
> + // constant expression of pointer type that evaluates to...
> +
> + // ... a null pointer value, or a prvalue core constant expression of type
> + // std::nullptr_t.
> if (!E) return true;
>
> - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
> - if (isa<FunctionDecl>(DRE->getDecl()))
> - return true;
> + switch (E->getStmtClass()) {
> + default:
> + return false;
> + case Expr::DeclRefExprClass: {
> + const DeclRefExpr *DRE = cast<DeclRefExpr>(E);
> + // ... the address of an object with static storage duration,
> if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
> return VD->hasGlobalStorage();
> + // ... to the address of a function,
> + if (isa<FunctionDecl>(DRE->getDecl()))
> + return true;
> return false;
> }
> -
> - if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(E))
> - return CLE->isFileScope();
> -
> - if (isa<MemberExpr>(E) || isa<MaterializeTemporaryExpr>(E))
> - return false;
> -
> - return true;
> + case Expr::CompoundLiteralExprClass:
> + return cast<CompoundLiteralExpr>(E)->isFileScope();
> + // A string literal has static storage duration.
> + case Expr::StringLiteralClass:
> + case Expr::PredefinedExprClass:
> + case Expr::ObjCStringLiteralClass:
> + case Expr::ObjCEncodeExprClass:
> + return true;
> + case Expr::CallExprClass:
> + return IsStringLiteralCall(cast<CallExpr>(E));
> + // For GCC compatibility, &&label has static storage duration.
> + case Expr::AddrLabelExprClass:
> + return true;
> + // A Block literal expression may be used as the initialization value for
> + // Block variables at global or local static scope.
> + case Expr::BlockExprClass:
> + return !cast<BlockExpr>(E)->getBlockDecl()->hasCaptures();
> + }
> }
>
> /// Check that this reference or pointer core constant expression is a valid
> @@ -381,6 +451,8 @@
> return true;
> }
>
> + // FIXME: Null references are not constant expressions.
> +
> Value = APValue(LVal.getLValueBase(), LVal.getLValueOffset(),
> Designator.Entries);
> return true;
> @@ -477,6 +549,8 @@
> }
> case APValue::Vector:
> case APValue::Array:
> + case APValue::Struct:
> + case APValue::Union:
> return false;
> }
>
> @@ -534,8 +608,142 @@
> return Result;
> }
>
> +/// If the given LValue refers to a base subobject of some object, find the most
> +/// derived object and the corresponding complete record type. This is necessary
> +/// in order to find the offset of a virtual base class.
> +static bool ExtractMostDerivedObject(EvalInfo &Info, LValue &Result,
> + const CXXRecordDecl *&MostDerivedType) {
> + SubobjectDesignator &D = Result.Designator;
> + if (D.Invalid || !Result.Base)
> + return false;
> +
> + const Type *T = Result.Base->getType().getTypePtr();
> +
> + // Find path prefix which leads to the most-derived subobject.
> + unsigned MostDerivedPathLength = 0;
> + MostDerivedType = T->getAsCXXRecordDecl();
> + bool MostDerivedIsArrayElement = false;
> +
> + for (unsigned I = 0, N = D.Entries.size(); I != N; ++I) {
> + bool IsArray = T && T->isArrayType();
> + if (IsArray)
> + T = T->getBaseElementTypeUnsafe();
> + else if (const FieldDecl *FD = getAsField(D.Entries[I]))
> + T = FD->getType().getTypePtr();
> + else
> + T = 0;
> +
> + if (T) {
> + MostDerivedType = T->getAsCXXRecordDecl();
> + MostDerivedPathLength = I + 1;
> + MostDerivedIsArrayElement = IsArray;
> + }
> + }
> +
> + if (!MostDerivedType)
> + return false;
> +
> + // (B*)&d + 1 has no most-derived object.
> + if (D.OnePastTheEnd && MostDerivedPathLength != D.Entries.size())
> + return false;
> +
> + // Remove the trailing base class path entries and their offsets.
> + const RecordDecl *RD = MostDerivedType;
> + for (unsigned I = MostDerivedPathLength, N = D.Entries.size(); I != N; ++I) {
> + const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
> + const CXXRecordDecl *Base = getAsBaseClass(D.Entries[I]);
> + if (isVirtualBaseClass(D.Entries[I])) {
> + assert(I == MostDerivedPathLength &&
> + "virtual base class must be immediately after most-derived class");
> + Result.Offset -= Layout.getVBaseClassOffset(Base);
> + } else
> + Result.Offset -= Layout.getBaseClassOffset(Base);
> + RD = Base;
> + }
> + D.Entries.resize(MostDerivedPathLength);
> + D.ArrayElement = MostDerivedIsArrayElement;
> + return true;
> +}
> +
> +static void HandleLValueDirectBase(EvalInfo &Info, LValue &Obj,
> + const CXXRecordDecl *Derived,
> + const CXXRecordDecl *Base,
> + const ASTRecordLayout *RL = 0) {
> + if (!RL) RL = &Info.Ctx.getASTRecordLayout(Derived);
> + Obj.getLValueOffset() += RL->getBaseClassOffset(Base);
> + Obj.Designator.addDecl(Base, /*Virtual*/ false);
> +}
> +
> +static bool HandleLValueBase(EvalInfo &Info, LValue &Obj,
> + const CXXRecordDecl *DerivedDecl,
> + const CXXBaseSpecifier *Base) {
> + const CXXRecordDecl *BaseDecl = Base->getType()->getAsCXXRecordDecl();
> +
> + if (!Base->isVirtual()) {
> + HandleLValueDirectBase(Info, Obj, DerivedDecl, BaseDecl);
> + return true;
> + }
> +
> + // Extract most-derived object and corresponding type.
> + if (!ExtractMostDerivedObject(Info, Obj, DerivedDecl))
> + return false;
> +
> + const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(DerivedDecl);
> + Obj.getLValueOffset() += Layout.getVBaseClassOffset(BaseDecl);
> + Obj.Designator.addDecl(BaseDecl, /*Virtual*/ true);
> + return true;
> +}
> +
> +/// Update LVal to refer to the given field, which must be a member of the type
> +/// currently described by LVal.
> +static void HandleLValueMember(EvalInfo &Info, LValue &LVal,
> + const FieldDecl *FD,
> + const ASTRecordLayout *RL = 0) {
> + if (!RL)
> + RL = &Info.Ctx.getASTRecordLayout(FD->getParent());
> +
> + unsigned I = FD->getFieldIndex();
> + LVal.Offset += Info.Ctx.toCharUnitsFromBits(RL->getFieldOffset(I));
> + LVal.Designator.addDecl(FD);
> +}
> +
> +/// Get the size of the given type in char units.
> +static bool HandleSizeof(EvalInfo &Info, QualType Type, CharUnits &Size) {
> + // sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc
> + // extension.
> + if (Type->isVoidType() || Type->isFunctionType()) {
> + Size = CharUnits::One();
> + return true;
> + }
> +
> + if (!Type->isConstantSizeType()) {
> + // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
> + return false;
> + }
> +
> + Size = Info.Ctx.getTypeSizeInChars(Type);
> + return true;
> +}
> +
> +/// Update a pointer value to model pointer arithmetic.
> +/// \param Info - Information about the ongoing evaluation.
> +/// \param LVal - The pointer value to be updated.
> +/// \param EltTy - The pointee type represented by LVal.
> +/// \param Adjustment - The adjustment, in objects of type EltTy, to add.
> +static bool HandleLValueArrayAdjustment(EvalInfo &Info, LValue &LVal,
> + QualType EltTy, int64_t Adjustment) {
> + CharUnits SizeOfPointee;
> + if (!HandleSizeof(Info, EltTy, SizeOfPointee))
> + return false;
> +
> + // Compute the new offset in the appropriate width.
> + LVal.Offset += Adjustment * SizeOfPointee;
> + LVal.Designator.adjustIndex(Adjustment);
> + return true;
> +}
> +
> /// Try to evaluate the initializer for a variable declaration.
> -static bool EvaluateVarDeclInit(EvalInfo &Info, const VarDecl *VD,
> +static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E,const VarDecl *VD,
> CallStackFrame *Frame, CCValue &Result) {
> // If this is a parameter to an active constexpr function call, perform
> // argument substitution.
> @@ -546,6 +754,13 @@
> return true;
> }
>
> + // If we're currently evaluating the initializer of this declaration, use that
> + // in-flight value.
> + if (Info.EvaluatingDecl == VD) {
> + Result = CCValue(*Info.EvaluatingDeclValue, CCValue::GlobalValue());
> + return !Result.isUninit();
> + }
> +
> // Never evaluate the initializer of a weak variable. We can't be sure that
> // this is the definition which will be used.
> if (IsWeakDecl(VD))
> @@ -567,10 +782,13 @@
>
> Expr::EvalStatus EStatus;
> EvalInfo InitInfo(Info.Ctx, EStatus);
> + APValue EvalResult;
> + InitInfo.setEvaluatingDecl(VD, EvalResult);
> + LValue LVal;
> + LVal.setExpr(E);
> // FIXME: The caller will need to know whether the value was a constant
> // expression. If not, we should propagate up a diagnostic.
> - APValue EvalResult;
> - if (!EvaluateConstantExpression(EvalResult, InitInfo, Init)) {
> + if (!EvaluateConstantExpression(EvalResult, InitInfo, LVal, 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.
> @@ -605,10 +823,10 @@
>
> 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) {
> - if (O->isUninit())
> - return false;
> if (ObjType->isArrayType()) {
> + // Next subobject is an array element.
> const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(ObjType);
> if (!CAT)
> return false;
> @@ -620,10 +838,40 @@
> else
> O = &O->getArrayFiller();
> ObjType = CAT->getElementType();
> + } else if (const FieldDecl *Field = getAsField(Sub.Entries[I])) {
> + // Next subobject is a class, struct or union field.
> + RecordDecl *RD = ObjType->castAs<RecordType>()->getDecl();
> + if (RD->isUnion()) {
> + const FieldDecl *UnionField = O->getUnionField();
> + if (!UnionField ||
> + UnionField->getCanonicalDecl() != Field->getCanonicalDecl())
> + return false;
> + O = &O->getUnionValue();
> + } else
> + O = &O->getStructField(Field->getFieldIndex());
> + ObjType = Field->getType();
> } else {
> - // FIXME: Support handling of subobjects of structs and unions. Also
> - // for vector elements, if we want to support those?
> + // Next subobject is a base class.
> + const CXXRecordDecl *RD =
> + cast<CXXRecordDecl>(ObjType->castAs<RecordType>()->getDecl());
> + const CXXRecordDecl *Base =
> + getAsBaseClass(Sub.Entries[I])->getCanonicalDecl();
> + unsigned Index = 0;
> + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
> + E = RD->bases_end(); I != E; ++I, ++Index) {
> + QualType BT = I->getType();
> + if (BT->castAs<RecordType>()->getDecl()->getCanonicalDecl() == Base) {
> + O = &O->getStructBase(Index);
> + ObjType = BT;
> + break;
> + }
> + }
> + if (Index == RD->getNumBases())
> + return false;
> }
> +
> + if (O->isUninit())
> + return false;
> }
>
> assert(Info.Ctx.hasSameUnqualifiedType(ObjType, SubType) &&
> @@ -632,6 +880,14 @@
> return true;
> }
>
> +/// HandleLValueToRValueConversion - Perform an lvalue-to-rvalue conversion on
> +/// the given lvalue. This can also be used for 'lvalue-to-lvalue' conversions
> +/// for looking up the glvalue referred to by an entity of reference type.
> +///
> +/// \param Info - Information about the ongoing evaluation.
> +/// \param Type - The type we expect this conversion to produce.
> +/// \param LVal - The glvalue on which we are attempting to perform this action.
> +/// \param RVal - The produced value will be placed here.
> static bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type,
> const LValue &LVal, CCValue &RVal) {
> const Expr *Base = LVal.Base;
> @@ -665,7 +921,7 @@
> !VD->isConstexpr())
> return false;
> }
> - if (!EvaluateVarDeclInit(Info, VD, Frame, RVal))
> + if (!EvaluateVarDeclInit(Info, LVal.Base, VD, Frame, RVal))
> return false;
>
> if (isa<ParmVarDecl>(VD) || !VD->getAnyInitializer()->isLValue())
> @@ -758,6 +1014,20 @@
> }
> }
>
> +namespace {
> +typedef SmallVector<CCValue, 16> ArgVector;
> +}
> +
> +/// EvaluateArgs - Evaluate the arguments to a function call.
> +static bool EvaluateArgs(ArrayRef<const Expr*> Args, ArgVector &ArgValues,
> + EvalInfo &Info) {
> + for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
> + I != E; ++I)
> + if (!Evaluate(ArgValues[I - Args.begin()], Info, *I))
> + return false;
> + return true;
> +}
> +
> /// Evaluate a function call.
> static bool HandleFunctionCall(ArrayRef<const Expr*> Args, const Stmt *Body,
> EvalInfo &Info, CCValue &Result) {
> @@ -765,17 +1035,87 @@
> if (Info.NumCalls >= 1000000 || Info.CallStackDepth >= 512)
> return false;
>
> - SmallVector<CCValue, 16> ArgValues(Args.size());
> - // FIXME: Deal with default arguments and 'this'.
> - for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
> - I != E; ++I)
> - if (!Evaluate(ArgValues[I - Args.begin()], Info, *I))
> - return false;
> + ArgVector ArgValues(Args.size());
> + if (!EvaluateArgs(Args, ArgValues, Info))
> + return false;
>
> - CallStackFrame Frame(Info, ArgValues.data());
> + // FIXME: Pass in 'this' for member functions.
> + const LValue *This = 0;
> + CallStackFrame Frame(Info, This, ArgValues.data());
> return EvaluateStmt(Result, Info, Body) == ESR_Returned;
> }
>
> +/// Evaluate a constructor call.
> +static bool HandleConstructorCall(ArrayRef<const Expr*> Args,
> + const CXXConstructorDecl *Definition,
> + EvalInfo &Info, const LValue &This,
> + APValue &Result) {
> + if (Info.NumCalls >= 1000000 || Info.CallStackDepth >= 512)
> + return false;
> +
> + ArgVector ArgValues(Args.size());
> + if (!EvaluateArgs(Args, ArgValues, Info))
> + return false;
> +
> + CallStackFrame Frame(Info, &This, ArgValues.data());
> +
> + // If it's a delegating constructor, just delegate.
> + if (Definition->isDelegatingConstructor()) {
> + CXXConstructorDecl::init_const_iterator I = Definition->init_begin();
> + return EvaluateConstantExpression(Result, Info, This, (*I)->getInit());
> + }
> +
> + // Reserve space for the struct members.
> + const CXXRecordDecl *RD = Definition->getParent();
> + if (!RD->isUnion())
> + Result = APValue(APValue::UninitStruct(), RD->getNumBases(),
> + std::distance(RD->field_begin(), RD->field_end()));
> +
> + const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
> +
> + unsigned BasesSeen = 0;
> +#ifndef NDEBUG
> + CXXRecordDecl::base_class_const_iterator BaseIt = RD->bases_begin();
> +#endif
> + for (CXXConstructorDecl::init_const_iterator I = Definition->init_begin(),
> + E = Definition->init_end(); I != E; ++I) {
> + if ((*I)->isBaseInitializer()) {
> + QualType BaseType((*I)->getBaseClass(), 0);
> +#ifndef NDEBUG
> + // Non-virtual base classes are initialized in the order in the class
> + // definition. We cannot have a virtual base class for a literal type.
> + assert(!BaseIt->isVirtual() && "virtual base for literal type");
> + assert(Info.Ctx.hasSameType(BaseIt->getType(), BaseType) &&
> + "base class initializers not in expected order");
> + ++BaseIt;
> +#endif
> + LValue Subobject = This;
> + HandleLValueDirectBase(Info, Subobject, RD,
> + BaseType->getAsCXXRecordDecl(), &Layout);
> + if (!EvaluateConstantExpression(Result.getStructBase(BasesSeen++), Info,
> + Subobject, (*I)->getInit()))
> + return false;
> + } else if (FieldDecl *FD = (*I)->getMember()) {
> + LValue Subobject = This;
> + HandleLValueMember(Info, Subobject, FD, &Layout);
> + if (RD->isUnion()) {
> + Result = APValue(FD);
> + if (!EvaluateConstantExpression(Result.getUnionValue(), Info,
> + Subobject, (*I)->getInit()))
> + return false;
> + } else if (!EvaluateConstantExpression(
> + Result.getStructField(FD->getFieldIndex()),
> + Info, Subobject, (*I)->getInit()))
> + return false;
> + } else {
> + // FIXME: handle indirect field initializers
> + return false;
> + }
> + }
> +
> + return true;
> +}
> +
> namespace {
> class HasSideEffect
> : public ConstStmtVisitor<HasSideEffect, bool> {
> @@ -907,12 +1247,6 @@
>
> RetTy ValueInitialization(const Expr *E) { return DerivedError(E); }
>
> - bool MakeTemporary(const Expr *Key, const Expr *Value, LValue &Result) {
> - if (!Evaluate(Info.CurrentCall->Temporaries[Key], Info, Value))
> - return false;
> - Result.setExpr(Key, Info.CurrentCall);
> - return true;
> - }
> public:
> ExprEvaluatorBase(EvalInfo &Info) : Info(Info) {}
>
> @@ -1029,6 +1363,29 @@
> return DerivedValueInitialization(E);
> }
>
> + /// A member expression where the object is a prvalue is itself a prvalue.
> + RetTy VisitMemberExpr(const MemberExpr *E) {
> + assert(!E->isArrow() && "missing call to bound member function?");
> +
> + CCValue Val;
> + if (!Evaluate(Val, Info, E->getBase()))
> + return false;
> +
> + QualType BaseTy = E->getBase()->getType();
> +
> + const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
> + if (!FD) return false;
> + assert(!FD->getType()->isReferenceType() && "prvalue reference?");
> + assert(BaseTy->getAs<RecordType>()->getDecl()->getCanonicalDecl() ==
> + FD->getParent()->getCanonicalDecl() && "record / field mismatch");
> +
> + SubobjectDesignator Designator;
> + Designator.addDecl(FD);
> +
> + return ExtractSubobject(Info, Val, BaseTy, Designator, E->getType()) &&
> + DerivedSuccess(Val, E);
> + }
> +
> RetTy VisitCastExpr(const CastExpr *E) {
> switch (E->getCastKind()) {
> default:
> @@ -1075,6 +1432,7 @@
> // * CompoundLiteralExpr in C
> // * StringLiteral
> // * PredefinedExpr
> +// * ObjCStringLiteralExpr
> // * ObjCEncodeExpr
> // * AddrLabelExpr
> // * BlockExpr
> @@ -1129,8 +1487,24 @@
> Result.Designator.setInvalid();
> return true;
>
> - // FIXME: Support CK_DerivedToBase and CK_UncheckedDerivedToBase.
> - // Reuse PointerExprEvaluator::VisitCastExpr for these.
> + case CK_DerivedToBase:
> + case CK_UncheckedDerivedToBase: {
> + if (!Visit(E->getSubExpr()))
> + return false;
> +
> + // Now figure out the necessary offset to add to the base LV to get from
> + // the derived class to the base class.
> + QualType Type = E->getSubExpr()->getType();
> +
> + for (CastExpr::path_const_iterator PathI = E->path_begin(),
> + PathE = E->path_end(); PathI != PathE; ++PathI) {
> + if (!HandleLValueBase(Info, Result, Type->getAsCXXRecordDecl(), *PathI))
> + return false;
> + Type = (*PathI)->getType();
> + }
> +
> + return true;
> + }
> }
> }
>
> @@ -1169,7 +1543,7 @@
> }
>
> CCValue V;
> - if (EvaluateVarDeclInit(Info, VD, Info.CurrentCall, V))
> + if (EvaluateVarDeclInit(Info, E, VD, Info.CurrentCall, V))
> return Success(V, E);
>
> return Error(E);
> @@ -1177,7 +1551,9 @@
>
> bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
> const MaterializeTemporaryExpr *E) {
> - return MakeTemporary(E, E->GetTemporaryExpr(), Result);
> + Result.setExpr(E, Info.CurrentCall);
> + return EvaluateConstantExpression(Info.CurrentCall->Temporaries[E], Info,
> + Result, E->GetTemporaryExpr());
> }
>
> bool
> @@ -1203,30 +1579,32 @@
> }
> }
>
> - QualType Ty;
> + // Handle non-static data members.
> + QualType BaseTy;
> if (E->isArrow()) {
> if (!EvaluatePointer(E->getBase(), Result, Info))
> return false;
> - Ty = E->getBase()->getType()->getAs<PointerType>()->getPointeeType();
> + BaseTy = E->getBase()->getType()->getAs<PointerType>()->getPointeeType();
> } else {
> if (!Visit(E->getBase()))
> return false;
> - Ty = E->getBase()->getType();
> + BaseTy = E->getBase()->getType();
> }
>
> - const RecordDecl *RD = Ty->getAs<RecordType>()->getDecl();
> - const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
> -
> const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
> - if (!FD) // FIXME: deal with other kinds of member expressions
> - return false;
> -
> - if (FD->getType()->isReferenceType())
> - return false;
> -
> - unsigned i = FD->getFieldIndex();
> - Result.Offset += Info.Ctx.toCharUnitsFromBits(RL.getFieldOffset(i));
> - Result.Designator.addDecl(FD);
> + if (!FD) return false;
> + assert(BaseTy->getAs<RecordType>()->getDecl()->getCanonicalDecl() ==
> + FD->getParent()->getCanonicalDecl() && "record / field mismatch");
> + (void)BaseTy;
> +
> + HandleLValueMember(Info, Result, FD);
> +
> + if (FD->getType()->isReferenceType()) {
> + CCValue RefValue;
> + if (!HandleLValueToRValueConversion(Info, FD->getType(), Result, RefValue))
> + return false;
> + return Success(RefValue, E);
> + }
> return true;
> }
>
> @@ -1241,14 +1619,11 @@
> APSInt Index;
> if (!EvaluateInteger(E->getIdx(), Index, Info))
> return false;
> - uint64_t IndexValue
> - = Index.isSigned() ? static_cast<uint64_t>(Index.getSExtValue())
> - : Index.getZExtValue();
> -
> - CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(E->getType());
> - Result.Offset += IndexValue * ElementSize;
> - Result.Designator.adjustIndex(IndexValue);
> - return true;
> + int64_t IndexValue
> + = Index.isSigned() ? Index.getSExtValue()
> + : static_cast<int64_t>(Index.getZExtValue());
> +
> + return HandleLValueArrayAdjustment(Info, Result, E->getType(), IndexValue);
> }
>
> bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) {
> @@ -1299,6 +1674,12 @@
> }
> bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E)
> { return ValueInitialization(E); }
> + bool VisitCXXThisExpr(const CXXThisExpr *E) {
> + if (!Info.CurrentCall->This)
> + return false;
> + Result = *Info.CurrentCall->This;
> + return true;
> + }
>
> // FIXME: Missing: @protocol, @selector
> };
> @@ -1331,27 +1712,14 @@
> if (E->getOpcode() == BO_Sub)
> AdditionalOffset = -AdditionalOffset;
>
> - // Compute the new offset in the appropriate width.
> - QualType PointeeType =
> - PExp->getType()->getAs<PointerType>()->getPointeeType();
> - CharUnits SizeOfPointee;
> -
> - // Explicitly handle GNU void* and function pointer arithmetic extensions.
> - if (PointeeType->isVoidType() || PointeeType->isFunctionType())
> - SizeOfPointee = CharUnits::One();
> - else
> - SizeOfPointee = Info.Ctx.getTypeSizeInChars(PointeeType);
> -
> - Result.Offset += AdditionalOffset * SizeOfPointee;
> - Result.Designator.adjustIndex(AdditionalOffset);
> - return true;
> + QualType Pointee = PExp->getType()->getAs<PointerType>()->getPointeeType();
> + return HandleLValueArrayAdjustment(Info, Result, Pointee, AdditionalOffset);
> }
>
> bool PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) {
> return EvaluateLValue(E->getSubExpr(), Result, Info);
> }
>
> -
> bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
> const Expr* SubExpr = E->getSubExpr();
>
> @@ -1373,31 +1741,18 @@
> if (!EvaluatePointer(E->getSubExpr(), Result, Info))
> return false;
>
> - // Now figure out the necessary offset to add to the baseLV to get from
> + // Now figure out the necessary offset to add to the base LV to get from
> // the derived class to the base class.
> - QualType Ty = E->getSubExpr()->getType();
> - const CXXRecordDecl *DerivedDecl =
> - Ty->getAs<PointerType>()->getPointeeType()->getAsCXXRecordDecl();
> + QualType Type =
> + E->getSubExpr()->getType()->castAs<PointerType>()->getPointeeType();
>
> - for (CastExpr::path_const_iterator PathI = E->path_begin(),
> + for (CastExpr::path_const_iterator PathI = E->path_begin(),
> PathE = E->path_end(); PathI != PathE; ++PathI) {
> - const CXXBaseSpecifier *Base = *PathI;
> -
> - // FIXME: If the base is virtual, we'd need to determine the type of the
> - // most derived class and we don't support that right now.
> - if (Base->isVirtual())
> + if (!HandleLValueBase(Info, Result, Type->getAsCXXRecordDecl(), *PathI))
> return false;
> -
> - const CXXRecordDecl *BaseDecl = Base->getType()->getAsCXXRecordDecl();
> - const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(DerivedDecl);
> -
> - Result.getLValueOffset() += Layout.getBaseClassOffset(BaseDecl);
> - DerivedDecl = BaseDecl;
> + Type = (*PathI)->getType();
> }
>
> - // FIXME
> - Result.Designator.setInvalid();
> -
> return true;
> }
>
> @@ -1441,16 +1796,113 @@
> }
>
> bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) {
> - if (E->isBuiltinCall(Info.Ctx) ==
> - Builtin::BI__builtin___CFStringMakeConstantString ||
> - E->isBuiltinCall(Info.Ctx) ==
> - Builtin::BI__builtin___NSStringMakeConstantString)
> + if (IsStringLiteralCall(E))
> return Success(E);
>
> return ExprEvaluatorBaseTy::VisitCallExpr(E);
> }
>
> //===----------------------------------------------------------------------===//
> +// Record Evaluation
> +//===----------------------------------------------------------------------===//
> +
> +namespace {
> + class RecordExprEvaluator
> + : public ExprEvaluatorBase<RecordExprEvaluator, bool> {
> + const LValue &This;
> + APValue &Result;
> + public:
> +
> + RecordExprEvaluator(EvalInfo &info, const LValue &This, APValue &Result)
> + : ExprEvaluatorBaseTy(info), This(This), Result(Result) {}
> +
> + bool Success(const CCValue &V, const Expr *E) {
> + return CheckConstantExpression(V, Result);
> + }
> + bool Error(const Expr *E) { return false; }
> +
> + bool VisitInitListExpr(const InitListExpr *E);
> + bool VisitCXXConstructExpr(const CXXConstructExpr *E);
> + };
> +}
> +
> +bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
> + const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl();
> + const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
> +
> + if (RD->isUnion()) {
> + Result = APValue(E->getInitializedFieldInUnion());
> + if (!E->getNumInits())
> + return true;
> + LValue Subobject = This;
> + HandleLValueMember(Info, Subobject, E->getInitializedFieldInUnion(),
> + &Layout);
> + return EvaluateConstantExpression(Result.getUnionValue(), Info,
> + Subobject, E->getInit(0));
> + }
> +
> + assert((!isa<CXXRecordDecl>(RD) || !cast<CXXRecordDecl>(RD)->getNumBases()) &&
> + "initializer list for class with base classes");
> + Result = APValue(APValue::UninitStruct(), 0,
> + std::distance(RD->field_begin(), RD->field_end()));
> + unsigned ElementNo = 0;
> + for (RecordDecl::field_iterator Field = RD->field_begin(),
> + FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) {
> + // Anonymous bit-fields are not considered members of the class for
> + // purposes of aggregate initialization.
> + if (Field->isUnnamedBitfield())
> + continue;
> +
> + LValue Subobject = This;
> + HandleLValueMember(Info, Subobject, *Field, &Layout);
> +
> + if (ElementNo < E->getNumInits()) {
> + if (!EvaluateConstantExpression(
> + Result.getStructField((*Field)->getFieldIndex()),
> + Info, Subobject, E->getInit(ElementNo++)))
> + return false;
> + } else {
> + // Perform an implicit value-initialization for members beyond the end of
> + // the initializer list.
> + ImplicitValueInitExpr VIE(Field->getType());
> + if (!EvaluateConstantExpression(
> + Result.getStructField((*Field)->getFieldIndex()),
> + Info, Subobject, &VIE))
> + return false;
> + }
> + }
> +
> + return true;
> +}
> +
> +bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
> + const CXXConstructorDecl *FD = E->getConstructor();
> + const FunctionDecl *Definition = 0;
> + FD->getBody(Definition);
> +
> + if (!Definition || !Definition->isConstexpr() || Definition->isInvalidDecl())
> + return false;
> +
> + // FIXME: Elide the copy/move construction wherever we can.
> + if (E->isElidable())
> + if (const MaterializeTemporaryExpr *ME
> + = dyn_cast<MaterializeTemporaryExpr>(E->getArg(0)))
> + return Visit(ME->GetTemporaryExpr());
> +
> + llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
> + return HandleConstructorCall(Args, cast<CXXConstructorDecl>(Definition),
> + Info, This, Result);
> +}
> +
> +static bool EvaluateRecord(const Expr *E, const LValue &This,
> + APValue &Result, EvalInfo &Info) {
> + assert(E->isRValue() && E->getType()->isRecordType() &&
> + E->getType()->isLiteralType() &&
> + "can't evaluate expression as a record rvalue");
> + return RecordExprEvaluator(Info, This, Result).Visit(E);
> +}
> +
> +//===----------------------------------------------------------------------===//
> // Vector Evaluation
> //===----------------------------------------------------------------------===//
>
> @@ -1645,11 +2097,12 @@
> namespace {
> class ArrayExprEvaluator
> : public ExprEvaluatorBase<ArrayExprEvaluator, bool> {
> + const LValue &This;
> APValue &Result;
> public:
>
> - ArrayExprEvaluator(EvalInfo &Info, APValue &Result)
> - : ExprEvaluatorBaseTy(Info), Result(Result) {}
> + ArrayExprEvaluator(EvalInfo &Info, const LValue &This, APValue &Result)
> + : ExprEvaluatorBaseTy(Info), This(This), Result(Result) {}
>
> bool Success(const APValue &V, const Expr *E) {
> assert(V.isArray() && "Expected array type");
> @@ -1658,14 +2111,35 @@
> }
> bool Error(const Expr *E) { return false; }
>
> + bool ValueInitialization(const Expr *E) {
> + const ConstantArrayType *CAT =
> + Info.Ctx.getAsConstantArrayType(E->getType());
> + if (!CAT)
> + return false;
> +
> + Result = APValue(APValue::UninitArray(), 0,
> + CAT->getSize().getZExtValue());
> + if (!Result.hasArrayFiller()) return true;
> +
> + // Value-initialize all elements.
> + LValue Subobject = This;
> + Subobject.Designator.addIndex(0);
> + ImplicitValueInitExpr VIE(CAT->getElementType());
> + return EvaluateConstantExpression(Result.getArrayFiller(), Info,
> + Subobject, &VIE);
> + }
> +
> + // FIXME: We also get CXXConstructExpr, in cases like:
> + // struct S { constexpr S(); }; constexpr S s[10];
> bool VisitInitListExpr(const InitListExpr *E);
> };
> } // end anonymous namespace
>
> -static bool EvaluateArray(const Expr* E, APValue& Result, EvalInfo &Info) {
> +static bool EvaluateArray(const Expr *E, const LValue &This,
> + APValue &Result, EvalInfo &Info) {
> assert(E->isRValue() && E->getType()->isArrayType() &&
> E->getType()->isLiteralType() && "not a literal array rvalue");
> - return ArrayExprEvaluator(Info, Result).Visit(E);
> + return ArrayExprEvaluator(Info, This, Result).Visit(E);
> }
>
> bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
> @@ -1675,16 +2149,26 @@
>
> Result = APValue(APValue::UninitArray(), E->getNumInits(),
> CAT->getSize().getZExtValue());
> + LValue Subobject = This;
> + Subobject.Designator.addIndex(0);
> + unsigned Index = 0;
> for (InitListExpr::const_iterator I = E->begin(), End = E->end();
> - I != End; ++I)
> - if (!EvaluateConstantExpression(Result.getArrayInitializedElt(I-E->begin()),
> - Info, cast<Expr>(*I)))
> + I != End; ++I, ++Index) {
> + if (!EvaluateConstantExpression(Result.getArrayInitializedElt(Index),
> + Info, Subobject, cast<Expr>(*I)))
> + return false;
> + if (!HandleLValueArrayAdjustment(Info, Subobject, CAT->getElementType(), 1))
> return false;
> + }
>
> if (!Result.hasArrayFiller()) return true;
> assert(E->hasArrayFiller() && "no array filler for incomplete init list");
> + // FIXME: The Subobject here isn't necessarily right. This rarely matters,
> + // but sometimes does:
> + // struct S { constexpr S() : p(&p) {} void *p; };
> + // S s[10] = {};
> return EvaluateConstantExpression(Result.getArrayFiller(), Info,
> - E->getArrayFiller());
> + Subobject, E->getArrayFiller());
> }
>
> //===----------------------------------------------------------------------===//
> @@ -1979,7 +2463,7 @@
> }
>
> bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
> - switch (E->isBuiltinCall(Info.Ctx)) {
> + switch (E->isBuiltinCall()) {
> default:
> return ExprEvaluatorBaseTy::VisitCallExpr(E);
>
> @@ -2269,11 +2753,11 @@
> QualType Type = E->getLHS()->getType();
> QualType ElementType = Type->getAs<PointerType>()->getPointeeType();
>
> - CharUnits ElementSize = CharUnits::One();
> - if (!ElementType->isVoidType() && !ElementType->isFunctionType())
> - ElementSize = Info.Ctx.getTypeSizeInChars(ElementType);
> + CharUnits ElementSize;
> + if (!HandleSizeof(Info, ElementType, ElementSize))
> + return false;
>
> - CharUnits Diff = LHSValue.getLValueOffset() -
> + CharUnits Diff = LHSValue.getLValueOffset() -
> RHSValue.getLValueOffset();
> return Success(Diff / ElementSize, E);
> }
> @@ -2453,17 +2937,10 @@
> if (const ReferenceType *Ref = SrcTy->getAs<ReferenceType>())
> SrcTy = Ref->getPointeeType();
>
> - // sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc
> - // extension.
> - if (SrcTy->isVoidType() || SrcTy->isFunctionType())
> - return Success(1, E);
> -
> - // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
> - if (!SrcTy->isConstantSizeType())
> + CharUnits Sizeof;
> + if (!HandleSizeof(Info, SrcTy, Sizeof))
> return false;
> -
> - // Get information about the size.
> - return Success(Info.Ctx.getTypeSizeInChars(SrcTy), E);
> + return Success(Sizeof, E);
> }
> }
>
> @@ -2796,7 +3273,7 @@
> }
>
> bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
> - switch (E->isBuiltinCall(Info.Ctx)) {
> + switch (E->isBuiltinCall()) {
> default:
> return ExprEvaluatorBaseTy::VisitCallExpr(E);
>
> @@ -3350,11 +3827,17 @@
> // FIXME: Implement evaluation of pointer-to-member types.
> return false;
> } else if (E->getType()->isArrayType() && E->getType()->isLiteralType()) {
> - if (!EvaluateArray(E, Result, Info))
> + LValue LV;
> + LV.setExpr(E, Info.CurrentCall);
> + if (!EvaluateArray(E, LV, Info.CurrentCall->Temporaries[E], Info))
> return false;
> + Result = Info.CurrentCall->Temporaries[E];
> } else if (E->getType()->isRecordType() && E->getType()->isLiteralType()) {
> - // FIXME: Implement evaluation of record rvalues.
> - return false;
> + LValue LV;
> + LV.setExpr(E, Info.CurrentCall);
> + if (!EvaluateRecord(E, LV, Info.CurrentCall->Temporaries[E], Info))
> + return false;
> + Result = Info.CurrentCall->Temporaries[E];
> } else
> return false;
>
> @@ -3366,16 +3849,14 @@
> /// since later initializers for an object can indirectly refer to subobjects
> /// which were initialized earlier.
> static bool EvaluateConstantExpression(APValue &Result, EvalInfo &Info,
> - const Expr *E) {
> + const LValue &This, const Expr *E) {
> 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()) {
> - if (!EvaluateArray(E, Result, Info))
> - return false;
> - } else if (E->getType()->isRecordType())
> - // FIXME: Implement evaluation of record rvalues.
> - return false;
> + if (E->getType()->isArrayType())
> + return EvaluateArray(E, This, Result, Info);
> + else if (E->getType()->isRecordType())
> + return EvaluateRecord(E, This, Result, Info);
> }
>
> // For any other type, in-place evaluation is unimportant.
> @@ -3399,6 +3880,7 @@
>
> EvalInfo Info(Ctx, Result);
>
> + // FIXME: If this is the initializer for an lvalue, pass that in.
> CCValue Value;
> if (!::Evaluate(Value, Info, this))
> return false;
> @@ -3410,10 +3892,6 @@
> 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);
> @@ -3628,7 +4106,7 @@
> // constant expressions, but they can never be ICEs because an ICE cannot
> // contain an operand of (pointer to) function type.
> const CallExpr *CE = cast<CallExpr>(E);
> - if (CE->isBuiltinCall(Ctx))
> + if (CE->isBuiltinCall())
> return CheckEvalInICE(E, Ctx);
> return ICEDiag(2, E->getLocStart());
> }
> @@ -3867,7 +4345,7 @@
> // extension. See GCC PR38377 for discussion.
> if (const CallExpr *CallCE
> = dyn_cast<CallExpr>(Exp->getCond()->IgnoreParenCasts()))
> - if (CallCE->isBuiltinCall(Ctx) == Builtin::BI__builtin_constant_p) {
> + if (CallCE->isBuiltinCall() == Builtin::BI__builtin_constant_p) {
> Expr::EvalResult EVResult;
> if (!E->EvaluateAsRValue(EVResult, Ctx) || EVResult.HasSideEffects ||
> !EVResult.Val.isInt()) {
>
> Modified: cfe/trunk/lib/CodeGen/CGExprConstant.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprConstant.cpp?rev=144265&r1=144264&r2=144265&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Thu Nov 10 00:34:14 2011
> @@ -908,7 +908,7 @@
> }
> case Expr::CallExprClass: {
> CallExpr* CE = cast<CallExpr>(E);
> - unsigned builtin = CE->isBuiltinCall(CGM.getContext());
> + unsigned builtin = CE->isBuiltinCall();
> if (builtin !=
> Builtin::BI__builtin___CFStringMakeConstantString &&
> builtin !=
> @@ -1071,7 +1071,8 @@
> return llvm::ConstantVector::get(Inits);
> }
> case APValue::Array:
> - assert(0 && "shouldn't see array constants here yet");
> + case APValue::Struct:
> + case APValue::Union:
> break;
> }
> }
>
> Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=144265&r1=144264&r2=144265&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaChecking.cpp Thu Nov 10 00:34:14 2011
> @@ -2439,7 +2439,7 @@
> else {
> // Look for 'strlcpy(dst, x, strlen(x))'
> if (const CallExpr *SizeCall = dyn_cast<CallExpr>(SizeArg)) {
> - if (SizeCall->isBuiltinCall(Context) == Builtin::BIstrlen
> + if (SizeCall->isBuiltinCall() == Builtin::BIstrlen
> && SizeCall->getNumArgs() == 1)
> CompareWithSrc = ignoreLiteralAdditions(SizeCall->getArg(0), Context);
> }
> @@ -2887,12 +2887,12 @@
> // Check for comparisons with builtin types.
> if (EmitWarning)
> if (CallExpr* CL = dyn_cast<CallExpr>(LeftExprSansParen))
> - if (CL->isBuiltinCall(Context))
> + if (CL->isBuiltinCall())
> EmitWarning = false;
>
> if (EmitWarning)
> if (CallExpr* CR = dyn_cast<CallExpr>(RightExprSansParen))
> - if (CR->isBuiltinCall(Context))
> + if (CR->isBuiltinCall())
> EmitWarning = false;
>
> // Emit the diagnostic.
>
> Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp?rev=144265&r1=144264&r2=144265&view=diff
> ==============================================================================
> --- cfe/trunk/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp (original)
> +++ cfe/trunk/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp Thu Nov 10 00:34:14 2011
> @@ -83,8 +83,6 @@
> if (!C || !PM)
> return;
>
> - ASTContext &Ctx = B.getContext();
> -
> // Find CFGBlocks that were not covered by any node
> for (CFG::const_iterator I = C->begin(), E = C->end(); I != E; ++I) {
> const CFGBlock *CB = *I;
> @@ -117,7 +115,7 @@
> ci != ce; ++ci) {
> if (const CFGStmt *S = (*ci).getAs<CFGStmt>())
> if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) {
> - if (CE->isBuiltinCall(Ctx) == Builtin::BI__builtin_unreachable) {
> + if (CE->isBuiltinCall() == Builtin::BI__builtin_unreachable) {
> foundUnreachable = true;
> break;
> }
>
> Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp?rev=144265&r1=144264&r2=144265&view=diff
> ==============================================================================
> --- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp (original)
> +++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp Thu Nov 10 00:34:14 2011
> @@ -117,8 +117,7 @@
> return x * x;
> }
>
> -// FIXME: The initializer is a constant expression.
> -constexpr pixel large(4); // unexpected-error {{must be initialized by a constant expression}}
> +constexpr pixel large(4);
>
> int next(constexpr int x) { // expected-error {{function parameter cannot be constexpr}}
> return x + 1;
>
> Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=144265&r1=144264&r2=144265&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
> +++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Thu Nov 10 00:34:14 2011
> @@ -33,6 +33,50 @@
> constexpr int zero() { return 0; }
> };
>
> +namespace DerivedToVBaseCast {
> +
> + struct U { int n; };
> + struct V : U { int n; };
> + struct A : virtual V { int n; };
> + struct Aa { int n; };
> + struct B : virtual A, Aa {};
> + struct C : virtual A, Aa {};
> + struct D : B, C {};
> +
> + D d;
> + constexpr B *p = &d;
> + constexpr C *q = &d;
> + static_assert_fold((void*)p != (void*)q, "");
> + static_assert_fold((A*)p == (A*)q, "");
> + static_assert_fold((Aa*)p != (Aa*)q, "");
> +
> + constexpr B &pp = d;
> + constexpr C &qq = d;
> + static_assert_fold((void*)&pp != (void*)&qq, "");
> + static_assert_fold(&(A&)pp == &(A&)qq, "");
> + static_assert_fold(&(Aa&)pp != &(Aa&)qq, "");
> +
> + constexpr V *v = p;
> + constexpr V *w = q;
> + constexpr V *x = (A*)p;
> + static_assert_fold(v == w, "");
> + static_assert_fold(v == x, "");
> +
> + static_assert_fold((U*)&d == p, "");
> + static_assert_fold((U*)&d == q, "");
> + static_assert_fold((U*)&d == v, "");
> + static_assert_fold((U*)&d == w, "");
> + static_assert_fold((U*)&d == x, "");
> +
> + struct X {};
> + struct Y1 : virtual X {};
> + struct Y2 : X {};
> + struct Z : Y1, Y2 {};
> + Z z;
> + static_assert_fold((X*)(Y1*)&z != (X*)(Y2*)&z, "");
> +
> +}
> +
> namespace TemplateArgumentConversion {
> template<int n> struct IntParam {};
>
> @@ -268,6 +312,10 @@
>
> }
>
> +constexpr int strcmp_ce(const char *p, const char *q) {
> + return (!*p || *p != *q) ? *p - *q : strcmp_ce(p+1, q+1);
> +}
> +
> namespace StringLiteral {
>
> // FIXME: Refactor this once we support constexpr templates.
> @@ -309,6 +357,11 @@
> static_assert_fold(*max == 'z', "");
> static_assert_fold(max == str + 38, "");
>
> +static_assert_fold(strcmp_ce("hello world", "hello world") == 0, "");
> +static_assert_fold(strcmp_ce("hello world", "hello clang") > 0, "");
> +static_assert_fold(strcmp_ce("constexpr", "test") < 0, "");
> +static_assert_fold(strcmp_ce("", " ") < 0, "");
> +
> }
>
> namespace Array {
> @@ -350,6 +403,17 @@
> static_assert_fold(zs[0][0][0][2] == 3, ""); // expected-error {{constant expression}}
> static_assert_fold((&zs[0][0][0][2])[-1] == 2, "");
> static_assert_fold(**(**(zs + 1) + 1) == 11, "");
> +static_assert_fold(*(&(&(*(*&(&zs[2] - 1)[0] + 2 - 2))[2])[-1][-1] + 1) == 11, "");
> +
> +constexpr int arr[40] = { 1, 2, 3, [8] = 4 };
> +constexpr int SumNonzero(const int *p) {
> + return *p + (*p ? SumNonzero(p+1) : 0);
> +}
> +constexpr int CountZero(const int *p, const int *q) {
> + return p == q ? 0 : (*p == 0) + CountZero(p+1, q);
> +}
> +static_assert_fold(SumNonzero(arr) == 6, "");
> +static_assert_fold(CountZero(arr, arr + 40) == 36, "");
>
> }
>
> @@ -367,3 +431,180 @@
> };
>
> }
> +
> +namespace Class {
> +
> +struct A { constexpr A(int a, int b) : k(a + b) {} int k; };
> +constexpr int fn(const A &a) { return a.k; }
> +static_assert_fold(fn(A(4,5)) == 9, "");
> +
> +struct B { int n; int m; } constexpr b = { 0, b.n }; // expected-warning {{uninitialized}}
> +struct C {
> + constexpr C(C *this_) : m(42), n(this_->m) {} // ok
> + int m, n;
> +};
> +struct D {
> + C c;
> + constexpr D() : c(&c) {}
> +};
> +static_assert_fold(D().c.n == 42, "");
> +
> +struct E {
> + constexpr E() : p(&p) {}
> + void *p;
> +};
> +constexpr const E &e1 = E(); // expected-error {{constant expression}}
> +// This is a constant expression if we elide the copy constructor call, and
> +// is not a constant expression if we don't! But we do, so it is.
> +// FIXME: The move constructor is not currently implicitly defined as constexpr.
> +// We notice this when evaluating an expression which uses it, but not when
> +// checking its initializer.
> +constexpr E e2 = E(); // unexpected-error {{constant expression}}
> +static_assert_fold(e2.p == &e2.p, ""); // unexpected-error {{constant expression}}
> +// FIXME: We don't pass through the fact that 'this' is ::e3 when checking the
> +// initializer of this declaration.
> +constexpr E e3; // unexpected-error {{constant expression}}
> +static_assert_fold(e3.p == &e3.p, "");
> +
> +extern const class F f;
> +struct F {
> + constexpr F() : p(&f.p) {}
> + const void *p;
> +};
> +constexpr F f = F();
> +
> +struct G {
> + struct T {
> + constexpr T(T *p) : u1(), u2(p) {}
> + union U1 {
> + constexpr U1() {}
> + int a, b = 42;
> + } u1;
> + union U2 {
> + constexpr U2(T *p) : c(p->u1.b) {}
> + int c, d;
> + } u2;
> + } t;
> + constexpr G() : t(&t) {}
> +} constexpr g;
> +
> +static_assert_fold(g.t.u1.a == 42, ""); // expected-error {{constant expression}}
> +static_assert_fold(g.t.u1.b == 42, "");
> +static_assert_fold(g.t.u2.c == 42, "");
> +static_assert_fold(g.t.u2.d == 42, ""); // expected-error {{constant expression}}
> +
> +struct S {
> + int a, b;
> + const S *p;
> + double d;
> + const char *q;
> +
> + constexpr S(int n, const S *p) : a(5), b(n), p(p), d(n), q("hello") {}
> +};
> +
> +S global(43, &global);
> +
> +static_assert_fold(S(15, &global).b == 15, "");
> +
> +constexpr bool CheckS(const S &s) {
> + return s.a == 5 && s.b == 27 && s.p == &global && s.d == 27. && s.q[3] == 'l';
> +}
> +static_assert_fold(CheckS(S(27, &global)), "");
> +
> +struct Arr {
> + char arr[3];
> + constexpr Arr() : arr{'x', 'y', 'z'} {}
> +};
> +constexpr int hash(Arr &&a) {
> + return a.arr[0] + a.arr[1] * 0x100 + a.arr[2] * 0x10000;
> +}
> +constexpr int k = hash(Arr());
> +static_assert_fold(k == 0x007a7978, "");
> +
> +
> +struct AggregateInit {
> + const char &c;
> + int n;
> + double d;
> + int arr[5];
> + void *p;
> +};
> +
> +constexpr AggregateInit agg1 = { "hello"[0] };
> +
> +static_assert_fold(strcmp_ce(&agg1.c, "hello") == 0, "");
> +static_assert_fold(agg1.n == 0, "");
> +static_assert_fold(agg1.d == 0.0, "");
> +static_assert_fold(agg1.arr[-1] == 0, ""); // expected-error {{constant expression}}
> +static_assert_fold(agg1.arr[0] == 0, "");
> +static_assert_fold(agg1.arr[4] == 0, "");
> +static_assert_fold(agg1.arr[5] == 0, ""); // expected-error {{constant expression}}
> +static_assert_fold(agg1.p == nullptr, "");
> +
> +namespace SimpleDerivedClass {
> +
> +struct B {
> + constexpr B(int n) : a(n) {}
> + int a;
> +};
> +struct D : B {
> + constexpr D(int n) : B(n) {}
> +};
> +constexpr D d(3);
> +static_assert_fold(d.a == 3, "");
> +
> +}
> +
> +struct Base {
> + constexpr Base(int a = 42, const char *b = "test") : a(a), b(b) {}
> + int a;
> + const char *b;
> +};
> +struct Base2 {
> + constexpr Base2(const int &r) : r(r) {}
> + int q = 123;
> + // FIXME: When we track the global for which we are computing the initializer,
> + // use a reference here.
> + //const int &r;
> + int r;
> +};
> +struct Derived : Base, Base2 {
> + constexpr Derived() : Base(76), Base2(a) {}
> + int c = r + b[1];
> +};
> +
> +constexpr bool operator==(const Base &a, const Base &b) {
> + return a.a == b.a && strcmp_ce(a.b, b.b) == 0;
> +}
> +
> +constexpr Base base;
> +constexpr Base base2(76);
> +constexpr Derived derived;
> +static_assert_fold(derived.a == 76, "");
> +static_assert_fold(derived.b[2] == 's', "");
> +static_assert_fold(derived.c == 76 + 'e', "");
> +static_assert_fold(derived.q == 123, "");
> +static_assert_fold(derived.r == 76, "");
> +static_assert_fold(&derived.r == &derived.a, ""); // expected-error {{}}
> +
> +static_assert_fold(!(derived == base), "");
> +static_assert_fold(derived == base2, "");
> +
> +}
> +
> +namespace Union {
> +
> +union U {
> + int a;
> + int b;
> +};
> +
> +constexpr U u[4] = { { .a = 0 }, { .b = 1 }, { .a = 2 }, { .b = 3 } };
> +static_assert_fold(u[0].a == 0, "");
> +static_assert_fold(u[0].b, ""); // expected-error {{constant expression}}
> +static_assert_fold(u[1].b == 1, "");
> +static_assert_fold((&u[1].b)[1] == 2, ""); // expected-error {{constant expression}}
> +static_assert_fold(*(&(u[1].b) + 1 + 1) == 3, ""); // expected-error {{constant expression}}
> +static_assert_fold((&(u[1]) + 1 + 1)->b == 3, "");
> +
> +}
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
More information about the cfe-commits
mailing list