[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/Checkers/UnreachableCodeChecker.cpp test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp test/SemaCXX/constant-expression-cxx11.cpp

Richard Smith richard-llvm at metafoo.co.uk
Wed Nov 9 22:34:14 PST 2011


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.

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, "");
+
+}





More information about the cfe-commits mailing list