[cfe-commits] r94826 - in /cfe/trunk: lib/AST/Expr.cpp lib/Sema/SemaInit.cpp lib/Sema/SemaInit.h test/CodeGenCXX/reference-init.cpp

Douglas Gregor dgregor at apple.com
Fri Jan 29 11:14:03 PST 2010


Author: dgregor
Date: Fri Jan 29 13:14:02 2010
New Revision: 94826

URL: http://llvm.org/viewvc/llvm-project?rev=94826&view=rev
Log:
Fix reference binding of const lvalue references to bit-fields, which
requires a temporary. Previously, we were building an initialization
sequence that bound to the bit-field as if it were a real lvalue. Note
that we previously (and still) diagnose binding of non-const
references to bit-fields, as we should.

There's no real way to test that this code is correct, since reference
binding does not *currently* have any representation in the AST. This
fix should make it easier for that to happen, so I've verified this
fix with...

Added InitializationSequence::dump(), to print an initialization
sequence for debugging purposes.


Modified:
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/lib/Sema/SemaInit.h
    cfe/trunk/test/CodeGenCXX/reference-init.cpp

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=94826&r1=94825&r2=94826&view=diff

==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Fri Jan 29 13:14:02 2010
@@ -1958,6 +1958,13 @@
 FieldDecl *Expr::getBitField() {
   Expr *E = this->IgnoreParens();
 
+  while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+    if (ICE->isLvalueCast() && ICE->getCastKind() == CastExpr::CK_NoOp)
+      E = ICE->getSubExpr()->IgnoreParens();
+    else
+      break;
+  }
+
   if (MemberExpr *MemRef = dyn_cast<MemberExpr>(E))
     if (FieldDecl *Field = dyn_cast<FieldDecl>(MemRef->getMemberDecl()))
       if (Field->isBitField())

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=94826&r1=94825&r2=94826&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Fri Jan 29 13:14:02 2010
@@ -2327,16 +2327,20 @@
       //   - is an lvalue (but is not a bit-field), and "cv1 T1" is 
       //     reference-compatible with "cv2 T2," or
       //
-      // Per C++ [over.best.ics]p2, we ignore whether the lvalue is a 
+      // Per C++ [over.best.ics]p2, we don't diagnose whether the lvalue is a 
       // bit-field when we're determining whether the reference initialization
-      // can occur. This property will be checked by PerformInitialization.
+      // can occur. However, we do pay attention to whether it is a bit-field
+      // to decide whether we're actually binding to a temporary created from
+      // the bit-field.
       if (DerivedToBase)
         Sequence.AddDerivedToBaseCastStep(
                          S.Context.getQualifiedType(T1, T2Quals), 
                          /*isLValue=*/true);
       if (T1Quals != T2Quals)
         Sequence.AddQualificationConversionStep(cv1T1, /*IsLValue=*/true);
-      Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/false);
+      bool BindingTemporary = T1Quals.hasConst() && !T1Quals.hasVolatile() &&
+           Initializer->getBitField();
+      Sequence.AddReferenceBindingStep(cv1T1, BindingTemporary);
       return;
     }
     
@@ -3665,6 +3669,194 @@
   return true;
 }
 
+void InitializationSequence::dump(llvm::raw_ostream &OS) const {
+  switch (SequenceKind) {
+  case FailedSequence: {
+    OS << "Failed sequence: ";
+    switch (Failure) {
+    case FK_TooManyInitsForReference:
+      OS << "too many initializers for reference";
+      break;
+      
+    case FK_ArrayNeedsInitList:
+      OS << "array requires initializer list";
+      break;
+      
+    case FK_ArrayNeedsInitListOrStringLiteral:
+      OS << "array requires initializer list or string literal";
+      break;
+      
+    case FK_AddressOfOverloadFailed:
+      OS << "address of overloaded function failed";
+      break;
+      
+    case FK_ReferenceInitOverloadFailed:
+      OS << "overload resolution for reference initialization failed";
+      break;
+      
+    case FK_NonConstLValueReferenceBindingToTemporary:
+      OS << "non-const lvalue reference bound to temporary";
+      break;
+      
+    case FK_NonConstLValueReferenceBindingToUnrelated:
+      OS << "non-const lvalue reference bound to unrelated type";
+      break;
+      
+    case FK_RValueReferenceBindingToLValue:
+      OS << "rvalue reference bound to an lvalue";
+      break;
+      
+    case FK_ReferenceInitDropsQualifiers:
+      OS << "reference initialization drops qualifiers";
+      break;
+      
+    case FK_ReferenceInitFailed:
+      OS << "reference initialization failed";
+      break;
+      
+    case FK_ConversionFailed:
+      OS << "conversion failed";
+      break;
+      
+    case FK_TooManyInitsForScalar:
+      OS << "too many initializers for scalar";
+      break;
+      
+    case FK_ReferenceBindingToInitList:
+      OS << "referencing binding to initializer list";
+      break;
+      
+    case FK_InitListBadDestinationType:
+      OS << "initializer list for non-aggregate, non-scalar type";
+      break;
+      
+    case FK_UserConversionOverloadFailed:
+      OS << "overloading failed for user-defined conversion";
+      break;
+      
+    case FK_ConstructorOverloadFailed:
+      OS << "constructor overloading failed";
+      break;
+      
+    case FK_DefaultInitOfConst:
+      OS << "default initialization of a const variable";
+      break;
+    }   
+    OS << '\n';
+    return;
+  }
+      
+  case DependentSequence:
+    OS << "Dependent sequence: ";
+    return;
+      
+  case UserDefinedConversion:
+    OS << "User-defined conversion sequence: ";
+    break;
+      
+  case ConstructorInitialization:
+    OS << "Constructor initialization sequence: ";
+    break;
+      
+  case ReferenceBinding:
+    OS << "Reference binding: ";
+    break;
+      
+  case ListInitialization:
+    OS << "List initialization: ";
+    break;
+
+  case ZeroInitialization:
+    OS << "Zero initialization\n";
+    return;
+      
+  case NoInitialization:
+    OS << "No initialization\n";
+    return;
+      
+  case StandardConversion:
+    OS << "Standard conversion: ";
+    break;
+      
+  case CAssignment:
+    OS << "C assignment: ";
+    break;
+      
+  case StringInit:
+    OS << "String initialization: ";
+    break;
+  }
+  
+  for (step_iterator S = step_begin(), SEnd = step_end(); S != SEnd; ++S) {
+    if (S != step_begin()) {
+      OS << " -> ";
+    }
+    
+    switch (S->Kind) {
+    case SK_ResolveAddressOfOverloadedFunction:
+      OS << "resolve address of overloaded function";
+      break;
+      
+    case SK_CastDerivedToBaseRValue:
+      OS << "derived-to-base case (rvalue" << S->Type.getAsString() << ")";
+      break;
+      
+    case SK_CastDerivedToBaseLValue:
+      OS << "derived-to-base case (lvalue" << S->Type.getAsString() << ")";
+      break;
+      
+    case SK_BindReference:
+      OS << "bind reference to lvalue";
+      break;
+      
+    case SK_BindReferenceToTemporary:
+      OS << "bind reference to a temporary";
+      break;
+      
+    case SK_UserConversion:
+      OS << "user-defined conversion via " << S->Function->getNameAsString();
+      break;
+      
+    case SK_QualificationConversionRValue:
+      OS << "qualification conversion (rvalue)";
+
+    case SK_QualificationConversionLValue:
+      OS << "qualification conversion (lvalue)";
+      break;
+      
+    case SK_ConversionSequence:
+      OS << "implicit conversion sequence (";
+      S->ICS->DebugPrint(); // FIXME: use OS
+      OS << ")";
+      break;
+      
+    case SK_ListInitialization:
+      OS << "list initialization";
+      break;
+      
+    case SK_ConstructorInitialization:
+      OS << "constructor initialization";
+      break;
+      
+    case SK_ZeroInitialization:
+      OS << "zero initialization";
+      break;
+      
+    case SK_CAssignment:
+      OS << "C assignment";
+      break;
+      
+    case SK_StringInit:
+      OS << "string initialization";
+      break;
+    }
+  }
+}
+
+void InitializationSequence::dump() const {
+  dump(llvm::errs());
+}
+
 //===----------------------------------------------------------------------===//
 // Initialization helper functions
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/lib/Sema/SemaInit.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.h?rev=94826&r1=94825&r2=94826&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.h (original)
+++ cfe/trunk/lib/Sema/SemaInit.h Fri Jan 29 13:14:02 2010
@@ -21,6 +21,10 @@
 #include "llvm/ADT/SmallVector.h"
 #include <cassert>
 
+namespace llvm {
+  class raw_ostream;
+}
+
 namespace clang {
   
 class CXXBaseSpecifier;
@@ -658,6 +662,14 @@
     assert(getKind() == FailedSequence && "Not an initialization failure!");
     return Failure;
   }
+  
+  /// \brief Dump a representation of this initialization sequence to 
+  /// the given stream, for debugging purposes.
+  void dump(llvm::raw_ostream &OS) const;
+  
+  /// \brief Dump a representation of this initialization sequence to 
+  /// standard error, for debugging purposes.
+  void dump() const;
 };
   
 } // end namespace clang

Modified: cfe/trunk/test/CodeGenCXX/reference-init.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/reference-init.cpp?rev=94826&r1=94825&r2=94826&view=diff

==============================================================================
--- cfe/trunk/test/CodeGenCXX/reference-init.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/reference-init.cpp Fri Jan 29 13:14:02 2010
@@ -19,3 +19,6 @@
 struct Foo { int foo; };
 Foo& ignoreSetMutex = *(new Foo);
 
+// Binding to a bit-field that requires a temporary. 
+struct { int bitfield : 3; } s = { 3 };
+const int &s2 = s.bitfield;





More information about the cfe-commits mailing list