forked from OSchip/llvm-project
Extend the bitfield-truncation warning to initializations.
rdar://problem/8652606 llvm-svn: 118773
This commit is contained in:
parent
6ed689bfcb
commit
1f425648ca
|
@ -4539,6 +4539,9 @@ private:
|
||||||
void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex);
|
void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex);
|
||||||
void CheckImplicitConversions(Expr *E, SourceLocation CC = SourceLocation());
|
void CheckImplicitConversions(Expr *E, SourceLocation CC = SourceLocation());
|
||||||
|
|
||||||
|
void CheckBitFieldInitialization(SourceLocation InitLoc, FieldDecl *Field,
|
||||||
|
Expr *Init);
|
||||||
|
|
||||||
/// \brief The parser's current scope.
|
/// \brief The parser's current scope.
|
||||||
///
|
///
|
||||||
/// The parser maintains this state here.
|
/// The parser maintains this state here.
|
||||||
|
@ -4546,6 +4549,7 @@ private:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class Parser;
|
friend class Parser;
|
||||||
|
friend class InitializationSequence;
|
||||||
|
|
||||||
/// \brief Retrieve the parser's current scope.
|
/// \brief Retrieve the parser's current scope.
|
||||||
Scope *getCurScope() const { return CurScope; }
|
Scope *getCurScope() const { return CurScope; }
|
||||||
|
|
|
@ -2608,6 +2608,55 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) {
|
||||||
<< lex->getSourceRange() << rex->getSourceRange();
|
<< lex->getSourceRange() << rex->getSourceRange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Analyzes an attempt to assign the given value to a bitfield.
|
||||||
|
///
|
||||||
|
/// Returns true if there was something fishy about the attempt.
|
||||||
|
bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
|
||||||
|
SourceLocation InitLoc) {
|
||||||
|
assert(Bitfield->isBitField());
|
||||||
|
if (Bitfield->isInvalidDecl())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Expr *OriginalInit = Init->IgnoreParenImpCasts();
|
||||||
|
|
||||||
|
llvm::APSInt Width(32);
|
||||||
|
Expr::EvalResult InitValue;
|
||||||
|
if (!Bitfield->getBitWidth()->isIntegerConstantExpr(Width, S.Context) ||
|
||||||
|
!Init->Evaluate(InitValue, S.Context) ||
|
||||||
|
!InitValue.Val.isInt())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const llvm::APSInt &Value = InitValue.Val.getInt();
|
||||||
|
unsigned OriginalWidth = Value.getBitWidth();
|
||||||
|
unsigned FieldWidth = Width.getZExtValue();
|
||||||
|
|
||||||
|
if (OriginalWidth <= FieldWidth)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
llvm::APSInt TruncatedValue = Value;
|
||||||
|
TruncatedValue.trunc(FieldWidth);
|
||||||
|
|
||||||
|
// It's fairly common to write values into signed bitfields
|
||||||
|
// that, if sign-extended, would end up becoming a different
|
||||||
|
// value. We don't want to warn about that.
|
||||||
|
if (Value.isSigned() && Value.isNegative())
|
||||||
|
TruncatedValue.sext(OriginalWidth);
|
||||||
|
else
|
||||||
|
TruncatedValue.zext(OriginalWidth);
|
||||||
|
|
||||||
|
if (Value == TruncatedValue)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::string PrettyValue = Value.toString(10);
|
||||||
|
std::string PrettyTrunc = TruncatedValue.toString(10);
|
||||||
|
|
||||||
|
S.Diag(InitLoc, diag::warn_impcast_bitfield_precision_constant)
|
||||||
|
<< PrettyValue << PrettyTrunc << OriginalInit->getType()
|
||||||
|
<< Init->getSourceRange();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// Analyze the given simple or compound assignment for warning-worthy
|
/// Analyze the given simple or compound assignment for warning-worthy
|
||||||
/// operations.
|
/// operations.
|
||||||
void AnalyzeAssignment(Sema &S, BinaryOperator *E) {
|
void AnalyzeAssignment(Sema &S, BinaryOperator *E) {
|
||||||
|
@ -2617,44 +2666,11 @@ void AnalyzeAssignment(Sema &S, BinaryOperator *E) {
|
||||||
// We want to recurse on the RHS as normal unless we're assigning to
|
// We want to recurse on the RHS as normal unless we're assigning to
|
||||||
// a bitfield.
|
// a bitfield.
|
||||||
if (FieldDecl *Bitfield = E->getLHS()->getBitField()) {
|
if (FieldDecl *Bitfield = E->getLHS()->getBitField()) {
|
||||||
assert(Bitfield->isBitField());
|
if (AnalyzeBitFieldAssignment(S, Bitfield, E->getRHS(),
|
||||||
|
E->getOperatorLoc())) {
|
||||||
Expr *RHS = E->getRHS()->IgnoreParenImpCasts();
|
// Recurse, ignoring any implicit conversions on the RHS.
|
||||||
|
return AnalyzeImplicitConversions(S, E->getRHS()->IgnoreParenImpCasts(),
|
||||||
llvm::APSInt Width(32);
|
E->getOperatorLoc());
|
||||||
Expr::EvalResult RHSValue;
|
|
||||||
if (!Bitfield->isInvalidDecl() &&
|
|
||||||
Bitfield->getBitWidth()->isIntegerConstantExpr(Width, S.Context) &&
|
|
||||||
RHS->Evaluate(RHSValue, S.Context) && RHSValue.Val.isInt()) {
|
|
||||||
const llvm::APSInt &Value = RHSValue.Val.getInt();
|
|
||||||
unsigned OriginalWidth = Value.getBitWidth();
|
|
||||||
unsigned FieldWidth = Width.getZExtValue();
|
|
||||||
|
|
||||||
if (OriginalWidth > FieldWidth) {
|
|
||||||
llvm::APSInt TruncatedValue = Value;
|
|
||||||
TruncatedValue.trunc(FieldWidth);
|
|
||||||
|
|
||||||
// It's fairly common to write values into signed bitfields
|
|
||||||
// that, if sign-extended, would end up becoming a different
|
|
||||||
// value. We don't want to warn about that.
|
|
||||||
if (Value.isSigned() && Value.isNegative())
|
|
||||||
TruncatedValue.sext(OriginalWidth);
|
|
||||||
else
|
|
||||||
TruncatedValue.zext(OriginalWidth);
|
|
||||||
|
|
||||||
if (Value != TruncatedValue) {
|
|
||||||
std::string PrettyValue = Value.toString(10);
|
|
||||||
std::string PrettyTrunc = TruncatedValue.toString(10);
|
|
||||||
|
|
||||||
S.Diag(E->getOperatorLoc(),
|
|
||||||
diag::warn_impcast_bitfield_precision_constant)
|
|
||||||
<< PrettyValue << PrettyTrunc << RHS->getType()
|
|
||||||
<< E->getRHS()->getSourceRange();
|
|
||||||
|
|
||||||
// Recurse, ignoring any implicit conversions on the RHS.
|
|
||||||
return AnalyzeImplicitConversions(S, RHS, E->getOperatorLoc());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2932,6 +2948,12 @@ void Sema::CheckImplicitConversions(Expr *E, SourceLocation CC) {
|
||||||
AnalyzeImplicitConversions(*this, E, CC);
|
AnalyzeImplicitConversions(*this, E, CC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Sema::CheckBitFieldInitialization(SourceLocation InitLoc,
|
||||||
|
FieldDecl *BitField,
|
||||||
|
Expr *Init) {
|
||||||
|
(void) AnalyzeBitFieldAssignment(*this, BitField, Init, InitLoc);
|
||||||
|
}
|
||||||
|
|
||||||
/// CheckParmsForFunctionDef - Check that the parameters of the given
|
/// CheckParmsForFunctionDef - Check that the parameters of the given
|
||||||
/// function are appropriate for the definition of a function. This
|
/// function are appropriate for the definition of a function. This
|
||||||
/// takes care of any checks that cannot be performed on the
|
/// takes care of any checks that cannot be performed on the
|
||||||
|
|
|
@ -4047,6 +4047,13 @@ InitializationSequence::Perform(Sema &S,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Diagnose non-fatal problems with the completed initialization.
|
||||||
|
if (Entity.getKind() == InitializedEntity::EK_Member &&
|
||||||
|
cast<FieldDecl>(Entity.getDecl())->isBitField())
|
||||||
|
S.CheckBitFieldInitialization(Kind.getLocation(),
|
||||||
|
cast<FieldDecl>(Entity.getDecl()),
|
||||||
|
CurInit.get());
|
||||||
|
|
||||||
return move(CurInit);
|
return move(CurInit);
|
||||||
}
|
}
|
||||||
|
@ -4534,7 +4541,7 @@ Sema::PerformCopyInitialization(const InitializedEntity &Entity,
|
||||||
if (Init.isInvalid())
|
if (Init.isInvalid())
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
||||||
Expr *InitE = (Expr *)Init.get();
|
Expr *InitE = Init.get();
|
||||||
assert(InitE && "No initialization expression?");
|
assert(InitE && "No initialization expression?");
|
||||||
|
|
||||||
if (EqualLoc.isInvalid())
|
if (EqualLoc.isInvalid())
|
||||||
|
|
|
@ -24,3 +24,16 @@ enum Test2 test2(enum Test2 *t) {
|
||||||
*t = 20;
|
*t = 20;
|
||||||
return 10; // shouldn't warn
|
return 10; // shouldn't warn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test3() {
|
||||||
|
struct A {
|
||||||
|
unsigned int foo : 2;
|
||||||
|
int bar : 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct A a = { 0, 10 }; // expected-warning {{implicit truncation from 'int' to bitfield changes value from 10 to 2}}
|
||||||
|
struct A b[] = { 0, 10, 0, 0 }; // expected-warning {{implicit truncation from 'int' to bitfield changes value from 10 to 2}}
|
||||||
|
struct A c[] = {{10, 0}}; // expected-warning {{implicit truncation from 'int' to bitfield changes value from 10 to 2}}
|
||||||
|
struct A d = (struct A) { 10, 0 }; // expected-warning {{implicit truncation from 'int' to bitfield changes value from 10 to 2}}
|
||||||
|
struct A e = { .foo = 10 }; // expected-warning {{implicit truncation from 'int' to bitfield changes value from 10 to 2}}
|
||||||
|
}
|
||||||
|
|
|
@ -43,3 +43,10 @@ namespace test1 {
|
||||||
return p == foo();
|
return p == foo();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace test2 {
|
||||||
|
struct A {
|
||||||
|
unsigned int x : 2;
|
||||||
|
A() : x(10) {} // expected-warning {{implicit truncation from 'int' to bitfield changes value from 10 to 2}}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue