mirror of
https://github.com/intel/llvm.git
synced 2026-02-02 02:00:03 +08:00
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. llvm-svn: 94826
This commit is contained in:
@@ -1958,6 +1958,13 @@ bool Expr::isNullPointerConstant(ASTContext &Ctx,
|
||||
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())
|
||||
|
||||
@@ -2327,16 +2327,20 @@ static void TryReferenceInitialization(Sema &S,
|
||||
// - 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 @@ bool InitializationSequence::Diagnose(Sema &S,
|
||||
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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace llvm {
|
||||
class raw_ostream;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
class CXXBaseSpecifier;
|
||||
@@ -658,6 +662,14 @@ public:
|
||||
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
|
||||
|
||||
@@ -19,3 +19,6 @@ namespace PR5911 {
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user