r181252 - Grab-bag of bit-field fixes:

John McCall rjmccall at apple.com
Mon May 6 14:39:12 PDT 2013


Author: rjmccall
Date: Mon May  6 16:39:12 2013
New Revision: 181252

URL: http://llvm.org/viewvc/llvm-project?rev=181252&view=rev
Log:
Grab-bag of bit-field fixes:

  - References to ObjC bit-field ivars are bit-field lvalues;
    fixes rdar://13794269, which got me started down this.
  - Introduce Expr::refersToBitField, switch a couple users to
    it where semantically important, and comment the difference
    between this and the existing API.
  - Discourage Expr::getBitField by making it a bit longer and
    less general-sounding.
  - Lock down on const_casts of bit-field gl-values until we
    hear back from the committee as to whether they're allowed.

Added:
    cfe/trunk/test/CXX/expr/expr.unary/expr.sizeof/p1.cpp
Modified:
    cfe/trunk/include/clang/AST/Expr.h
    cfe/trunk/include/clang/AST/ExprObjC.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/Sema/SemaCast.cpp
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp
    cfe/trunk/test/CXX/expr/expr.post/expr.const.cast/p1-0x.cpp
    cfe/trunk/test/Sema/bitfield.c
    cfe/trunk/test/SemaObjCXX/references.mm

Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=181252&r1=181251&r2=181252&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Mon May  6 16:39:12 2013
@@ -427,12 +427,24 @@ private:
 
 public:
 
+  /// \brief Returns true if this expression is a gl-value that
+  /// potentially refers to a bit-field.
+  ///
+  /// In C++, whether a gl-value refers to a bitfield is essentially
+  /// an aspect of the value-kind type system.
+  bool refersToBitField() const { return getObjectKind() == OK_BitField; }
+
   /// \brief If this expression refers to a bit-field, retrieve the
   /// declaration of that bit-field.
-  FieldDecl *getBitField();
+  ///
+  /// Note that this returns a non-null pointer in subtly different
+  /// places than refersToBitField returns true.  In particular, this can
+  /// return a non-null pointer even for r-values loaded from
+  /// bit-fields, but it will return null for a conditional bit-field.
+  FieldDecl *getSourceBitField();
 
-  const FieldDecl *getBitField() const {
-    return const_cast<Expr*>(this)->getBitField();
+  const FieldDecl *getSourceBitField() const {
+    return const_cast<Expr*>(this)->getSourceBitField();
   }
 
   /// \brief If this expression is an l-value for an Objective C

Modified: cfe/trunk/include/clang/AST/ExprObjC.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprObjC.h?rev=181252&r1=181251&r2=181252&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExprObjC.h (original)
+++ cfe/trunk/include/clang/AST/ExprObjC.h Mon May  6 16:39:12 2013
@@ -476,7 +476,8 @@ public:
                   SourceLocation l, SourceLocation oploc,
                   Expr *base,
                   bool arrow = false, bool freeIvar = false) :
-    Expr(ObjCIvarRefExprClass, t, VK_LValue, OK_Ordinary,
+    Expr(ObjCIvarRefExprClass, t, VK_LValue,
+         d->isBitField() ? OK_BitField : OK_Ordinary,
          /*TypeDependent=*/false, base->isValueDependent(), 
          base->isInstantiationDependent(),
          base->containsUnexpandedParameterPack()), 

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=181252&r1=181251&r2=181252&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon May  6 16:39:12 2013
@@ -1307,7 +1307,8 @@ def err_member_function_call_bad_cvr : E
     "volatile or restrict|const, volatile, or restrict}2">;
 
 def err_reference_bind_to_bitfield : Error<
-  "%select{non-const|volatile}0 reference cannot bind to bit-field %1">;
+  "%select{non-const|volatile}0 reference cannot bind to "
+  "bit-field%select{| %1}2">;
 def err_reference_bind_to_vector_element : Error<
   "%select{non-const|volatile}0 reference cannot bind to vector element">;
 def err_reference_var_requires_init : Error<
@@ -4629,6 +4630,9 @@ def err_bad_cxx_cast_generic : Error<
 def err_bad_cxx_cast_rvalue : Error<
   "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
   "functional-style cast}0 from rvalue to reference type %2">;
+def err_bad_cxx_cast_bitfield : Error<
+  "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
+  "functional-style cast}0 from bit-field lvalue to reference type %2">;
 def err_bad_cxx_cast_qualifiers_away : Error<
   "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
   "functional-style cast}0 from %1 to %2 casts away qualifiers">;

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=181252&r1=181251&r2=181252&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Mon May  6 16:39:12 2013
@@ -4277,7 +4277,7 @@ QualType ASTContext::isPromotableBitFiel
   if (E->isTypeDependent() || E->isValueDependent())
     return QualType();
   
-  FieldDecl *Field = E->getBitField();
+  FieldDecl *Field = E->getSourceBitField(); // FIXME: conditional bit-fields?
   if (!Field)
     return QualType();
 

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=181252&r1=181251&r2=181252&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Mon May  6 16:39:12 2013
@@ -3149,7 +3149,7 @@ bool Expr::isObjCSelfExpr() const {
   return M->getSelfDecl() == Param;
 }
 
-FieldDecl *Expr::getBitField() {
+FieldDecl *Expr::getSourceBitField() {
   Expr *E = this->IgnoreParens();
 
   while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
@@ -3165,6 +3165,11 @@ FieldDecl *Expr::getBitField() {
       if (Field->isBitField())
         return Field;
 
+  if (ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E))
+    if (FieldDecl *Ivar = dyn_cast<FieldDecl>(IvarRef->getDecl()))
+      if (Ivar->isBitField())
+        return Ivar;
+
   if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E))
     if (FieldDecl *Field = dyn_cast<FieldDecl>(DeclRef->getDecl()))
       if (Field->isBitField())
@@ -3172,10 +3177,10 @@ FieldDecl *Expr::getBitField() {
 
   if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(E)) {
     if (BinOp->isAssignmentOp() && BinOp->getLHS())
-      return BinOp->getLHS()->getBitField();
+      return BinOp->getLHS()->getSourceBitField();
 
     if (BinOp->getOpcode() == BO_Comma && BinOp->getRHS())
-      return BinOp->getRHS()->getBitField();
+      return BinOp->getRHS()->getSourceBitField();
   }
 
   return 0;

Modified: cfe/trunk/lib/Sema/SemaCast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCast.cpp?rev=181252&r1=181251&r2=181252&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCast.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCast.cpp Mon May  6 16:39:12 2013
@@ -1452,7 +1452,7 @@ static TryCastResult TryConstCast(Sema &
   DestType = Self.Context.getCanonicalType(DestType);
   QualType SrcType = SrcExpr->getType();
   if (const ReferenceType *DestTypeTmp =DestType->getAs<ReferenceType>()) {
-    if (DestTypeTmp->isLValueReferenceType() && !SrcExpr->isLValue()) {
+    if (isa<LValueReferenceType>(DestTypeTmp) && !SrcExpr->isLValue()) {
       // Cannot const_cast non-lvalue to lvalue reference type. But if this
       // is C-style, static_cast might find a way, so we simply suggest a
       // message and tell the parent to keep searching.
@@ -1460,6 +1460,16 @@ static TryCastResult TryConstCast(Sema &
       return TC_NotApplicable;
     }
 
+    // It's not completely clear under the standard whether we can
+    // const_cast bit-field gl-values.  Doing so would not be
+    // intrinsically complicated, but for now, we say no for
+    // consistency with other compilers and await the word of the
+    // committee.
+    if (SrcExpr->refersToBitField()) {
+      msg = diag::err_bad_cxx_cast_bitfield;
+      return TC_NotApplicable;
+    }
+
     // C++ 5.2.11p4: An lvalue of type T1 can be [cast] to an lvalue of type T2
     //   [...] if a pointer to T1 can be [cast] to the type pointer to T2.
     DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType());

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=181252&r1=181251&r2=181252&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Mon May  6 16:39:12 2013
@@ -4311,7 +4311,7 @@ static IntRange GetExprRange(ASTContext
     IntRange::forValueOfType(C, E->getType());
   }
 
-  if (FieldDecl *BitField = E->getBitField())
+  if (FieldDecl *BitField = E->getSourceBitField())
     return IntRange(BitField->getBitWidthValue(C),
                     BitField->getType()->isUnsignedIntegerOrEnumerationType());
 
@@ -4688,7 +4688,7 @@ static void AnalyzeAssignment(Sema &S, B
 
   // We want to recurse on the RHS as normal unless we're assigning to
   // a bitfield.
-  if (FieldDecl *Bitfield = E->getLHS()->getBitField()) {
+  if (FieldDecl *Bitfield = E->getLHS()->getSourceBitField()) {
     if (AnalyzeBitFieldAssignment(S, Bitfield, E->getRHS(),
                                   E->getOperatorLoc())) {
       // Recurse, ignoring any implicit conversions on the RHS.

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=181252&r1=181251&r2=181252&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon May  6 16:39:12 2013
@@ -3383,7 +3383,7 @@ Sema::CreateUnaryExprOrTypeTraitExpr(Exp
     isInvalid = CheckAlignOfExpr(*this, E);
   } else if (ExprKind == UETT_VecStep) {
     isInvalid = CheckVecStepExpr(E);
-  } else if (E->getBitField()) {  // C99 6.5.3.4p1.
+  } else if (E->refersToBitField()) {  // C99 6.5.3.4p1.
     Diag(E->getExprLoc(), diag::err_sizeof_alignof_bitfield) << 0;
     isInvalid = true;
   } else {

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=181252&r1=181251&r2=181252&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Mon May  6 16:39:12 2013
@@ -3440,7 +3440,7 @@ convertQualifiersAndValueKindIfNecessary
                                          Qualifiers T1Quals,
                                          Qualifiers T2Quals,
                                          bool IsLValueRef) {
-  bool IsNonAddressableType = Initializer->getBitField() ||
+  bool IsNonAddressableType = Initializer->refersToBitField() ||
                               Initializer->refersToVectorElement();
 
   if (IsNonAddressableType) {
@@ -5225,13 +5225,18 @@ InitializationSequence::Perform(Sema &S,
     }
 
     case SK_BindReference:
-      if (FieldDecl *BitField = CurInit.get()->getBitField()) {
-        // References cannot bind to bit fields (C++ [dcl.init.ref]p5).
+      // References cannot bind to bit-fields (C++ [dcl.init.ref]p5).
+      if (CurInit.get()->refersToBitField()) {
+        // We don't necessarily have an unambiguous source bit-field.
+        FieldDecl *BitField = CurInit.get()->getSourceBitField();
         S.Diag(Kind.getLocation(), diag::err_reference_bind_to_bitfield)
           << Entity.getType().isVolatileQualified()
-          << BitField->getDeclName()
+          << (BitField ? BitField->getDeclName() : DeclarationName())
+          << (BitField != NULL)
           << CurInit.get()->getSourceRange();
-        S.Diag(BitField->getLocation(), diag::note_bitfield_decl);
+        if (BitField)
+          S.Diag(BitField->getLocation(), diag::note_bitfield_decl);
+
         return ExprError();
       }
 

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=181252&r1=181251&r2=181252&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon May  6 16:39:12 2013
@@ -1837,7 +1837,7 @@ bool Sema::IsIntegralPromotion(Expr *Fro
   // conversion.
   using llvm::APSInt;
   if (From)
-    if (FieldDecl *MemberDecl = From->getBitField()) {
+    if (FieldDecl *MemberDecl = From->getSourceBitField()) {
       APSInt BitWidth;
       if (FromType->isIntegralType(Context) &&
           MemberDecl->getBitWidth()->isIntegerConstantExpr(BitWidth, Context)) {

Modified: cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp?rev=181252&r1=181251&r2=181252&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp (original)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp Mon May  6 16:39:12 2013
@@ -38,3 +38,26 @@ namespace PR6066 {
     return 0;
   }
 }
+
+namespace test3 {
+  struct A {
+    unsigned bitX : 4; // expected-note 4 {{bit-field is declared here}}
+    unsigned bitY : 4; // expected-note {{bit-field is declared here}}
+    unsigned var;
+
+    void foo();
+  };
+
+  void test(A *a) {
+    unsigned &t0 = a->bitX; // expected-error {{non-const reference cannot bind to bit-field 'bitX'}}
+    unsigned &t1 = (unsigned&) a->bitX; // expected-error {{non-const reference cannot bind to bit-field 'bitX'}}
+    unsigned &t2 = const_cast<unsigned&>(a->bitX); // expected-error {{const_cast from bit-field lvalue to reference type 'unsigned int &'}}
+    unsigned &t3 = (a->foo(), a->bitX); // expected-error {{non-const reference cannot bind to bit-field 'bitX'}}
+    unsigned &t4 = (a->var ? a->bitX : a->bitY); // expected-error {{non-const reference cannot bind to bit-field}}
+    unsigned &t5 = (a->var ? a->bitX : a->bitX); // expected-error {{non-const reference cannot bind to bit-field}}
+    unsigned &t6 = (a->var ? a->bitX : a->var); // expected-error {{non-const reference cannot bind to bit-field}}
+    unsigned &t7 = (a->var ? a->var : a->bitY); // expected-error {{non-const reference cannot bind to bit-field}}
+    unsigned &t8 = (a->bitX = 3); // expected-error {{non-const reference cannot bind to bit-field 'bitX'}}
+    unsigned &t9 = (a->bitY += 3); // expected-error {{non-const reference cannot bind to bit-field 'bitY'}}
+  }
+}

Modified: cfe/trunk/test/CXX/expr/expr.post/expr.const.cast/p1-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.post/expr.const.cast/p1-0x.cpp?rev=181252&r1=181251&r2=181252&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.post/expr.const.cast/p1-0x.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.post/expr.const.cast/p1-0x.cpp Mon May  6 16:39:12 2013
@@ -1,5 +1,4 @@
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
-// expected-no-diagnostics
 
 // The result of the expression const_cast<T>(v) is of type T. If T is
 // an lvalue reference to object type, the result is an lvalue; if T
@@ -16,3 +15,19 @@ void test_classification(const int *ptr)
   int *ptr1 = const_cast<int *&&>(xvalue<const int*>());
   int *ptr2 = const_cast<int *&&>(prvalue<const int*>());
 }
+
+struct A {
+  volatile unsigned ubf : 4;
+  volatile unsigned uv;
+  volatile int sv;
+  void foo();
+  bool pred();
+};
+
+void test(A &a) {
+  unsigned &t0 = const_cast<unsigned&>(a.ubf); // expected-error {{const_cast from bit-field lvalue to reference type}}
+  unsigned &t1 = const_cast<unsigned&>(a.foo(), a.ubf); // expected-error {{const_cast from bit-field lvalue to reference type}}
+  unsigned &t2 = const_cast<unsigned&>(a.pred() ? a.ubf : a.ubf); // expected-error {{const_cast from bit-field lvalue to reference type}}
+  unsigned &t3 = const_cast<unsigned&>(a.pred() ? a.ubf : a.uv); // expected-error {{const_cast from bit-field lvalue to reference type}}
+  unsigned &t4 = const_cast<unsigned&>(a.pred() ? a.ubf : a.sv); // expected-error {{const_cast from rvalue to reference type}}
+}

Added: cfe/trunk/test/CXX/expr/expr.unary/expr.sizeof/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.unary/expr.sizeof/p1.cpp?rev=181252&view=auto
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.unary/expr.sizeof/p1.cpp (added)
+++ cfe/trunk/test/CXX/expr/expr.unary/expr.sizeof/p1.cpp Mon May  6 16:39:12 2013
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+struct A {
+  unsigned bitX : 4;
+  unsigned bitY : 4;
+  unsigned var;
+
+  void foo();
+};
+
+void test(A *a) {
+  int x;
+  x = sizeof(a->bitX); // expected-error {{invalid application of 'sizeof' to bit-field}}
+  x = sizeof((unsigned) a->bitX);
+  x = sizeof(a->foo(), a->bitX); // expected-error {{invalid application of 'sizeof' to bit-field}}
+  x = sizeof(a->var ? a->bitX : a->bitY); // expected-error {{invalid application of 'sizeof' to bit-field}}
+  x = sizeof(a->var ? a->bitX : a->bitX); // expected-error {{invalid application of 'sizeof' to bit-field}}
+  x = sizeof(a->bitX = 3); // expected-error {{invalid application of 'sizeof' to bit-field}}
+  x = sizeof(a->bitY += 3); // expected-error {{invalid application of 'sizeof' to bit-field}}
+}

Modified: cfe/trunk/test/Sema/bitfield.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/bitfield.c?rev=181252&r1=181251&r2=181252&view=diff
==============================================================================
--- cfe/trunk/test/Sema/bitfield.c (original)
+++ cfe/trunk/test/Sema/bitfield.c Mon May  6 16:39:12 2013
@@ -39,3 +39,18 @@ int y;
 struct PR8025 {
   double : 2; // expected-error{{anonymous bit-field has non-integral type 'double'}}
 };
+
+struct Test4 {
+  unsigned bitX : 4;
+  unsigned bitY : 4;
+  unsigned var;
+};
+void test4(struct Test4 *t) {
+  (void) sizeof(t->bitX); // expected-error {{invalid application of 'sizeof' to bit-field}}
+  (void) sizeof((t->bitY)); // expected-error {{invalid application of 'sizeof' to bit-field}}
+  (void) sizeof(t->bitX = 4); // not a bitfield designator in C
+  (void) sizeof(t->bitX += 4); // not a bitfield designator in C
+  (void) sizeof((void) 0, t->bitX); // not a bitfield designator in C
+  (void) sizeof(t->var ? t->bitX : t->bitY); // not a bitfield designator in C
+  (void) sizeof(t->var ? t->bitX : t->bitX); // not a bitfield designator in C
+}

Modified: cfe/trunk/test/SemaObjCXX/references.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/references.mm?rev=181252&r1=181251&r2=181252&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjCXX/references.mm (original)
+++ cfe/trunk/test/SemaObjCXX/references.mm Mon May  6 16:39:12 2013
@@ -1,5 +1,7 @@
-// RUN: %clang_cc1 -verify -emit-llvm -o - %s
-// expected-no-diagnostics
+// RUN: %clang_cc1 -verify -o - %s
+
+__attribute__((objc_root_class))
+ at interface Root @end
 
 // Test reference binding.
 
@@ -8,7 +10,7 @@ typedef struct {
   int f1;
 } T;
 
- at interface A
+ at interface A : Root
 @property (assign) T p0;
 @property (assign) T& p1; 
 @end
@@ -61,3 +63,14 @@ void f6(baz* x) {
   f5d(ToBar());
   (void)((foo&)ToBar());
 }
+
+// rdar://13794269
+ at interface B : Root @end
+ at implementation B {
+  unsigned bf : 4; // expected-note {{declared here}}
+}
+
+- (void) foo {
+  unsigned &i = bf; // expected-error {{non-const reference cannot bind to bit-field 'bf'}}
+}
+ at end





More information about the cfe-commits mailing list