Skip to content

Commit 066c96c

Browse files
author
git apple-llvm automerger
committed
Merge commit '69c8c96691c7' from llvm.org/release/17.x into stable/20230725
2 parents f2820c5 + 69c8c96 commit 066c96c

File tree

4 files changed

+67
-19
lines changed

4 files changed

+67
-19
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -481,10 +481,8 @@ Improvements to Clang's diagnostics
481481
- ``-Wformat`` cast fix-its will now suggest ``static_cast`` instead of C-style casts
482482
for C++ code.
483483
- ``-Wformat`` will no longer suggest a no-op fix-it for fixing scoped enum format
484-
warnings. Instead, it will suggest casting the enum object to the type specified
485-
in the format string.
486-
- Clang contexpr evaluator now displays notes as well as an error when a constructor
487-
of a base class is not called in the constructor of its derived class.
484+
warnings. Instead, it will suggest casting the enum object based on its
485+
underlying type.
488486

489487
Bug Fixes in This Version
490488
-------------------------

clang/lib/Sema/SemaChecking.cpp

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11478,12 +11478,15 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
1147811478
ImplicitMatch == ArgType::NoMatchTypeConfusion)
1147911479
Match = ImplicitMatch;
1148011480
assert(Match != ArgType::MatchPromotion);
11481+
1148111482
// Look through unscoped enums to their underlying type.
1148211483
bool IsEnum = false;
1148311484
bool IsScopedEnum = false;
11485+
QualType IntendedTy = ExprTy;
1148411486
if (auto EnumTy = ExprTy->getAs<EnumType>()) {
11487+
IntendedTy = EnumTy->getDecl()->getIntegerType();
1148511488
if (EnumTy->isUnscopedEnumerationType()) {
11486-
ExprTy = EnumTy->getDecl()->getIntegerType();
11489+
ExprTy = IntendedTy;
1148711490
// This controls whether we're talking about the underlying type or not,
1148811491
// which we only want to do when it's an unscoped enum.
1148911492
IsEnum = true;
@@ -11495,7 +11498,6 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
1149511498
// %C in an Objective-C context prints a unichar, not a wchar_t.
1149611499
// If the argument is an integer of some kind, believe the %C and suggest
1149711500
// a cast instead of changing the conversion specifier.
11498-
QualType IntendedTy = ExprTy;
1149911501
if (isObjCContext() &&
1150011502
FS.getConversionSpecifier().getKind() == ConversionSpecifier::CArg) {
1150111503
if (ExprTy->isIntegralOrUnscopedEnumerationType() &&
@@ -11531,8 +11533,10 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
1153111533
std::tie(CastTy, CastTyName) = shouldNotPrintDirectly(S.Context, IntendedTy, E);
1153211534
if (!CastTy.isNull()) {
1153311535
// %zi/%zu and %td/%tu are OK to use for NSInteger/NSUInteger of type int
11534-
// (long in ASTContext). Only complain to pedants.
11535-
if ((CastTyName == "NSInteger" || CastTyName == "NSUInteger") &&
11536+
// (long in ASTContext). Only complain to pedants or when they're the
11537+
// underlying type of a scoped enum (which always needs a cast).
11538+
if (!IsScopedEnum &&
11539+
(CastTyName == "NSInteger" || CastTyName == "NSUInteger") &&
1153611540
(AT.isSizeT() || AT.isPtrdiffT()) &&
1153711541
AT.matchesType(S.Context, CastTy))
1153811542
Match = ArgType::NoMatchPedantic;
@@ -11587,20 +11591,15 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
1158711591
// should be printed as 'long' for 64-bit compatibility.)
1158811592
// Rather than emitting a normal format/argument mismatch, we want to
1158911593
// add a cast to the recommended type (and correct the format string
11590-
// if necessary).
11594+
// if necessary). We should also do so for scoped enumerations.
1159111595
SmallString<16> CastBuf;
1159211596
llvm::raw_svector_ostream CastFix(CastBuf);
1159311597
CastFix << (S.LangOpts.CPlusPlus ? "static_cast<" : "(");
11594-
if (IsScopedEnum) {
11595-
CastFix << AT.getRepresentativeType(S.Context).getAsString(
11596-
S.Context.getPrintingPolicy());
11597-
} else {
11598-
IntendedTy.print(CastFix, S.Context.getPrintingPolicy());
11599-
}
11598+
IntendedTy.print(CastFix, S.Context.getPrintingPolicy());
1160011599
CastFix << (S.LangOpts.CPlusPlus ? ">" : ")");
1160111600

1160211601
SmallVector<FixItHint,4> Hints;
11603-
if ((!AT.matchesType(S.Context, IntendedTy) && !IsScopedEnum) ||
11602+
if (AT.matchesType(S.Context, IntendedTy) != ArgType::Match ||
1160411603
ShouldNotPrintDirectly)
1160511604
Hints.push_back(FixItHint::CreateReplacement(SpecRange, os.str()));
1160611605

@@ -11628,7 +11627,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
1162811627
Hints.push_back(FixItHint::CreateInsertion(After, ")"));
1162911628
}
1163011629

11631-
if (ShouldNotPrintDirectly) {
11630+
if (ShouldNotPrintDirectly && !IsScopedEnum) {
1163211631
// The expression has a type that should not be printed directly.
1163311632
// We extract the name from the typedef because we don't want to show
1163411633
// the underlying type in the diagnostic.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -verify -Wformat %s
2+
// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -fdiagnostics-parseable-fixits -Wformat %s 2>&1 | FileCheck %s
3+
4+
extern "C" int printf(const char * restrict, ...);
5+
6+
#if __LP64__
7+
typedef long CFIndex;
8+
typedef long NSInteger;
9+
typedef unsigned long NSUInteger;
10+
#else
11+
typedef int CFIndex;
12+
typedef int NSInteger;
13+
typedef unsigned int NSUInteger;
14+
#endif
15+
16+
enum class CFIndexEnum : CFIndex { One };
17+
enum class NSIntegerEnum : NSInteger { Two };
18+
enum class NSUIntegerEnum : NSUInteger { Three };
19+
20+
void f() {
21+
printf("%d", CFIndexEnum::One); // expected-warning{{format specifies type 'int' but the argument has type 'CFIndexEnum'}}
22+
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%ld"
23+
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:16}:"static_cast<long>("
24+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:32-[[@LINE-3]]:32}:")"
25+
26+
printf("%d", NSIntegerEnum::Two); // expected-warning{{format specifies type 'int' but the argument has type 'NSIntegerEnum'}}
27+
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%ld"
28+
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:16}:"static_cast<long>("
29+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:34-[[@LINE-3]]:34}:")"
30+
31+
printf("%d", NSUIntegerEnum::Three); // expected-warning{{format specifies type 'int' but the argument has type 'NSUIntegerEnum'}}
32+
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%lu"
33+
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:16}:"static_cast<unsigned long>("
34+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:37-[[@LINE-3]]:37}:")"
35+
}

clang/test/FixIt/format.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,33 @@ struct S {
1212
N::E Type;
1313
};
1414

15+
using uint32_t = unsigned;
16+
enum class FixedE : uint32_t { Two };
17+
1518
void a(N::E NEVal, S *SPtr, S &SRef) {
1619
printf("%d", N::E::One); // expected-warning{{format specifies type 'int' but the argument has type 'N::E'}}
1720
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:16-[[@LINE-1]]:16}:"static_cast<int>("
1821
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:25-[[@LINE-2]]:25}:")"
1922

2023
printf("%hd", N::E::One); // expected-warning{{format specifies type 'short' but the argument has type 'N::E'}}
21-
// CHECK: "static_cast<short>("
24+
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:14}:"%d"
25+
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:17-[[@LINE-2]]:17}:"static_cast<int>("
26+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:26-[[@LINE-3]]:26}:")"
2227

2328
printf("%hu", N::E::One); // expected-warning{{format specifies type 'unsigned short' but the argument has type 'N::E'}}
24-
// CHECK: "static_cast<unsigned short>("
29+
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:14}:"%d"
30+
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:17-[[@LINE-2]]:17}:"static_cast<int>("
31+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:26-[[@LINE-3]]:26}:")"
2532

2633
LOG("%d", N::E::One); // expected-warning{{format specifies type 'int' but the argument has type 'N::E'}}
2734
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:13}:"static_cast<int>("
2835
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:22-[[@LINE-2]]:22}:")"
2936

37+
LOG("%s", N::E::One); // expected-warning{{format specifies type 'char *' but the argument has type 'N::E'}}
38+
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:8-[[@LINE-1]]:10}:"%d"
39+
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"static_cast<int>("
40+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:22-[[@LINE-3]]:22}:")"
41+
3042
printf("%d", NEVal); // expected-warning{{format specifies type 'int' but the argument has type 'N::E'}}
3143
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:16-[[@LINE-1]]:16}:"static_cast<int>("
3244
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:21-[[@LINE-2]]:21}:")"
@@ -58,4 +70,8 @@ void a(N::E NEVal, S *SPtr, S &SRef) {
5870
SRef.Type);
5971
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:7-[[@LINE-1]]:7}:"static_cast<int>("
6072
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:16}:")"
73+
74+
printf("%u", FixedE::Two); //expected-warning{{format specifies type 'unsigned int' but the argument has type 'FixedE'}}
75+
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:16-[[@LINE-1]]:16}:"static_cast<uint32_t>("
76+
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:27-[[@LINE-2]]:27}:")"
6177
}

0 commit comments

Comments
 (0)