[clang] [Sema] Add check for bitfield assignments to larger integral types (PR #68276)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 5 16:04:06 PDT 2023
https://github.com/vabridgers updated https://github.com/llvm/llvm-project/pull/68276
>From 83dd0fa7956942b6cffefb12caf5f070196b4ca3 Mon Sep 17 00:00:00 2001
From: Vince Bridgers <vince.a.bridgers at gmail.com>
Date: Thu, 5 Oct 2023 02:39:12 +0200
Subject: [PATCH] [Sema] Add check for bitfield assignments to integral types
We noticed that clang does not check for bitfield assignment widths,
while gcc does check this.
gcc produced a warning like so for it's -Wconversion flag:
$ gcc -Wconversion -c test.c
test.c: In function 'foo':
test.c:10:15: warning: conversion from 'int' to 'signed char:7' may
change value [-Wconversion]
10 | vxx.bf = x; // no warning
| ^
This change simply adds this for integral types under the -Wconversion
compiler option.
---
.../clang/Basic/DiagnosticSemaKinds.td | 3 ++
clang/lib/Sema/SemaChecking.cpp | 14 ++++++++
clang/test/SemaCXX/bitfield-width.c | 36 +++++++++++++++++++
3 files changed, 53 insertions(+)
create mode 100644 clang/test/SemaCXX/bitfield-width.c
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 28f1db29e62fa91..ec0004d545357b7 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6171,6 +6171,9 @@ def warn_signed_bitfield_enum_conversion : Warning<
"signed bit-field %0 needs an extra bit to represent the largest positive "
"enumerators of %1">,
InGroup<BitFieldEnumConversion>, DefaultIgnore;
+def warn_bitfield_too_small_for_integral_type : Warning<
+ "bit-field %0 (%1 bits) is not wide enough to store type of %2 ">,
+ InGroup<Conversion>, DefaultIgnore;
def note_change_bitfield_sign : Note<
"consider making the bitfield type %select{unsigned|signed}0">;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 446e35218bff0ad..4a664eb1b4fb032 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -14299,6 +14299,19 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
S.Diag(WidthExpr->getExprLoc(), diag::note_widen_bitfield)
<< BitsNeeded << ED << WidthExpr->getSourceRange();
}
+ } else if (OriginalInit->getType()->isIntegralType(S.Context)) {
+ IntRange LikelySourceRange =
+ GetExprRange(S.Context, Init, S.isConstantEvaluatedContext(),
+ /*Approximate=*/true);
+
+ if (LikelySourceRange.Width > FieldWidth) {
+ Expr *WidthExpr = Bitfield->getBitWidth();
+ S.Diag(InitLoc, diag::warn_bitfield_too_small_for_integral_type)
+ << Bitfield << FieldWidth << OriginalInit->getType();
+ S.Diag(WidthExpr->getExprLoc(), diag::note_widen_bitfield)
+ << LikelySourceRange.Width << OriginalInit->getType()
+ << WidthExpr->getSourceRange();
+ }
}
return false;
@@ -15224,6 +15237,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
if (TargetRange.Width == 32 && S.Context.getIntWidth(E->getType()) == 64)
return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_integer_64_32,
/* pruneControlFlow */ true);
+
return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_integer_precision);
}
diff --git a/clang/test/SemaCXX/bitfield-width.c b/clang/test/SemaCXX/bitfield-width.c
new file mode 100644
index 000000000000000..cf6fd9231f9d439
--- /dev/null
+++ b/clang/test/SemaCXX/bitfield-width.c
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -Wconversion -fsyntax-only -verify %s
+
+typedef struct _xx {
+ int bf:9; // expected-note{{widen this field to 32 bits to store all values of 'int'}}
+ // expected-note at -1{{widen this field to 16 bits to store all values of 'short'}}
+ // expected-note at -2{{widen this field to 32 bits to store all values of 'int'}}
+ // expected-note at -3{{widen this field to 10 bits to store all values of 'int'}}
+ } xx, *pxx;
+
+ xx vxx;
+
+ void foo1(int x) {
+ vxx.bf = x; // expected-warning{{bit-field 'bf' (9 bits) is not wide enough to store type of 'int'}}
+ }
+ void foo2(short x) {
+ vxx.bf = x; // expected-warning{{bit-field 'bf' (9 bits) is not wide enough to store type of 'short'}}
+ }
+ void foo3(char x) {
+ vxx.bf = x; // no warning expected
+ }
+ void foo5(void * x) {
+ vxx.bf = (int)x; // expected-warning{{cast to smaller integer type 'int' from 'void *'}}
+ // expected-warning at -1{{bit-field 'bf' (9 bits) is not wide enough to store type of 'int'}}
+ }
+ void foo6(short x) {
+ vxx.bf = 0xff & x; // no warning expected
+ }
+ void foo7(short x) {
+ vxx.bf = 0x1ff & x; // no warning expected
+ }
+ void foo8(short x) {
+ vxx.bf = 0x3ff & x; // expected-warning{{bit-field 'bf' (9 bits) is not wide enough to store type of 'int'}}
+ }
+ int fee(void) {
+ return 0;
+ }
More information about the cfe-commits
mailing list