https://github.com/vabridgers updated https://github.com/llvm/llvm-project/pull/68276
>From 3f5fc972933535ba57c1a833fbd329f81c365f91 Mon Sep 17 00:00:00 2001 From: Vince Bridgers <vince.a.bridg...@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 | 10 +++++++ clang/test/SemaCXX/bitfield-width.c | 26 +++++++++++++++++++ 3 files changed, 39 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 217309c4ecbca52..a66fd57054a1ce7 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6165,6 +6165,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 is not wide enough to store type of %1 ">, + 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 3b0cc154c2e46ab..eb567bc4935e768 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -14300,6 +14300,16 @@ 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)) { + TypeInfo TI = S.Context.getTypeInfo(OriginalInit->getType()); + if (TI.Width > FieldWidth) { + Expr *WidthExpr = Bitfield->getBitWidth(); + S.Diag(InitLoc, diag::warn_bitfield_too_small_for_integral_type) + << Bitfield << OriginalInit->getType(); + S.Diag(WidthExpr->getExprLoc(), diag::note_widen_bitfield) + << TI.Width << OriginalInit->getType() + << WidthExpr->getSourceRange(); + } } return false; diff --git a/clang/test/SemaCXX/bitfield-width.c b/clang/test/SemaCXX/bitfield-width.c new file mode 100644 index 000000000000000..c9856f53922c490 --- /dev/null +++ b/clang/test/SemaCXX/bitfield-width.c @@ -0,0 +1,26 @@ +// 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@-1{{widen this field to 16 bits to store all values of 'short'}} + // expected-note@-3{{widen this field to 32 bits to store all values of 'int'}} + } xx, *pxx; + + xx vxx; + + void foo1(int x) { + vxx.bf = x; // expected-warning{{bit-field 'bf' is not wide enough to store type of 'int'}} + } + void foo2(short x) { + vxx.bf = x; // expected-warning{{bit-field 'bf' 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@-1{{bit-field 'bf' is not wide enough to store type of 'int'}} + } + int fee(void) { + return 0; + } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits