[cfe-commits] r143909 - in /cfe/trunk: include/clang/AST/APValue.h include/clang/AST/Expr.h lib/AST/APValue.cpp lib/AST/ExprConstant.cpp test/SemaCXX/constant-expression-cxx11.cpp

Richard Smith richard-llvm at metafoo.co.uk
Sun Nov 6 21:07:53 PST 2011


Author: rsmith
Date: Sun Nov  6 23:07:52 2011
New Revision: 143909

URL: http://llvm.org/viewvc/llvm-project?rev=143909&view=rev
Log:
Constant expression evaluation: preserve subobject designator when flattening a
core constant value down to an APValue.

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/ExprConstant.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=143909&r1=143908&r2=143909&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/APValue.h (original)
+++ cfe/trunk/include/clang/AST/APValue.h Sun Nov  6 23:07:52 2011
@@ -22,6 +22,7 @@
   class CharUnits;
   class DiagnosticBuilder;
   class Expr;
+  class Decl;
 
 /// APValue - This class implements a discriminated union of [uninitialized]
 /// [APSInt] [APFloat], [Complex APSInt] [Complex APFloat], [Expr + Offset].
@@ -38,6 +39,11 @@
     LValue,
     Vector
   };
+  union LValuePathEntry {
+    const Decl *BaseOrMember;
+    uint64_t ArrayIndex;
+  };
+  struct NoLValuePath {};
 private:
   ValueKind Kind;
 
@@ -57,6 +63,8 @@
     ~Vec() { delete[] Elts; }
   };
 
+  struct LV;
+
   enum {
     MaxSize = (sizeof(ComplexAPSInt) > sizeof(ComplexAPFloat) ?
                sizeof(ComplexAPSInt) : sizeof(ComplexAPFloat))
@@ -87,10 +95,15 @@
   APValue(const APValue &RHS) : Kind(Uninitialized) {
     *this = RHS;
   }
-  APValue(const Expr* B, const CharUnits &O) : Kind(Uninitialized) {
-    MakeLValue(); setLValue(B, O);
+  APValue(const Expr *B, const CharUnits &O, NoLValuePath N)
+      : Kind(Uninitialized) {
+    MakeLValue(); setLValue(B, O, N);
+  }
+  APValue(const Expr *B, const CharUnits &O, ArrayRef<LValuePathEntry> Path)
+      : Kind(Uninitialized) {
+    MakeLValue(); setLValue(B, O, Path);
   }
-  APValue(const Expr* B);
+  APValue(const Expr *B);
 
   ~APValue() {
     MakeUninit();
@@ -174,6 +187,8 @@
   const CharUnits &getLValueOffset() const {
     return const_cast<APValue*>(this)->getLValueOffset();
   }
+  bool hasLValuePath() const;
+  ArrayRef<LValuePathEntry> getLValuePath() const;
 
   void setInt(const APSInt &I) {
     assert(isInt() && "Invalid accessor");
@@ -204,7 +219,9 @@
     ((ComplexAPFloat*)(char*)Data)->Real = R;
     ((ComplexAPFloat*)(char*)Data)->Imag = I;
   }
-  void setLValue(const Expr *B, const CharUnits &O);
+  void setLValue(const Expr *B, const CharUnits &O, NoLValuePath);
+  void setLValue(const Expr *B, const CharUnits &O,
+                 ArrayRef<LValuePathEntry> Path);
 
   const APValue &operator=(const APValue &RHS);
 

Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=143909&r1=143908&r2=143909&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Sun Nov  6 23:07:52 2011
@@ -500,10 +500,6 @@
   /// lvalue with link time known address, with no side-effects.
   bool EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const;
 
-  /// EvaluateAsLValue - Evaluate an expression to see if we can fold it to an
-  /// lvalue, even if the expression has side-effects.
-  bool EvaluateAsAnyLValue(EvalResult &Result, const ASTContext &Ctx) const;
-
   /// \brief Enumeration used to describe the kind of Null pointer constant
   /// returned from \c isNullPointerConstant().
   enum NullPointerConstantKind {

Modified: cfe/trunk/lib/AST/APValue.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/APValue.cpp?rev=143909&r1=143908&r2=143909&view=diff
==============================================================================
--- cfe/trunk/lib/AST/APValue.cpp (original)
+++ cfe/trunk/lib/AST/APValue.cpp Sun Nov  6 23:07:52 2011
@@ -20,14 +20,41 @@
 using namespace clang;
 
 namespace {
-  struct LV {
-    const Expr* Base;
+  struct LVBase {
+    const Expr *Base;
     CharUnits Offset;
+    unsigned PathLength;
   };
 }
 
+struct APValue::LV : LVBase {
+  static const unsigned InlinePathSpace =
+      (MaxSize - sizeof(LVBase)) / sizeof(LValuePathEntry);
+
+  /// Path - The sequence of base classes, fields and array indices to follow to
+  /// walk from Base to the subobject. When performing GCC-style folding, there
+  /// may not be such a path.
+  union {
+    LValuePathEntry Path[InlinePathSpace];
+    LValuePathEntry *PathPtr;
+  };
+
+  LV() { PathLength = (unsigned)-1; }
+  ~LV() { if (hasPathPtr()) delete [] PathPtr; }
+
+  void allocPath() {
+    if (hasPathPtr()) PathPtr = new LValuePathEntry[PathLength];
+  }
+
+  bool hasPath() const { return PathLength != (unsigned)-1; }
+  bool hasPathPtr() const { return hasPath() && PathLength > InlinePathSpace; }
+
+  LValuePathEntry *getPath() { return hasPathPtr() ? PathPtr : Path; }
+};
+
 APValue::APValue(const Expr* B) : Kind(Uninitialized) {
-  MakeLValue(); setLValue(B, CharUnits::Zero());
+  MakeLValue();
+  setLValue(B, CharUnits::Zero(), ArrayRef<LValuePathEntry>());
 }
 
 const APValue &APValue::operator=(const APValue &RHS) {
@@ -57,8 +84,12 @@
     setComplexInt(RHS.getComplexIntReal(), RHS.getComplexIntImag());
   else if (isComplexFloat())
     setComplexFloat(RHS.getComplexFloatReal(), RHS.getComplexFloatImag());
-  else if (isLValue())
-    setLValue(RHS.getLValueBase(), RHS.getLValueOffset());
+  else if (isLValue()) {
+    if (RHS.hasLValuePath())
+      setLValue(RHS.getLValueBase(), RHS.getLValueOffset(),RHS.getLValuePath());
+    else
+      setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), NoLValuePath());
+  }
   return *this;
 }
 
@@ -174,14 +205,38 @@
   return ((LV*)(void*)Data)->Offset;
 }
 
-void APValue::setLValue(const Expr *B, const CharUnits &O) {
+bool APValue::hasLValuePath() const {
+  assert(isLValue() && "Invalid accessor");
+  return ((LV*)(char*)Data)->hasPath();
+}
+
+ArrayRef<APValue::LValuePathEntry> APValue::getLValuePath() const {
+  assert(isLValue() && hasLValuePath() && "Invalid accessor");
+  LV &LVal = *((LV*)(char*)Data);
+  return ArrayRef<LValuePathEntry>(LVal.getPath(), LVal.PathLength);
+}
+
+void APValue::setLValue(const Expr *B, const CharUnits &O, NoLValuePath) {
+  assert(isLValue() && "Invalid accessor");
+  LV &LVal = *((LV*)(char*)Data);
+  LVal.Base = B;
+  LVal.Offset = O;
+  LVal.PathLength = (unsigned)-1;
+}
+
+void APValue::setLValue(const Expr *B, const CharUnits &O,
+                        ArrayRef<LValuePathEntry> Path) {
   assert(isLValue() && "Invalid accessor");
-  ((LV*)(char*)Data)->Base = B;
-  ((LV*)(char*)Data)->Offset = O;
+  LV &LVal = *((LV*)(char*)Data);
+  LVal.Base = B;
+  LVal.Offset = O;
+  LVal.PathLength = Path.size();
+  memcpy(LVal.getPath(), Path.data(), Path.size() * sizeof(LValuePathEntry));
 }
 
 void APValue::MakeLValue() {
   assert(isUninit() && "Bad state change");
+  assert(sizeof(LV) <= MaxSize && "LV too big");
   new ((void*)(char*)Data) LV();
   Kind = LValue;
 }

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=143909&r1=143908&r2=143909&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Sun Nov  6 23:07:52 2011
@@ -46,6 +46,24 @@
   struct CallStackFrame;
   struct EvalInfo;
 
+  /// 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();
+    for (unsigned I = 0, N = Path.size(); I != N; ++I) {
+      IsArrayElement = T && T->isArrayType();
+      if (IsArrayElement)
+        T = T->getBaseElementTypeUnsafe();
+      else if (const FieldDecl *FD = dyn_cast<FieldDecl>(Path[I].BaseOrMember))
+        T = FD->getType().getTypePtr();
+      else
+        // Path[I] describes a base class.
+        T = 0;
+    }
+    return IsArrayElement;
+  }
+
   /// 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
@@ -59,20 +77,28 @@
     /// Whether this designates 'one past the end' of the current subobject.
     bool OnePastTheEnd : 1;
 
-    union PathEntry {
-      /// If the current subobject is of class type, this indicates which
-      /// subobject of that type is accessed next.
-      const Decl *BaseOrMember;
-      /// If the current subobject is of array type, this indicates which index
-      /// within that array is accessed next.
-      uint64_t Index;
-    };
+    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(const APValue &V) :
+      Invalid(!V.isLValue() || !V.hasLValuePath()), ArrayElement(false),
+      OnePastTheEnd(false) {
+      if (!Invalid) {
+        ArrayRef<PathEntry> VEntries = V.getLValuePath();
+        Entries.insert(Entries.end(), VEntries.begin(), VEntries.end());
+        if (V.getLValueBase())
+          ArrayElement = SubobjectIsArrayElement(V.getLValueBase()->getType(),
+                                                 V.getLValuePath());
+        else
+          assert(V.getLValuePath().empty() &&"Null pointer with nonempty path");
+      }
+    }
+
     void setInvalid() {
       Invalid = true;
       Entries.clear();
@@ -85,7 +111,7 @@
         return;
       }
       PathEntry Entry;
-      Entry.Index = N;
+      Entry.ArrayIndex = N;
       Entries.push_back(Entry);
       ArrayElement = true;
     }
@@ -106,7 +132,7 @@
     void adjustIndex(uint64_t N) {
       if (Invalid) return;
       if (ArrayElement) {
-        Entries.back().Index += N;
+        Entries.back().ArrayIndex += N;
         return;
       }
       if (OnePastTheEnd && N == (uint64_t)-1)
@@ -141,9 +167,9 @@
     CCValue(const CCValue &V) : APValue(V), CallFrame(V.CallFrame) {}
     CCValue(const Expr *B, const CharUnits &O, CallStackFrame *F,
             const SubobjectDesignator &D) :
-      APValue(B, O), CallFrame(F), Designator(D) {}
+      APValue(B, O, APValue::NoLValuePath()), CallFrame(F), Designator(D) {}
     CCValue(const APValue &V, GlobalValue) :
-      APValue(V), CallFrame(0), Designator() {}
+      APValue(V), CallFrame(0), Designator(V) {}
 
     CallStackFrame *getLValueFrame() const {
       assert(getKind() == LValue);
@@ -336,15 +362,37 @@
   return true;
 }
 
+/// 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.
+template<typename T>
+static bool CheckLValueConstantExpression(const T &LVal, APValue &Value) {
+  if (!IsGlobalLValue(LVal.getLValueBase()))
+    return false;
+
+  const SubobjectDesignator &Designator = LVal.getLValueDesignator();
+  // A constant expression must refer to an object or be a null pointer.
+  if (Designator.Invalid || Designator.OnePastTheEnd ||
+      (!LVal.getLValueBase() && !Designator.Entries.empty())) {
+    // FIXME: Check for out-of-bounds array indices.
+    // FIXME: This is not a constant expression.
+    Value = APValue(LVal.getLValueBase(), LVal.getLValueOffset(),
+                    APValue::NoLValuePath());
+    return true;
+  }
+
+  Value = APValue(LVal.getLValueBase(), LVal.getLValueOffset(),
+                  Designator.Entries);
+  return true;
+}
+
 /// Check that this core constant expression value is a valid value for a
 /// constant expression, and if it is, produce the corresponding constant value.
 static bool CheckConstantExpression(const CCValue &CCValue, APValue &Value) {
-  if (CCValue.isLValue() && !IsGlobalLValue(CCValue.getLValueBase()))
-    return false;
-
-  // Slice off the extra bits.
-  Value = CCValue;
-  return true;
+  if (!CCValue.isLValue()) {
+    Value = CCValue;
+    return true;
+  }
+  return CheckLValueConstantExpression(CCValue, Value);
 }
 
 const ValueDecl *GetLValueBaseDecl(const LValue &LVal) {
@@ -595,7 +643,7 @@
       return false;
 
     assert(Type->isIntegerType() && "string element not integer type");
-    uint64_t Index = Designator.Entries[0].Index;
+    uint64_t Index = Designator.Entries[0].ArrayIndex;
     if (Index > S->getLength())
       return false;
     APSInt Value(S->getCharByteWidth() * Info.Ctx.getCharWidth(),
@@ -1954,7 +2002,7 @@
     if (!ADecl)
       return false;
     const Decl *BDecl = GetLValueBaseDecl(B);
-    if (ADecl != BDecl)
+    if (!BDecl || ADecl->getCanonicalDecl() != BDecl->getCanonicalDecl())
       return false;
   }
 
@@ -3293,24 +3341,8 @@
   EvalInfo Info(Ctx, Result);
 
   LValue LV;
-  if (EvaluateLValue(this, LV, Info) && !Result.HasSideEffects &&
-      IsGlobalLValue(LV.Base)) {
-    Result.Val = APValue(LV.Base, LV.Offset);
-    return true;
-  }
-  return false;
-}
-
-bool Expr::EvaluateAsAnyLValue(EvalResult &Result,
-                               const ASTContext &Ctx) const {
-  EvalInfo Info(Ctx, Result);
-
-  LValue LV;
-  if (EvaluateLValue(this, LV, Info)) {
-    Result.Val = APValue(LV.Base, LV.Offset);
-    return true;
-  }
-  return false;
+  return EvaluateLValue(this, LV, Info) && !Result.HasSideEffects &&
+         CheckLValueConstantExpression(LV, Result.Val);
 }
 
 /// isEvaluatable - Call EvaluateAsRValue to see if this expression can be

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=143909&r1=143908&r2=143909&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Sun Nov  6 23:07:52 2011
@@ -261,4 +261,22 @@
 constexpr char c3 = "negative index"[-1]; // expected-error {{must be initialized by a constant expression}} expected-warning {{indexes before the beginning}}
 constexpr char c4 = ((char*)(int*)"no reinterpret_casts allowed")[14]; // expected-error {{must be initialized by a constant expression}}
 
+constexpr const char *p = "test" + 2;
+static_assert_fold(*p == 's', "");
+
+constexpr const char *max_iter(const char *a, const char *b) {
+  return *a < *b ? b : a;
+}
+constexpr const char *max_element(const char *a, const char *b) {
+  return (a+1 >= b) ? a : max_iter(a, max_element(a+1, b));
+}
+
+constexpr const char *begin(const char (&arr)[45]) { return arr; }
+constexpr const char *end(const char (&arr)[45]) { return arr + 45; }
+
+constexpr char str[] = "the quick brown fox jumped over the lazy dog";
+constexpr const char *max = max_element(begin(str), end(str));
+static_assert_fold(*max == 'z', "");
+static_assert_fold(max == str + 38, "");
+
 }





More information about the cfe-commits mailing list