[cfe-commits] r147659 - in /cfe/trunk: include/clang/Basic/DiagnosticASTKinds.td lib/AST/ExprConstant.cpp test/CXX/expr/expr.const/p2-0x.cpp test/SemaCXX/constant-expression-cxx11.cpp test/SemaCXX/constexpr-backtrace-limit.cpp

Richard Smith richard-llvm at metafoo.co.uk
Fri Jan 6 08:39:00 PST 2012


Author: rsmith
Date: Fri Jan  6 10:39:00 2012
New Revision: 147659

URL: http://llvm.org/viewvc/llvm-project?rev=147659&view=rev
Log:
C++11 generalized constant expressions: implement checking and diagnostics for
pointer-arithmetic-related undefined behavior and unspecified results. We
continue to fold such values, but now notice they aren't constant expressions.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp
    cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
    cfe/trunk/test/SemaCXX/constexpr-backtrace-limit.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=147659&r1=147658&r2=147659&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Fri Jan  6 10:39:00 2012
@@ -16,6 +16,8 @@
 def note_constexpr_invalid_cast : Note<
   "%select{reinterpret_cast|dynamic_cast|cast which performs the conversions of"
   " a reinterpret_cast|cast from %1}0 is not allowed in a constant expression">;
+def note_constexpr_invalid_downcast : Note<
+  "cannot cast object of dynamic type %0 to type %1">;
 def note_constexpr_overflow : Note<
   "value %0 is outside the range of representable values of type %1">;
 def note_constexpr_invalid_function : Note<
@@ -28,9 +30,20 @@
   "%select{temporary|%4}2 %select{is not a constant expression|"
   "cannot be returned from a constexpr function|"
   "cannot be used to initialize a member in a constant expression}3">;
+def note_constexpr_array_index : Note<"cannot refer to element %0 of "
+  "%select{array of %2 elements|non-array object}1 in a constant expression">;
+def note_constexpr_pointer_arithmetic : Note<
+  "cannot refer to element %0 of non-array object in a constant "
+  "expression">;
 def note_constexpr_past_end : Note<
-  "dereferenced pointer past the end of %select{|subobject of}0 "
+  "dereferenced pointer past the end of %select{|subobject of }0"
   "%select{temporary|%2}1 is not a constant expression">;
+def note_constexpr_past_end_subobject : Note<
+  "cannot access %select{base class|derived class|field|array element}0 of "
+  "pointer past the end of object">;
+def note_constexpr_null_subobject : Note<
+  "cannot %select{access base class of|access derived class of|access field of|"
+  "access array element of|perform pointer arithmetic on}0 null pointer">;
 def note_constexpr_var_init_non_constant : Note<
   "initializer of %0 is not a constant expression">;
 def note_constexpr_typeid_polymorphic : Note<

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=147659&r1=147658&r2=147659&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Fri Jan  6 10:39:00 2012
@@ -76,24 +76,38 @@
     return Value.getInt();
   }
 
-  /// Determine whether the described subobject is an array element.
-  static bool SubobjectIsArrayElement(QualType Base,
-                                      ArrayRef<APValue::LValuePathEntry> Path) {
-    bool IsArrayElement = false;
-    const Type *T = Base.getTypePtr();
+  /// Find the path length and type of the most-derived subobject in the given
+  /// path, and find the size of the containing array, if any.
+  static
+  unsigned findMostDerivedSubobject(ASTContext &Ctx, QualType Base,
+                                    ArrayRef<APValue::LValuePathEntry> Path,
+                                    uint64_t &ArraySize, QualType &Type) {
+    unsigned MostDerivedLength = 0;
+    Type = Base;
     for (unsigned I = 0, N = Path.size(); I != N; ++I) {
-      IsArrayElement = T && T->isArrayType();
-      if (IsArrayElement)
-        T = T->getBaseElementTypeUnsafe();
-      else if (const FieldDecl *FD = getAsField(Path[I]))
-        T = FD->getType().getTypePtr();
-      else
+      if (Type->isArrayType()) {
+        const ConstantArrayType *CAT =
+          cast<ConstantArrayType>(Ctx.getAsArrayType(Type));
+        Type = CAT->getElementType();
+        ArraySize = CAT->getSize().getZExtValue();
+        MostDerivedLength = I + 1;
+      } else if (const FieldDecl *FD = getAsField(Path[I])) {
+        Type = FD->getType();
+        ArraySize = 0;
+        MostDerivedLength = I + 1;
+      } else {
         // Path[I] describes a base class.
-        T = 0;
+        ArraySize = 0;
+      }
     }
-    return IsArrayElement;
+    return MostDerivedLength;
   }
 
+  // The order of this enum is important for diagnostics.
+  enum CheckSubobjectKind {
+    CSK_Base, CSK_Derived, CSK_Field, CSK_ArrayToPointer, CSK_ArrayIndex
+  };
+
   /// A path from a glvalue to a subobject of that glvalue.
   struct SubobjectDesignator {
     /// True if the subobject was named in a manner not supported by C++11. Such
@@ -101,32 +115,43 @@
     /// and we cannot perform lvalue-to-rvalue conversions on them.
     bool Invalid : 1;
 
-    /// Whether this designates an array element.
-    bool ArrayElement : 1;
+    /// Is this a pointer one past the end of an object?
+    bool IsOnePastTheEnd : 1;
+
+    /// The length of the path to the most-derived object of which this is a
+    /// subobject.
+    unsigned MostDerivedPathLength : 30;
+
+    /// The size of the array of which the most-derived object is an element, or
+    /// 0 if the most-derived object is not an array element.
+    uint64_t MostDerivedArraySize;
 
-    /// Whether this designates 'one past the end' of the current subobject.
-    bool OnePastTheEnd : 1;
+    /// The type of the most derived object referred to by this address.
+    QualType MostDerivedType;
 
     typedef APValue::LValuePathEntry PathEntry;
 
     /// The entries on the path from the glvalue to the designated subobject.
     SmallVector<PathEntry, 8> Entries;
 
-    SubobjectDesignator() :
-      Invalid(false), ArrayElement(false), OnePastTheEnd(false) {}
+    SubobjectDesignator() : Invalid(true) {}
 
-    SubobjectDesignator(const APValue &V) :
-      Invalid(!V.isLValue() || !V.hasLValuePath()), ArrayElement(false),
-      OnePastTheEnd(false) {
+    explicit SubobjectDesignator(QualType T)
+      : Invalid(false), IsOnePastTheEnd(false), MostDerivedPathLength(0),
+        MostDerivedArraySize(0), MostDerivedType(T) {}
+
+    SubobjectDesignator(ASTContext &Ctx, const APValue &V)
+      : Invalid(!V.isLValue() || !V.hasLValuePath()), IsOnePastTheEnd(false),
+        MostDerivedPathLength(0), MostDerivedArraySize(0) {
       if (!Invalid) {
+        IsOnePastTheEnd = V.isLValueOnePastTheEnd();
         ArrayRef<PathEntry> VEntries = V.getLValuePath();
         Entries.insert(Entries.end(), VEntries.begin(), VEntries.end());
         if (V.getLValueBase())
-          ArrayElement = SubobjectIsArrayElement(getType(V.getLValueBase()),
-                                                 V.getLValuePath());
-        else
-          assert(V.getLValuePath().empty() &&"Null pointer with nonempty path");
-        OnePastTheEnd = V.isLValueOnePastTheEnd();
+          MostDerivedPathLength =
+              findMostDerivedSubobject(Ctx, getType(V.getLValueBase()),
+                                       V.getLValuePath(), MostDerivedArraySize,
+                                       MostDerivedType);
       }
     }
 
@@ -134,46 +159,76 @@
       Invalid = true;
       Entries.clear();
     }
-    /// Update this designator to refer to the given element within this array.
-    void addIndex(uint64_t N) {
-      if (Invalid) return;
-      if (OnePastTheEnd) {
-        setInvalid();
-        return;
-      }
+
+    /// Determine whether this is a one-past-the-end pointer.
+    bool isOnePastTheEnd() const {
+      if (IsOnePastTheEnd)
+        return true;
+      if (MostDerivedArraySize &&
+          Entries[MostDerivedPathLength - 1].ArrayIndex == MostDerivedArraySize)
+        return true;
+      return false;
+    }
+
+    /// Check that this refers to a valid subobject.
+    bool isValidSubobject() const {
+      if (Invalid)
+        return false;
+      return !isOnePastTheEnd();
+    }
+    /// Check that this refers to a valid subobject, and if not, produce a
+    /// relevant diagnostic and set the designator as invalid.
+    bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK);
+
+    /// Update this designator to refer to the first element within this array.
+    void addArrayUnchecked(const ConstantArrayType *CAT) {
       PathEntry Entry;
-      Entry.ArrayIndex = N;
+      Entry.ArrayIndex = 0;
       Entries.push_back(Entry);
-      ArrayElement = true;
+
+      // This is a most-derived object.
+      MostDerivedType = CAT->getElementType();
+      MostDerivedArraySize = CAT->getSize().getZExtValue();
+      MostDerivedPathLength = Entries.size();
     }
     /// Update this designator to refer to the given base or member of this
     /// object.
-    void addDecl(const Decl *D, bool Virtual = false) {
-      if (Invalid) return;
-      if (OnePastTheEnd) {
-        setInvalid();
-        return;
-      }
+    void addDeclUnchecked(const Decl *D, bool Virtual = false) {
       PathEntry Entry;
       APValue::BaseOrMemberType Value(D, Virtual);
       Entry.BaseOrMember = Value.getOpaqueValue();
       Entries.push_back(Entry);
-      ArrayElement = false;
+
+      // If this isn't a base class, it's a new most-derived object.
+      if (const FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
+        MostDerivedType = FD->getType();
+        MostDerivedArraySize = 0;
+        MostDerivedPathLength = Entries.size();
+      }
     }
+    void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E, uint64_t N);
     /// Add N to the address of this subobject.
-    void adjustIndex(uint64_t N) {
+    void adjustIndex(EvalInfo &Info, const Expr *E, uint64_t N) {
       if (Invalid) return;
-      if (ArrayElement) {
-        // FIXME: Make sure the index stays within bounds, or one past the end.
+      if (MostDerivedPathLength == Entries.size() && MostDerivedArraySize) {
         Entries.back().ArrayIndex += N;
+        if (Entries.back().ArrayIndex > MostDerivedArraySize) {
+          diagnosePointerArithmetic(Info, E, Entries.back().ArrayIndex);
+          setInvalid();
+        }
         return;
       }
-      if (OnePastTheEnd && N == (uint64_t)-1)
-        OnePastTheEnd = false;
-      else if (!OnePastTheEnd && N == 1)
-        OnePastTheEnd = true;
-      else if (N != 0)
+      // [expr.add]p4: For the purposes of these operators, a pointer to a
+      // nonarray object behaves the same as a pointer to the first element of
+      // an array of length one with the type of the object as its element type.
+      if (IsOnePastTheEnd && N == (uint64_t)-1)
+        IsOnePastTheEnd = false;
+      else if (!IsOnePastTheEnd && N == 1)
+        IsOnePastTheEnd = true;
+      else if (N != 0) {
+        diagnosePointerArithmetic(Info, E, uint64_t(IsOnePastTheEnd) + N);
         setInvalid();
+      }
     }
   };
 
@@ -205,8 +260,8 @@
     CCValue(LValueBase B, const CharUnits &O, CallStackFrame *F,
             const SubobjectDesignator &D) :
       APValue(B, O, APValue::NoLValuePath()), CallFrame(F), Designator(D) {}
-    CCValue(const APValue &V, GlobalValue) :
-      APValue(V), CallFrame(0), Designator(V) {}
+    CCValue(ASTContext &Ctx, const APValue &V, GlobalValue) :
+      APValue(V), CallFrame(0), Designator(Ctx, V) {}
     CCValue(const ValueDecl *D, bool IsDerivedMember,
             ArrayRef<const CXXRecordDecl*> Path) :
       APValue(D, IsDerivedMember, Path) {}
@@ -397,6 +452,31 @@
   };
 }
 
+bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E,
+                                         CheckSubobjectKind CSK) {
+  if (Invalid)
+    return false;
+  if (isOnePastTheEnd()) {
+    Info.CCEDiag(E->getExprLoc(), diag::note_constexpr_past_end_subobject)
+      << CSK;
+    setInvalid();
+    return false;
+  }
+  return true;
+}
+
+void SubobjectDesignator::diagnosePointerArithmetic(EvalInfo &Info,
+                                                    const Expr *E, uint64_t N) {
+  if (MostDerivedPathLength == Entries.size() && MostDerivedArraySize)
+    Info.CCEDiag(E->getExprLoc(), diag::note_constexpr_array_index)
+      << static_cast<int>(N) << /*array*/ 0
+      << static_cast<unsigned>(MostDerivedArraySize);
+  else
+    Info.CCEDiag(E->getExprLoc(), diag::note_constexpr_array_index)
+      << static_cast<int>(N) << /*non-array*/ 1;
+  setInvalid();
+}
+
 CallStackFrame::CallStackFrame(EvalInfo &Info, SourceLocation CallLoc,
                                const FunctionDecl *Callee, const LValue *This,
                                const CCValue *Arguments)
@@ -434,7 +514,7 @@
       // Deliberately slice off the frame to form an APValue we can print.
       APValue Value(Arg.getLValueBase(), Arg.getLValueOffset(),
                     Arg.getLValueDesignator().Entries,
-                    Arg.getLValueDesignator().OnePastTheEnd);
+                    Arg.getLValueDesignator().IsOnePastTheEnd);
       Value.printPretty(Out, Frame->Info.Ctx, Param->getType());
     }
 
@@ -544,7 +624,44 @@
       Base = B;
       Offset = CharUnits::Zero();
       Frame = F;
-      Designator = SubobjectDesignator();
+      Designator = SubobjectDesignator(getType(B));
+    }
+
+    // Check that this LValue is not based on a null pointer. If it is, produce
+    // a diagnostic and mark the designator as invalid.
+    bool checkNullPointer(EvalInfo &Info, const Expr *E,
+                          CheckSubobjectKind CSK) {
+      if (Designator.Invalid)
+        return false;
+      if (!Base) {
+        Info.CCEDiag(E->getExprLoc(), diag::note_constexpr_null_subobject)
+          << CSK;
+        Designator.setInvalid();
+        return false;
+      }
+      return true;
+    }
+
+    // Check this LValue refers to an object. If not, set the designator to be
+    // invalid and emit a diagnostic.
+    bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK) {
+      return checkNullPointer(Info, E, CSK) &&
+             Designator.checkSubobject(Info, E, CSK);
+    }
+
+    void addDecl(EvalInfo &Info, const Expr *E,
+                 const Decl *D, bool Virtual = false) {
+      checkSubobject(Info, E, isa<FieldDecl>(D) ? CSK_Field : CSK_Base);
+      Designator.addDeclUnchecked(D, Virtual);
+    }
+    void addArray(EvalInfo &Info, const Expr *E, const ConstantArrayType *CAT) {
+      checkSubobject(Info, E, CSK_ArrayToPointer);
+      Designator.addArrayUnchecked(CAT);
+    }
+    void adjustIndex(EvalInfo &Info, const Expr *E, uint64_t N) {
+      if (!checkNullPointer(Info, E, CSK_ArrayIndex))
+        return;
+      Designator.adjustIndex(Info, E, N);
     }
   };
 
@@ -714,7 +831,8 @@
 }
 
 /// Check that this reference or pointer core constant expression is a valid
-/// value for a constant expression. Type T should be either LValue or CCValue.
+/// value for an address or reference constant expression. Type T should be
+/// either LValue or CCValue.
 template<typename T>
 static bool CheckLValueConstantExpression(EvalInfo &Info, const Expr *E,
                                           const T &LVal, APValue &Value,
@@ -739,20 +857,38 @@
     return false;
   }
 
-  // A constant expression must refer to an object or be a null pointer.
-  if (Designator.Invalid ||
-      (!LVal.getLValueBase() && !Designator.Entries.empty())) {
-    // FIXME: This is not a core constant expression. We should have already
-    // produced a CCE diagnostic.
+  bool IsReferenceType = E->isGLValue();
+
+  if (Designator.Invalid) {
+    // This is not a core constant expression. A diagnostic will have already
+    // been produced.
+    if (IsReferenceType)
+      return false;
+
+    // Allow this for pointers, so we can fold things like integers cast to
+    // pointers.
     Value = APValue(LVal.getLValueBase(), LVal.getLValueOffset(),
                     APValue::NoLValuePath());
     return true;
   }
 
+  Value = APValue(LVal.getLValueBase(), LVal.getLValueOffset(),
+                  Designator.Entries, Designator.IsOnePastTheEnd);
+
+  // Allow address constant expressions to be past-the-end pointers. This is
+  // an extension: the standard requires them to point to an object.
+  if (!IsReferenceType)
+    return true;
+
+  // A reference constant expression must refer to an object.
+  if (!Base) {
+    // FIXME: diagnostic
+    Info.CCEDiag(E->getExprLoc());
+    return false;
+  }
+
   // Does this refer one past the end of some object?
-  // This is technically not an address constant expression nor a reference
-  // constant expression, but we allow it for address constant expressions.
-  if (E->isGLValue() && Base && Designator.OnePastTheEnd) {
+  if (Designator.isOnePastTheEnd()) {
     const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
     Info.Diag(E->getExprLoc(), diag::note_constexpr_past_end, 1)
       << !Designator.Entries.empty() << !!VD << VD;
@@ -764,8 +900,6 @@
     return false;
   }
 
-  Value = APValue(LVal.getLValueBase(), LVal.getLValueOffset(),
-                  Designator.Entries, Designator.OnePastTheEnd);
   return true;
 }
 
@@ -980,49 +1114,22 @@
   return false;
 }
 
-static bool FindMostDerivedObject(EvalInfo &Info, const LValue &LVal,
-                                  const CXXRecordDecl *&MostDerivedType,
-                                  unsigned &MostDerivedPathLength,
-                                  bool &MostDerivedIsArrayElement) {
-  const SubobjectDesignator &D = LVal.Designator;
-  if (D.Invalid || !LVal.Base)
-    return false;
-
-  const Type *T = getType(LVal.Base).getTypePtr();
-
-  // Find path prefix which leads to the most-derived subobject.
-  MostDerivedType = T->getAsCXXRecordDecl();
-  MostDerivedPathLength = 0;
-  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;
-    }
-  }
+/// Cast an lvalue referring to a base subobject to a derived class, by
+/// truncating the lvalue's path to the given length.
+static bool CastToDerivedClass(EvalInfo &Info, const Expr *E, LValue &Result,
+                               const RecordDecl *TruncatedType,
+                               unsigned TruncatedElements) {
+  SubobjectDesignator &D = Result.Designator;
 
-  // (B*)&d + 1 has no most-derived object.
-  if (D.OnePastTheEnd && MostDerivedPathLength != D.Entries.size())
+  // Check we actually point to a derived class object.
+  if (TruncatedElements == D.Entries.size())
+    return true;
+  assert(TruncatedElements >= D.MostDerivedPathLength &&
+         "not casting to a derived class");
+  if (!Result.checkSubobject(Info, E, CSK_Derived))
     return false;
 
-  return MostDerivedType != 0;
-}
-
-static void TruncateLValueBasePath(EvalInfo &Info, LValue &Result,
-                                   const RecordDecl *TruncatedType,
-                                   unsigned TruncatedElements,
-                                   bool IsArrayElement) {
-  SubobjectDesignator &D = Result.Designator;
+  // Truncate the path to the subobject, and remove any derived-to-base offsets.
   const RecordDecl *RD = TruncatedType;
   for (unsigned I = TruncatedElements, N = D.Entries.size(); I != N; ++I) {
     const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
@@ -1034,58 +1141,47 @@
     RD = Base;
   }
   D.Entries.resize(TruncatedElements);
-  D.ArrayElement = IsArrayElement;
-}
-
-/// 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) {
-  unsigned MostDerivedPathLength;
-  bool MostDerivedIsArrayElement;
-  if (!FindMostDerivedObject(Info, Result, MostDerivedType,
-                             MostDerivedPathLength, MostDerivedIsArrayElement))
-    return false;
-
-  // Remove the trailing base class path entries and their offsets.
-  TruncateLValueBasePath(Info, Result, MostDerivedType, MostDerivedPathLength,
-                         MostDerivedIsArrayElement);
   return true;
 }
 
-static void HandleLValueDirectBase(EvalInfo &Info, LValue &Obj,
+static void HandleLValueDirectBase(EvalInfo &Info, const Expr *E, 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);
+  Obj.addDecl(Info, E, Base, /*Virtual*/ false);
 }
 
-static bool HandleLValueBase(EvalInfo &Info, LValue &Obj,
+static bool HandleLValueBase(EvalInfo &Info, const Expr *E, LValue &Obj,
                              const CXXRecordDecl *DerivedDecl,
                              const CXXBaseSpecifier *Base) {
   const CXXRecordDecl *BaseDecl = Base->getType()->getAsCXXRecordDecl();
 
   if (!Base->isVirtual()) {
-    HandleLValueDirectBase(Info, Obj, DerivedDecl, BaseDecl);
+    HandleLValueDirectBase(Info, E, Obj, DerivedDecl, BaseDecl);
     return true;
   }
 
+  SubobjectDesignator &D = Obj.Designator;
+  if (D.Invalid)
+    return false;
+
   // Extract most-derived object and corresponding type.
-  if (!ExtractMostDerivedObject(Info, Obj, DerivedDecl))
+  DerivedDecl = D.MostDerivedType->getAsCXXRecordDecl();
+  if (!CastToDerivedClass(Info, E, Obj, DerivedDecl, D.MostDerivedPathLength))
     return false;
 
+  // Find the virtual base class.
   const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(DerivedDecl);
   Obj.getLValueOffset() += Layout.getVBaseClassOffset(BaseDecl);
-  Obj.Designator.addDecl(BaseDecl, /*Virtual*/ true);
+  Obj.addDecl(Info, E, 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,
+static void HandleLValueMember(EvalInfo &Info, const Expr *E, LValue &LVal,
                                const FieldDecl *FD,
                                const ASTRecordLayout *RL = 0) {
   if (!RL)
@@ -1093,7 +1189,7 @@
 
   unsigned I = FD->getFieldIndex();
   LVal.Offset += Info.Ctx.toCharUnitsFromBits(RL->getFieldOffset(I));
-  LVal.Designator.addDecl(FD);
+  LVal.addDecl(Info, E, FD);
 }
 
 /// Get the size of the given type in char units.
@@ -1107,6 +1203,7 @@
 
   if (!Type->isConstantSizeType()) {
     // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
+    // FIXME: Diagnostic.
     return false;
   }
 
@@ -1116,18 +1213,20 @@
 
 /// Update a pointer value to model pointer arithmetic.
 /// \param Info - Information about the ongoing evaluation.
+/// \param E - The expression being evaluated, for diagnostic purposes.
 /// \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) {
+static bool HandleLValueArrayAdjustment(EvalInfo &Info, const Expr *E,
+                                        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);
+  LVal.adjustIndex(Info, E, Adjustment);
   return true;
 }
 
@@ -1156,7 +1255,8 @@
   // 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());
+    Result = CCValue(Info.Ctx, *Info.EvaluatingDeclValue,
+                     CCValue::GlobalValue());
     return !Result.isUninit();
   }
 
@@ -1183,7 +1283,7 @@
     Info.addNotes(Notes);
   }
 
-  Result = CCValue(*VD->getEvaluatedValue(), CCValue::GlobalValue());
+  Result = CCValue(Info.Ctx, *VD->getEvaluatedValue(), CCValue::GlobalValue());
   return true;
 }
 
@@ -1211,11 +1311,10 @@
 static bool ExtractSubobject(EvalInfo &Info, const Expr *E,
                              CCValue &Obj, QualType ObjType,
                              const SubobjectDesignator &Sub, QualType SubType) {
-  if (Sub.Invalid) {
-    Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
+  if (Sub.Invalid)
+    // A diagnostic will have already been produced.
     return false;
-  }
-  if (Sub.OnePastTheEnd) {
+  if (Sub.isOnePastTheEnd()) {
     Info.Diag(E->getExprLoc(), Info.getLangOpts().CPlusPlus0x ?
                 (unsigned)diag::note_constexpr_read_past_end :
                 (unsigned)diag::note_invalid_subexpr_in_const_expr);
@@ -1288,7 +1387,7 @@
     }
   }
 
-  Obj = CCValue(*O, CCValue::GlobalValue());
+  Obj = CCValue(Info.Ctx, *O, CCValue::GlobalValue());
   return true;
 }
 
@@ -1309,6 +1408,10 @@
   if (!Info.getLangOpts().CPlusPlus)
     Info.CCEDiag(Conv->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
 
+  if (LVal.Designator.Invalid)
+    // A diagnostic will have already been produced.
+    return false;
+
   const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
   CallStackFrame *Frame = LVal.Frame;
   SourceLocation Loc = Conv->getExprLoc();
@@ -1513,16 +1616,9 @@
 
   if (MemPtr.isDerivedMember()) {
     // This is a member of some derived class. Truncate LV appropriately.
-    const CXXRecordDecl *MostDerivedType;
-    unsigned MostDerivedPathLength;
-    bool MostDerivedIsArrayElement;
-    if (!FindMostDerivedObject(Info, LV, MostDerivedType, MostDerivedPathLength,
-                               MostDerivedIsArrayElement))
-      return 0;
-
     // The end of the derived-to-base path for the base object must match the
     // derived-to-base path for the member pointer.
-    if (MostDerivedPathLength + MemPtr.Path.size() >
+    if (LV.Designator.MostDerivedPathLength + MemPtr.Path.size() >
         LV.Designator.Entries.size())
       return 0;
     unsigned PathLengthToMember =
@@ -1536,11 +1632,9 @@
     }
 
     // Truncate the lvalue to the appropriate derived class.
-    bool ResultIsArray = false;
-    if (PathLengthToMember == MostDerivedPathLength)
-      ResultIsArray = MostDerivedIsArrayElement;
-    TruncateLValueBasePath(Info, LV, MemPtr.getContainingRecord(),
-                           PathLengthToMember, ResultIsArray);
+    if (!CastToDerivedClass(Info, BO, LV, MemPtr.getContainingRecord(),
+                            PathLengthToMember))
+      return 0;
   } else if (!MemPtr.Path.empty()) {
     // Extend the LValue path with the member pointer's path.
     LV.Designator.Entries.reserve(LV.Designator.Entries.size() +
@@ -1555,11 +1649,11 @@
     // The first class in the path is that of the lvalue.
     for (unsigned I = 1, N = MemPtr.Path.size(); I != N; ++I) {
       const CXXRecordDecl *Base = MemPtr.Path[N - I - 1];
-      HandleLValueDirectBase(Info, LV, RD, Base);
+      HandleLValueDirectBase(Info, BO, LV, RD, Base);
       RD = Base;
     }
     // Finally cast to the class containing the member.
-    HandleLValueDirectBase(Info, LV, RD, MemPtr.getContainingRecord());
+    HandleLValueDirectBase(Info, BO, LV, RD, MemPtr.getContainingRecord());
   }
 
   // Add the member. Note that we cannot build bound member functions here.
@@ -1567,7 +1661,7 @@
     // FIXME: Deal with IndirectFieldDecls.
     const FieldDecl *FD = dyn_cast<FieldDecl>(MemPtr.getDecl());
     if (!FD) return 0;
-    HandleLValueMember(Info, LV, FD);
+    HandleLValueMember(Info, BO, LV, FD);
   }
 
   return MemPtr.getDecl();
@@ -1577,40 +1671,38 @@
 /// the provided lvalue, which currently refers to the base object.
 static bool HandleBaseToDerivedCast(EvalInfo &Info, const CastExpr *E,
                                     LValue &Result) {
-  const CXXRecordDecl *MostDerivedType;
-  unsigned MostDerivedPathLength;
-  bool MostDerivedIsArrayElement;
-
-  // Check this cast doesn't take us outside the object.
-  if (!FindMostDerivedObject(Info, Result, MostDerivedType,
-                             MostDerivedPathLength,
-                             MostDerivedIsArrayElement))
-    return false;
   SubobjectDesignator &D = Result.Designator;
-  if (MostDerivedPathLength + E->path_size() > D.Entries.size())
+  if (D.Invalid || !Result.checkNullPointer(Info, E, CSK_Derived))
     return false;
 
-  // Check the type of the final cast. We don't need to check the path,
-  // since a cast can only be formed if the path is unique.
-  unsigned NewEntriesSize = D.Entries.size() - E->path_size();
-  bool ResultIsArray = false;
   QualType TargetQT = E->getType();
   if (const PointerType *PT = TargetQT->getAs<PointerType>())
     TargetQT = PT->getPointeeType();
+
+  // Check this cast lands within the final derived-to-base subobject path.
+  if (D.MostDerivedPathLength + E->path_size() > D.Entries.size()) {
+    Info.CCEDiag(E->getExprLoc(), diag::note_constexpr_invalid_downcast)
+      << D.MostDerivedType << TargetQT;
+    return false;
+  }
+
+  // Check the type of the final cast. We don't need to check the path,
+  // since a cast can only be formed if the path is unique.
+  unsigned NewEntriesSize = D.Entries.size() - E->path_size();
   const CXXRecordDecl *TargetType = TargetQT->getAsCXXRecordDecl();
   const CXXRecordDecl *FinalType;
-  if (NewEntriesSize == MostDerivedPathLength) {
-    ResultIsArray = MostDerivedIsArrayElement;
-    FinalType = MostDerivedType;
-  } else
+  if (NewEntriesSize == D.MostDerivedPathLength)
+    FinalType = D.MostDerivedType->getAsCXXRecordDecl();
+  else
     FinalType = getAsBaseClass(D.Entries[NewEntriesSize - 1]);
-  if (FinalType->getCanonicalDecl() != TargetType->getCanonicalDecl())
+  if (FinalType->getCanonicalDecl() != TargetType->getCanonicalDecl()) {
+    Info.CCEDiag(E->getExprLoc(), diag::note_constexpr_invalid_downcast)
+      << D.MostDerivedType << TargetQT;
     return false;
+  }
 
   // Truncate the lvalue to the appropriate derived class.
-  TruncateLValueBasePath(Info, Result, TargetType, NewEntriesSize,
-                         ResultIsArray);
-  return true;
+  return CastToDerivedClass(Info, E, Result, TargetType, NewEntriesSize);
 }
 
 namespace {
@@ -1787,14 +1879,14 @@
       ++BaseIt;
 #endif
       LValue Subobject = This;
-      HandleLValueDirectBase(Info, Subobject, RD,
+      HandleLValueDirectBase(Info, (*I)->getInit(), 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);
+      HandleLValueMember(Info, (*I)->getInit(), Subobject, FD, &Layout);
       if (RD->isUnion()) {
         Result = APValue(FD);
         if (!EvaluateConstantExpression(Result.getUnionValue(), Info, Subobject,
@@ -2083,11 +2175,11 @@
       if (!FD)
         return Error(Callee);
     } else if (CalleeType->isFunctionPointerType()) {
-      CCValue Call;
-      if (!Evaluate(Call, Info, Callee))
+      LValue Call;
+      if (!EvaluatePointer(Callee, Call, Info))
         return false;
 
-      if (!Call.isLValue() || !Call.getLValueOffset().isZero())
+      if (!Call.getLValueOffset().isZero())
         return Error(Callee);
       FD = dyn_cast_or_null<FunctionDecl>(
                              Call.getLValueBase().dyn_cast<const ValueDecl*>());
@@ -2124,7 +2216,7 @@
         !HandleFunctionCall(E, Definition, This, Args, Body, Info, Result))
       return false;
 
-    return DerivedSuccess(CCValue(Result, CCValue::GlobalValue()), E);
+    return DerivedSuccess(CCValue(Info.Ctx, Result, CCValue::GlobalValue()), E);
   }
 
   RetTy VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
@@ -2163,8 +2255,8 @@
     assert(BaseTy->getAs<RecordType>()->getDecl()->getCanonicalDecl() ==
            FD->getParent()->getCanonicalDecl() && "record / field mismatch");
 
-    SubobjectDesignator Designator;
-    Designator.addDecl(FD);
+    SubobjectDesignator Designator(BaseTy);
+    Designator.addDeclUnchecked(FD);
 
     return ExtractSubobject(Info, E, Val, BaseTy, Designator, E->getType()) &&
            DerivedSuccess(Val, E);
@@ -2228,14 +2320,6 @@
     return true;
   }
 
-  bool CheckValidLValue() {
-    // C++11 [basic.lval]p1: An lvalue designates a function or an object. Hence
-    // there are no null references, nor once-past-the-end references.
-    // FIXME: Check for one-past-the-end array indices
-    return Result.Base && !Result.Designator.Invalid &&
-           !Result.Designator.OnePastTheEnd;
-  }
-
   bool VisitMemberExpr(const MemberExpr *E) {
     // Handle non-static data members.
     QualType BaseTy;
@@ -2253,7 +2337,6 @@
         return false;
       BaseTy = E->getBase()->getType();
     }
-    // FIXME: In C++11, require the result to be a valid lvalue.
 
     const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
     // FIXME: Handle IndirectFieldDecls
@@ -2262,7 +2345,7 @@
            FD->getParent()->getCanonicalDecl() && "record / field mismatch");
     (void)BaseTy;
 
-    HandleLValueMember(this->Info, Result, FD);
+    HandleLValueMember(this->Info, E, Result, FD);
 
     if (FD->getType()->isReferenceType()) {
       CCValue RefValue;
@@ -2294,8 +2377,6 @@
     case CK_UncheckedDerivedToBase: {
       if (!this->Visit(E->getSubExpr()))
         return false;
-      if (!CheckValidLValue())
-        return false;
 
       // Now figure out the necessary offset to add to the base LV to get from
       // the derived class to the base class.
@@ -2303,7 +2384,7 @@
 
       for (CastExpr::path_const_iterator PathI = E->path_begin(),
            PathE = E->path_end(); PathI != PathE; ++PathI) {
-        if (!HandleLValueBase(this->Info, Result, Type->getAsCXXRecordDecl(),
+        if (!HandleLValueBase(this->Info, E, Result, Type->getAsCXXRecordDecl(),
                               *PathI))
           return false;
         Type = (*PathI)->getType();
@@ -2378,8 +2459,6 @@
     case CK_BaseToDerived:
       if (!Visit(E->getSubExpr()))
         return false;
-      if (!CheckValidLValue())
-        return false;
       return HandleBaseToDerivedCast(Info, E, Result);
     }
   }
@@ -2502,12 +2581,10 @@
     = Index.isSigned() ? Index.getSExtValue()
                        : static_cast<int64_t>(Index.getZExtValue());
 
-  // FIXME: In C++11, require the result to be a valid lvalue.
-  return HandleLValueArrayAdjustment(Info, Result, E->getType(), IndexValue);
+  return HandleLValueArrayAdjustment(Info, E, Result, E->getType(), IndexValue);
 }
 
 bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) {
-  // FIXME: In C++11, require the result to be a valid lvalue.
   return EvaluatePointer(E->getSubExpr(), Result, Info);
 }
 
@@ -2589,8 +2666,8 @@
     AdditionalOffset = -AdditionalOffset;
 
   QualType Pointee = PExp->getType()->getAs<PointerType>()->getPointeeType();
-  // FIXME: In C++11, require the result to be a valid lvalue.
-  return HandleLValueArrayAdjustment(Info, Result, Pointee, AdditionalOffset);
+  return HandleLValueArrayAdjustment(Info, E, Result, Pointee,
+                                     AdditionalOffset);
 }
 
 bool PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) {
@@ -2637,7 +2714,8 @@
 
     for (CastExpr::path_const_iterator PathI = E->path_begin(),
          PathE = E->path_end(); PathI != PathE; ++PathI) {
-      if (!HandleLValueBase(Info, Result, Type->getAsCXXRecordDecl(), *PathI))
+      if (!HandleLValueBase(Info, E, Result, Type->getAsCXXRecordDecl(),
+                            *PathI))
         return false;
       Type = (*PathI)->getType();
     }
@@ -2687,7 +2765,11 @@
         return false;
     }
     // The result is a pointer to the first element of the array.
-    Result.Designator.addIndex(0);
+    if (const ConstantArrayType *CAT
+          = Info.Ctx.getAsConstantArrayType(SubExpr->getType()))
+      Result.addArray(Info, E, CAT);
+    else
+      Result.Designator.setInvalid();
     return true;
 
   case CK_FunctionToPointerDecay:
@@ -2823,7 +2905,8 @@
 ///    -- if T is a (possibly cv-qualified) non-union class type,
 ///       each non-static data member and each base-class subobject is
 ///       zero-initialized
-static bool HandleClassZeroInitialization(EvalInfo &Info, const RecordDecl *RD,
+static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E,
+                                          const RecordDecl *RD,
                                           const LValue &This, APValue &Result) {
   assert(!RD->isUnion() && "Expected non-union class type");
   const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD);
@@ -2835,24 +2918,24 @@
   if (CD) {
     unsigned Index = 0;
     for (CXXRecordDecl::base_class_const_iterator I = CD->bases_begin(),
-           E = CD->bases_end(); I != E; ++I, ++Index) {
+           End = CD->bases_end(); I != End; ++I, ++Index) {
       const CXXRecordDecl *Base = I->getType()->getAsCXXRecordDecl();
       LValue Subobject = This;
-      HandleLValueDirectBase(Info, Subobject, CD, Base, &Layout);
-      if (!HandleClassZeroInitialization(Info, Base, Subobject,
+      HandleLValueDirectBase(Info, E, Subobject, CD, Base, &Layout);
+      if (!HandleClassZeroInitialization(Info, E, Base, Subobject,
                                          Result.getStructBase(Index)))
         return false;
     }
   }
 
-  for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
-       I != E; ++I) {
+  for (RecordDecl::field_iterator I = RD->field_begin(), End = RD->field_end();
+       I != End; ++I) {
     // -- if T is a reference type, no initialization is performed.
     if ((*I)->getType()->isReferenceType())
       continue;
 
     LValue Subobject = This;
-    HandleLValueMember(Info, Subobject, *I, &Layout);
+    HandleLValueMember(Info, E, Subobject, *I, &Layout);
 
     ImplicitValueInitExpr VIE((*I)->getType());
     if (!EvaluateConstantExpression(
@@ -2875,14 +2958,14 @@
     }
 
     LValue Subobject = This;
-    HandleLValueMember(Info, Subobject, *I);
+    HandleLValueMember(Info, E, Subobject, *I);
     Result = APValue(*I);
     ImplicitValueInitExpr VIE((*I)->getType());
     return EvaluateConstantExpression(Result.getUnionValue(), Info,
                                       Subobject, &VIE);
   }
 
-  return HandleClassZeroInitialization(Info, RD, This, Result);
+  return HandleClassZeroInitialization(Info, E, RD, This, Result);
 }
 
 bool RecordExprEvaluator::VisitCastExpr(const CastExpr *E) {
@@ -2926,8 +3009,8 @@
     if (!E->getNumInits())
       return true;
     LValue Subobject = This;
-    HandleLValueMember(Info, Subobject, E->getInitializedFieldInUnion(),
-                       &Layout);
+    HandleLValueMember(Info, E->getInit(0), Subobject,
+                       E->getInitializedFieldInUnion(), &Layout);
     return EvaluateConstantExpression(Result.getUnionValue(), Info,
                                       Subobject, E->getInit(0));
   }
@@ -2945,9 +3028,10 @@
       continue;
 
     LValue Subobject = This;
-    HandleLValueMember(Info, Subobject, *Field, &Layout);
 
     if (ElementNo < E->getNumInits()) {
+      HandleLValueMember(Info, E->getInit(ElementNo), Subobject, *Field,
+                         &Layout);
       if (!EvaluateConstantExpression(
             Result.getStructField((*Field)->getFieldIndex()),
             Info, Subobject, E->getInit(ElementNo++)))
@@ -2955,6 +3039,7 @@
     } else {
       // Perform an implicit value-initialization for members beyond the end of
       // the initializer list.
+      HandleLValueMember(Info, E, Subobject, *Field, &Layout);
       ImplicitValueInitExpr VIE(Field->getType());
       if (!EvaluateConstantExpression(
             Result.getStructField((*Field)->getFieldIndex()),
@@ -3274,7 +3359,7 @@
 
       // Zero-initialize all elements.
       LValue Subobject = This;
-      Subobject.Designator.addIndex(0);
+      Subobject.addArray(Info, E, CAT);
       ImplicitValueInitExpr VIE(CAT->getElementType());
       return EvaluateConstantExpression(Result.getArrayFiller(), Info,
                                         Subobject, &VIE);
@@ -3307,7 +3392,7 @@
     Result = APValue(APValue::UninitArray(), NumElements, NumElements);
 
     // Copy the string literal into the array. FIXME: Do this better.
-    LV.Designator.addIndex(0);
+    LV.addArray(Info, E, CAT);
     for (uint64_t I = 0; I < NumElements; ++I) {
       CCValue Char;
       if (!HandleLValueToRValueConversion(Info, E->getInit(0),
@@ -3316,7 +3401,8 @@
       if (!CheckConstantExpression(Info, E->getInit(0), Char,
                                    Result.getArrayInitializedElt(I)))
         return false;
-      if (!HandleLValueArrayAdjustment(Info, LV, CAT->getElementType(), 1))
+      if (!HandleLValueArrayAdjustment(Info, E->getInit(0), LV,
+                                       CAT->getElementType(), 1))
         return false;
     }
     return true;
@@ -3325,14 +3411,15 @@
   Result = APValue(APValue::UninitArray(), E->getNumInits(),
                    CAT->getSize().getZExtValue());
   LValue Subobject = This;
-  Subobject.Designator.addIndex(0);
+  Subobject.addArray(Info, E, CAT);
   unsigned Index = 0;
   for (InitListExpr::const_iterator I = E->begin(), End = E->end();
        I != End; ++I, ++Index) {
     if (!EvaluateConstantExpression(Result.getArrayInitializedElt(Index),
                                     Info, Subobject, cast<Expr>(*I)))
       return false;
-    if (!HandleLValueArrayAdjustment(Info, Subobject, CAT->getElementType(), 1))
+    if (!HandleLValueArrayAdjustment(Info, cast<Expr>(*I), Subobject,
+                                     CAT->getElementType(), 1))
       return false;
   }
 
@@ -3361,7 +3448,7 @@
   if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD, ZeroInit)) {
     if (ZeroInit) {
       LValue Subobject = This;
-      Subobject.Designator.addIndex(0);
+      Subobject.addArray(Info, E, CAT);
       ImplicitValueInitExpr VIE(CAT->getElementType());
       return EvaluateConstantExpression(Result.getArrayFiller(), Info,
                                         Subobject, &VIE);
@@ -3388,7 +3475,7 @@
   //   struct S { constexpr S() : p(&p) {} void *p; };
   //   S s[10];
   LValue Subobject = This;
-  Subobject.Designator.addIndex(0);
+  Subobject.addArray(Info, E, CAT);
 
   if (ZeroInit) {
     ImplicitValueInitExpr VIE(CAT->getElementType());
@@ -5284,7 +5371,8 @@
                                       const ASTContext &Ctx) const {
   EvalResult Scratch;
   return EvaluateAsRValue(Scratch, Ctx) &&
-         HandleConversionToBool(CCValue(Scratch.Val, CCValue::GlobalValue()),
+         HandleConversionToBool(CCValue(const_cast<ASTContext&>(Ctx),
+                                        Scratch.Val, CCValue::GlobalValue()),
                                 Result);
 }
 

Modified: cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp?rev=147659&r1=147658&r2=147659&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp Fri Jan  6 10:39:00 2012
@@ -137,6 +137,27 @@
   struct T {
     int n : f(p); // expected-error {{not an integer constant expression}} expected-note {{in call to 'f(&s.m + 1)'}}
   };
+
+  namespace Ptr {
+    struct A {};
+    struct B : A { int n; };
+    B a[3][3];
+    constexpr B *p = a[0] + 4; // expected-error {{constant expression}} expected-note {{element 4 of array of 3 elements}}
+    B b = {};
+    constexpr A *pa = &b + 1; // expected-error {{constant expression}} expected-note {{base class of pointer past the end}}
+    constexpr B *pb = (B*)((A*)&b + 1); // expected-error {{constant expression}} expected-note {{derived class of pointer past the end}}
+    constexpr const int *pn = &(&b + 1)->n; // expected-error {{constant expression}} expected-note {{field of pointer past the end}}
+    constexpr B *parr = &a[3][0]; // expected-error {{constant expression}} expected-note {{array element of pointer past the end}}
+
+    constexpr A *na = nullptr;
+    constexpr B *nb = nullptr;
+    constexpr A &ra = *nb; // expected-error {{constant expression}} expected-note {{cannot access base class of null pointer}}
+    constexpr B &rb = (B&)*na; // expected-error {{constant expression}} expected-note {{cannot access derived class of null pointer}}
+    static_assert((A*)nb == 0, "");
+    static_assert((B*)na == 0, "");
+    constexpr const int &nf = nb->n; // expected-error {{constant expression}} expected-note {{cannot access field of null pointer}}
+    constexpr const int &np = (*(int(*)[4])nullptr)[2]; // expected-error {{constant expression}} expected-note {{cannot access array element of null pointer}}
+  }
 }
 
 // - a lambda-expression (5.1.2);

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=147659&r1=147658&r2=147659&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Fri Jan  6 10:39:00 2012
@@ -363,9 +363,8 @@
 constexpr char c0 = "nought index"[0];
 constexpr char c1 = "nice index"[10];
 constexpr char c2 = "nasty index"[12]; // expected-error {{must be initialized by a constant expression}} expected-warning {{is past the end}} expected-note {{read of dereferenced one-past-the-end pointer}}
-// FIXME: block the pointer arithmetic with undefined behavior here
-constexpr char c3 = "negative index"[-1]; // expected-error {{must be initialized by a constant expression}} expected-warning {{is before the beginning}} expected-note {{read of dereferenced one-past-the-end pointer}}
-constexpr char c4 = ((char*)(int*)"no reinterpret_casts allowed")[14]; // expected-error {{must be initialized by a constant expression}}
+constexpr char c3 = "negative index"[-1]; // expected-error {{must be initialized by a constant expression}} expected-warning {{is before the beginning}} expected-note {{cannot refer to element -1 of array of 15 elements}}
+constexpr char c4 = ((char*)(int*)"no reinterpret_casts allowed")[14]; // expected-error {{must be initialized by a constant expression}} expected-note {{cast which performs the conversions of a reinterpret_cast}}
 
 constexpr const char *p = "test" + 2;
 static_assert(*p == 's', "");
@@ -443,9 +442,9 @@
 constexpr const int *p = xs + 3;
 constexpr int xs4 = p[1]; // ok
 constexpr int xs5 = p[2]; // expected-error {{constant expression}} expected-note {{read of dereferenced one-past-the-end pointer}}
+constexpr int xs6 = p[3]; // expected-error {{constant expression}} expected-note {{cannot refer to element 6}}
 constexpr int xs0 = p[-3]; // ok
-// FIXME: check pointer arithmetic here
-constexpr int xs_1 = p[-4]; // expected-error {{constant expression}} expected-note {{read of dereferenced one-past-the-end pointer}}
+constexpr int xs_1 = p[-4]; // expected-error {{constant expression}} expected-note {{cannot refer to element -1}}
 
 constexpr int zs[2][2][2][2] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
 static_assert(zs[0][0][0][0] == 1, "");
@@ -453,12 +452,14 @@
 static_assert(zs[0][0][0][2] == 3, ""); // expected-error {{constant expression}} expected-note {{read of dereferenced one-past-the-end pointer}}
 static_assert((&zs[0][0][0][2])[-1] == 2, "");
 static_assert(**(**(zs + 1) + 1) == 11, "");
-static_assert(*(&(&(*(*&(&zs[2] - 1)[0] + 2 - 2))[2])[-1][-1] + 1) == 11, "");
+static_assert(*(&(&(*(*&(&zs[2] - 1)[0] + 2 - 2))[2])[-1][-1] + 1) == 11, ""); // expected-error {{constant expression}} expected-note {{cannot refer to element -1 of array of 2 elements in a constant expression}}
+static_assert(*(&(&(*(*&(&zs[2] - 1)[0] + 2 - 2))[2])[-1][2] - 2) == 11, "");
+constexpr int err_zs_1_2_0_0 = zs[1][2][0][0]; // expected-error {{constant expression}} expected-note {{cannot access array element of pointer past the end}}
 
 constexpr int fail(const int &p) {
-  return (&p)[64]; // expected-note {{read of dereferenced one-past-the-end pointer}}
+  return (&p)[64]; // expected-note {{cannot refer to element 64 of array of 2 elements}}
 }
-static_assert(fail(*(&(&(*(*&(&zs[2] - 1)[0] + 2 - 2))[2])[-1][-1] + 1)) == 11, ""); // \
+static_assert(fail(*(&(&(*(*&(&zs[2] - 1)[0] + 2 - 2))[2])[-1][2] - 2)) == 11, ""); // \
 expected-error {{static_assert expression is not an integral constant expression}} \
 expected-note {{in call to 'fail(zs[1][0][1][0])'}}
 
@@ -598,8 +599,7 @@
 static_assert(strcmp_ce(&agg1.c, "hello") == 0, "");
 static_assert(agg1.n == 0, "");
 static_assert(agg1.d == 0.0, "");
-// FIXME: check pointer arithmetic here.
-static_assert(agg1.arr[-1] == 0, ""); // expected-error {{constant expression}} expected-note {{read of dereferenced one-past-the-end}}
+static_assert(agg1.arr[-1] == 0, ""); // expected-error {{constant expression}} expected-note {{cannot refer to element -1}}
 static_assert(agg1.arr[0] == 0, "");
 static_assert(agg1.arr[4] == 0, "");
 static_assert(agg1.arr[5] == 0, ""); // expected-error {{constant expression}} expected-note {{read of dereferenced one-past-the-end}}
@@ -662,13 +662,13 @@
 static_assert(pb1 == &bot1, "");
 static_assert(pb2 == &bot2, "");
 
-constexpr Base2 &fail = (Base2&)bot1; // expected-error {{constant expression}}
-constexpr Base &fail2 = (Base&)*pb2; // expected-error {{constant expression}}
+constexpr Base2 &fail = (Base2&)bot1; // expected-error {{constant expression}} expected-note {{cannot cast object of dynamic type 'const Class::Derived' to type 'Class::Base2'}}
+constexpr Base &fail2 = (Base&)*pb2; // expected-error {{constant expression}} expected-note {{cannot cast object of dynamic type 'const Class::Derived' to type 'Class::Base'}}
 constexpr Base2 &ok2 = (Base2&)bot2;
 static_assert(&ok2 == &derived, "");
 
-constexpr Base2 *pfail = (Base2*)pb1; // expected-error {{constant expression}}
-constexpr Base *pfail2 = (Base*)&bot2; // expected-error {{constant expression}}
+constexpr Base2 *pfail = (Base2*)pb1; // expected-error {{constant expression}} expected-note {{cannot cast object of dynamic type 'const Class::Derived' to type 'Class::Base2'}}
+constexpr Base *pfail2 = (Base*)&bot2; // expected-error {{constant expression}} expected-note {{cannot cast object of dynamic type 'const Class::Derived' to type 'Class::Base'}}
 constexpr Base2 *pok2 = (Base2*)pb2;
 static_assert(pok2 == &derived, "");
 static_assert(&ok2 == pok2, "");
@@ -723,7 +723,7 @@
 static_assert(u[0].b, ""); // expected-error {{constant expression}} expected-note {{read of member 'b' of union with active member 'a'}}
 static_assert(u[1].b == 1, "");
 static_assert((&u[1].b)[1] == 2, ""); // expected-error {{constant expression}} expected-note {{read of dereferenced one-past-the-end pointer}}
-static_assert(*(&(u[1].b) + 1 + 1) == 3, ""); // expected-error {{constant expression}} expected-note {{subexpression}}
+static_assert(*(&(u[1].b) + 1 + 1) == 3, ""); // expected-error {{constant expression}} expected-note {{cannot refer to element 2 of non-array object}}
 static_assert((&(u[1]) + 1 + 1)->b == 3, "");
 
 }
@@ -798,7 +798,7 @@
 
   constexpr T<5> *p17_5 = &t17;
   constexpr T<13> *p17_13 = (T<13>*)p17_5;
-  constexpr T<23> *p17_23 = (T<23>*)p17_13; // expected-error {{constant expression}}
+  constexpr T<23> *p17_23 = (T<23>*)p17_13; // expected-error {{constant expression}} expected-note {{cannot cast object of dynamic type 'T<17>' to type 'T<23>'}}
   static_assert(&(p17_5->*(int(T<3>::*))deepn) == &t17.n, "");
   static_assert(&(p17_13->*deepn) == &t17.n, "");
   constexpr int *pbad2 = &(p17_13->*(int(T<9>::*))deepm); // expected-error {{constant expression}}
@@ -832,15 +832,15 @@
 
   // pb3 does not point to an array element.
   constexpr Base *pb4 = pb3 + 1; // ok, one-past-the-end pointer.
-  constexpr int pb4n = pb4->n; // expected-error {{constant expression}}
-  constexpr Base *err_pb5 = pb3 + 2; // FIXME: reject this.
-  constexpr int err_pb5n = err_pb5->n; // expected-error {{constant expression}}
-  constexpr Base *err_pb2 = pb3 - 1; // FIXME: reject this.
-  constexpr int err_pb2n = err_pb2->n; // expected-error {{constant expression}}
+  constexpr int pb4n = pb4->n; // expected-error {{constant expression}} expected-note {{cannot access field of pointer past the end}}
+  constexpr Base *err_pb5 = pb3 + 2; // expected-error {{constant expression}} expected-note {{cannot refer to element 2}} expected-note {{here}}
+  constexpr int err_pb5n = err_pb5->n; // expected-error {{constant expression}} expected-note {{initializer of 'err_pb5' is not a constant expression}}
+  constexpr Base *err_pb2 = pb3 - 1; // expected-error {{constant expression}} expected-note {{cannot refer to element -1}} expected-note {{here}}
+  constexpr int err_pb2n = err_pb2->n; // expected-error {{constant expression}} expected-note {{initializer of 'err_pb2'}}
   constexpr Base *pb3a = pb4 - 1;
 
   // pb4 does not point to a Derived.
-  constexpr Derived *err_pd4 = (Derived*)pb4; // expected-error {{constant expression}}
+  constexpr Derived *err_pd4 = (Derived*)pb4; // expected-error {{constant expression}} expected-note {{cannot access derived class of pointer past the end}}
   constexpr Derived *pd3a = (Derived*)pb3a;
   constexpr int pd3n = pd3a->n;
 
@@ -850,10 +850,9 @@
   constexpr Derived *pd9 = pd6 + 3;
   constexpr Derived *pd10 = pd6 + 4;
   constexpr int pd9n = pd9->n; // ok
-  constexpr int err_pd10n = pd10->n; // expected-error {{constant expression}} expected-note {{read of dereferenced one-past-the-end pointer}}
+  constexpr int err_pd10n = pd10->n; // expected-error {{constant expression}} expected-note {{cannot access base class of pointer past the end}}
   constexpr int pd0n = pd10[-10].n;
-  // FIXME: check pointer arithmetic here.
-  constexpr int err_pdminus1n = pd10[-11].n; // expected-error {{constant expression}} expected-note {{read of dereferenced one-past-the-end pointer}}
+  constexpr int err_pdminus1n = pd10[-11].n; // expected-error {{constant expression}} expected-note {{cannot refer to element -1 of}}
 
   constexpr Base *pb9 = pd9;
   constexpr const int *(Base::*pfb)() const =

Modified: cfe/trunk/test/SemaCXX/constexpr-backtrace-limit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constexpr-backtrace-limit.cpp?rev=147659&r1=147658&r2=147659&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constexpr-backtrace-limit.cpp (original)
+++ cfe/trunk/test/SemaCXX/constexpr-backtrace-limit.cpp Fri Jan  6 10:39:00 2012
@@ -15,14 +15,14 @@
 
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -fconstexpr-backtrace-limit 2 -fconstexpr-depth 8 -fno-caret-diagnostics 2>&1 | FileCheck %s -check-prefix=TEST3
 // TEST3: constant expression
-// TEST3-NEXT: subexpression
+// TEST3-NEXT: reinterpret_cast
 // TEST3-NEXT: in call to 'recurse(0)'
 // TEST3-NEXT: skipping 4 calls
 // TEST3-NEXT: in call to 'recurse(5)'
 
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -fconstexpr-backtrace-limit 8 -fconstexpr-depth 8 -fno-caret-diagnostics 2>&1 | FileCheck %s -check-prefix=TEST4
 // TEST4: constant expression
-// TEST4-NEXT: subexpression
+// TEST4-NEXT: reinterpret_cast
 // TEST4-NEXT: in call to 'recurse(0)'
 // TEST4-NEXT: in call to 'recurse(1)'
 // TEST4-NEXT: in call to 'recurse(2)'





More information about the cfe-commits mailing list