[cfe-commits] r150895 - in /cfe/trunk: include/clang/Basic/DiagnosticASTKinds.td lib/AST/ExprConstant.cpp test/SemaCXX/constant-expression-cxx11.cpp

Richard Smith richard-llvm at metafoo.co.uk
Sat Feb 18 14:04:06 PST 2012


Author: rsmith
Date: Sat Feb 18 16:04:06 2012
New Revision: 150895

URL: http://llvm.org/viewvc/llvm-project?rev=150895&view=rev
Log:
Implement constant expression support for __real__ and __imag__ on lvalue
complex numbers. Treat complex numbers as arrays of the corresponding component
type, in order to make std::complex behave properly if implemented in terms of
_Complex T.

Apparently libstdc++'s std::complex is implemented this way, and we were
rejecting a member like this:

  constexpr double real() { return __real__ val; }

because it was marked constexpr but unable to produce a constant expression.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=150895&r1=150894&r2=150895&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Sat Feb 18 16:04:06 2012
@@ -58,12 +58,14 @@
   "%select{temporary|%2}1 is not a constant expression">;
 def note_constexpr_past_end_subobject : Note<
   "cannot %select{access base class of|access derived class of|access field of|"
-  "access array element of|ERROR|call member function on}0 "
+  "access array element of|ERROR|call member function on|"
+  "access real component of|access imaginary component of}0 "
   "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|"
-  "call member function on}0 null pointer">;
+  "call member function on|access real component of|"
+  "access imaginary component of}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=150895&r1=150894&r2=150895&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Sat Feb 18 16:04:06 2012
@@ -105,6 +105,11 @@
         Type = CAT->getElementType();
         ArraySize = CAT->getSize().getZExtValue();
         MostDerivedLength = I + 1;
+      } else if (Type->isAnyComplexType()) {
+        const ComplexType *CT = Type->castAs<ComplexType>();
+        Type = CT->getElementType();
+        ArraySize = 2;
+        MostDerivedLength = I + 1;
       } else if (const FieldDecl *FD = getAsField(Path[I])) {
         Type = FD->getType();
         ArraySize = 0;
@@ -120,7 +125,7 @@
   // The order of this enum is important for diagnostics.
   enum CheckSubobjectKind {
     CSK_Base, CSK_Derived, CSK_Field, CSK_ArrayToPointer, CSK_ArrayIndex,
-    CSK_This
+    CSK_This, CSK_Real, CSK_Imag
   };
 
   /// A path from a glvalue to a subobject of that glvalue.
@@ -221,6 +226,18 @@
         MostDerivedPathLength = Entries.size();
       }
     }
+    /// Update this designator to refer to the given complex component.
+    void addComplexUnchecked(QualType EltTy, bool Imag) {
+      PathEntry Entry;
+      Entry.ArrayIndex = Imag;
+      Entries.push_back(Entry);
+
+      // This is technically a most-derived object, though in practice this
+      // is unlikely to matter.
+      MostDerivedType = EltTy;
+      MostDerivedArraySize = 2;
+      MostDerivedPathLength = Entries.size();
+    }
     void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E, uint64_t N);
     /// Add N to the address of this subobject.
     void adjustIndex(EvalInfo &Info, const Expr *E, uint64_t N) {
@@ -792,6 +809,10 @@
       checkSubobject(Info, E, CSK_ArrayToPointer);
       Designator.addArrayUnchecked(CAT);
     }
+    void addComplex(EvalInfo &Info, const Expr *E, QualType EltTy, bool Imag) {
+      checkSubobject(Info, E, Imag ? CSK_Imag : CSK_Real);
+      Designator.addComplexUnchecked(EltTy, Imag);
+    }
     void adjustIndex(EvalInfo &Info, const Expr *E, uint64_t N) {
       if (!checkNullPointer(Info, E, CSK_ArrayIndex))
         return;
@@ -1420,6 +1441,24 @@
   return true;
 }
 
+/// Update an lvalue to refer to a component of a complex number.
+/// \param Info - Information about the ongoing evaluation.
+/// \param LVal - The lvalue to be updated.
+/// \param EltTy - The complex number's component type.
+/// \param Imag - False for the real component, true for the imaginary.
+static bool HandleLValueComplexElement(EvalInfo &Info, const Expr *E,
+                                       LValue &LVal, QualType EltTy,
+                                       bool Imag) {
+  if (Imag) {
+    CharUnits SizeOfComponent;
+    if (!HandleSizeof(Info, E->getExprLoc(), EltTy, SizeOfComponent))
+      return false;
+    LVal.Offset += SizeOfComponent;
+  }
+  LVal.addComplex(Info, E, EltTy, Imag);
+  return true;
+}
+
 /// Try to evaluate the initializer for a variable declaration.
 static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E,
                                 const VarDecl *VD,
@@ -1566,6 +1605,25 @@
       else
         O = &O->getArrayFiller();
       ObjType = CAT->getElementType();
+    } else if (ObjType->isAnyComplexType()) {
+      // Next subobject is a complex number.
+      uint64_t Index = Sub.Entries[I].ArrayIndex;
+      if (Index > 1) {
+        Info.Diag(E->getExprLoc(), Info.getLangOpts().CPlusPlus0x ?
+                    (unsigned)diag::note_constexpr_read_past_end :
+                    (unsigned)diag::note_invalid_subexpr_in_const_expr);
+        return false;
+      }
+      assert(I == N - 1 && "extracting subobject of scalar?");
+      if (O->isComplexInt()) {
+        Obj = CCValue(Index ? O->getComplexIntImag()
+                            : O->getComplexIntReal());
+      } else {
+        assert(O->isComplexFloat());
+        Obj = CCValue(Index ? O->getComplexFloatImag()
+                            : O->getComplexFloatReal());
+      }
+      return true;
     } else if (const FieldDecl *Field = getAsField(Sub.Entries[I])) {
       if (Field->isMutable()) {
         Info.Diag(E->getExprLoc(), diag::note_constexpr_ltor_mutable, 1)
@@ -1628,13 +1686,17 @@
                                        bool &WasArrayIndex) {
   unsigned I = 0, N = std::min(A.Entries.size(), B.Entries.size());
   for (/**/; I != N; ++I) {
-    if (!ObjType.isNull() && ObjType->isArrayType()) {
+    if (!ObjType.isNull() &&
+        (ObjType->isArrayType() || ObjType->isAnyComplexType())) {
       // Next subobject is an array element.
       if (A.Entries[I].ArrayIndex != B.Entries[I].ArrayIndex) {
         WasArrayIndex = true;
         return I;
       }
-      ObjType = ObjType->castAsArrayTypeUnsafe()->getElementType();
+      if (ObjType->isAnyComplexType())
+        ObjType = ObjType->castAs<ComplexType>()->getElementType();
+      else
+        ObjType = ObjType->castAsArrayTypeUnsafe()->getElementType();
     } else {
       if (A.Entries[I].BaseOrMember != B.Entries[I].BaseOrMember) {
         WasArrayIndex = false;
@@ -2870,6 +2932,8 @@
   bool VisitCXXTypeidExpr(const CXXTypeidExpr *E);
   bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);
   bool VisitUnaryDeref(const UnaryOperator *E);
+  bool VisitUnaryReal(const UnaryOperator *E);
+  bool VisitUnaryImag(const UnaryOperator *E);
 
   bool VisitCastExpr(const CastExpr *E) {
     switch (E->getCastKind()) {
@@ -2889,9 +2953,6 @@
       return HandleBaseToDerivedCast(Info, E, Result);
     }
   }
-
-  // FIXME: Missing: __real__, __imag__
-
 };
 } // end anonymous namespace
 
@@ -3015,6 +3076,24 @@
   return EvaluatePointer(E->getSubExpr(), Result, Info);
 }
 
+bool LValueExprEvaluator::VisitUnaryReal(const UnaryOperator *E) {
+  if (!Visit(E->getSubExpr()))
+    return false;
+  // __real is a no-op on scalar lvalues.
+  if (E->getSubExpr()->getType()->isAnyComplexType())
+    HandleLValueComplexElement(Info, E, Result, E->getType(), false);
+  return true;
+}
+
+bool LValueExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
+  assert(E->getSubExpr()->getType()->isAnyComplexType() &&
+         "lvalue __imag__ on scalar?");
+  if (!Visit(E->getSubExpr()))
+    return false;
+  HandleLValueComplexElement(Info, E, Result, E->getType(), true);
+  return true;
+}
+
 //===----------------------------------------------------------------------===//
 // Pointer Evaluation
 //===----------------------------------------------------------------------===//

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=150895&r1=150894&r2=150895&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Sat Feb 18 16:04:06 2012
@@ -1055,6 +1055,28 @@
   constexpr _Complex int test6 = {5,6};
   typedef _Complex float fcomplex;
   constexpr fcomplex test7 = fcomplex();
+
+  constexpr const double &t2r = __real test3;
+  constexpr const double &t2i = __imag test3;
+  static_assert(&t2r + 1 == &t2i, "");
+  static_assert(t2r == 1.0, "");
+  static_assert(t2i == 2.0, "");
+  constexpr const double *t2p = &t2r;
+  static_assert(t2p[-1] == 0.0, ""); // expected-error {{constant expr}} expected-note {{cannot refer to element -1 of array of 2 elements}}
+  static_assert(t2p[0] == 1.0, "");
+  static_assert(t2p[1] == 2.0, "");
+  static_assert(t2p[2] == 0.0, ""); // expected-error {{constant expr}} expected-note {{one-past-the-end pointer}}
+  static_assert(t2p[3] == 0.0, ""); // expected-error {{constant expr}} expected-note {{cannot refer to element 3 of array of 2 elements}}
+  constexpr _Complex float *p = 0;
+  constexpr float pr = __real *p; // expected-error {{constant expr}} expected-note {{cannot access real component of null}}
+  constexpr float pi = __imag *p; // expected-error {{constant expr}} expected-note {{cannot access imaginary component of null}}
+  constexpr const _Complex double *q = &test3 + 1;
+  constexpr double qr = __real *q; // expected-error {{constant expr}} expected-note {{cannot access real component of pointer past the end}}
+  constexpr double qi = __imag *q; // expected-error {{constant expr}} expected-note {{cannot access imaginary component of pointer past the end}}
+
+  static_assert(__real test6 == 5, "");
+  static_assert(__imag test6 == 6, "");
+  static_assert(&__imag test6 == &__real test6 + 1, "");
 }
 
 namespace InstantiateCaseStmt {





More information about the cfe-commits mailing list