Skip to content

Commit a8b8b0e

Browse files
Merge pull request #8638 from apple/revert-wformat-scoped-enum
Revert -Wformat for scoped enums
2 parents 3140c4b + 2f6f637 commit a8b8b0e

File tree

6 files changed

+25
-111
lines changed

6 files changed

+25
-111
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -497,8 +497,10 @@ Improvements to Clang's diagnostics
497497
- ``-Wformat`` cast fix-its will now suggest ``static_cast`` instead of C-style casts
498498
for C++ code.
499499
- ``-Wformat`` will no longer suggest a no-op fix-it for fixing scoped enum format
500-
warnings. Instead, it will suggest casting the enum object based on its
501-
underlying type.
500+
warnings. Instead, it will suggest casting the enum object to the type specified
501+
in the format string.
502+
- Clang contexpr evaluator now displays notes as well as an error when a constructor
503+
of a base class is not called in the constructor of its derived class.
502504

503505
- ``-Wzero-as-null-pointer-constant`` diagnostic is no longer emitted when using ``__null``
504506
(or, more commonly, ``NULL`` when the platform defines it as ``__null``) to be more consistent
@@ -670,11 +672,6 @@ Bug Fixes in This Version
670672
(`#50244 <https://github.com/llvm/llvm-project/issues/50244>`_).
671673
- Apply ``-fmacro-prefix-map`` to anonymous tags in template arguments
672674
(`#63219 <https://github.com/llvm/llvm-project/issues/63219>`_).
673-
- Clang now properly diagnoses format string mismatches involving scoped
674-
enumeration types. A scoped enumeration type is not promoted to an integer
675-
type by the default argument promotions, and thus this is UB. Clang's
676-
behavior now matches GCC's behavior in C++.
677-
(`#38717 <https://github.com/llvm/llvm-project/issues/38717>`_).
678675
- Fixed a failing assertion when implicitly defining a function within a GNU
679676
statement expression that appears outside of a function block scope. The
680677
assertion was benign outside of asserts builds and would only fire in C.

clang/lib/AST/FormatString.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -351,12 +351,10 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const {
351351
case AnyCharTy: {
352352
if (const auto *ETy = argTy->getAs<EnumType>()) {
353353
// If the enum is incomplete we know nothing about the underlying type.
354-
// Assume that it's 'int'. Do not use the underlying type for a scoped
355-
// enumeration.
354+
// Assume that it's 'int'.
356355
if (!ETy->getDecl()->isComplete())
357356
return NoMatch;
358-
if (ETy->isUnscopedEnumerationType())
359-
argTy = ETy->getDecl()->getIntegerType();
357+
argTy = ETy->getDecl()->getIntegerType();
360358
}
361359

362360
if (const auto *BT = argTy->getAs<BuiltinType>()) {
@@ -393,11 +391,10 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const {
393391
case SpecificTy: {
394392
if (const EnumType *ETy = argTy->getAs<EnumType>()) {
395393
// If the enum is incomplete we know nothing about the underlying type.
396-
// Assume that it's 'int'. Do not use the underlying type for a scoped
397-
// enumeration as that needs an exact match.
394+
// Assume that it's 'int'.
398395
if (!ETy->getDecl()->isComplete())
399396
argTy = C.IntTy;
400-
else if (ETy->isUnscopedEnumerationType())
397+
else
401398
argTy = ETy->getDecl()->getIntegerType();
402399
}
403400
argTy = C.getCanonicalType(argTy).getUnqualifiedType();

clang/lib/Sema/SemaChecking.cpp

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11500,26 +11500,18 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
1150011500
ImplicitMatch == ArgType::NoMatchTypeConfusion)
1150111501
Match = ImplicitMatch;
1150211502
assert(Match != ArgType::MatchPromotion);
11503-
11504-
// Look through unscoped enums to their underlying type.
11503+
// Look through enums to their underlying type.
1150511504
bool IsEnum = false;
1150611505
bool IsScopedEnum = false;
11507-
QualType IntendedTy = ExprTy;
1150811506
if (auto EnumTy = ExprTy->getAs<EnumType>()) {
11509-
IntendedTy = EnumTy->getDecl()->getIntegerType();
11510-
if (EnumTy->isUnscopedEnumerationType()) {
11511-
ExprTy = IntendedTy;
11512-
// This controls whether we're talking about the underlying type or not,
11513-
// which we only want to do when it's an unscoped enum.
11514-
IsEnum = true;
11515-
} else {
11516-
IsScopedEnum = true;
11517-
}
11507+
ExprTy = EnumTy->getDecl()->getIntegerType();
11508+
IsEnum = true;
1151811509
}
1151911510

1152011511
// %C in an Objective-C context prints a unichar, not a wchar_t.
1152111512
// If the argument is an integer of some kind, believe the %C and suggest
1152211513
// a cast instead of changing the conversion specifier.
11514+
QualType IntendedTy = ExprTy;
1152311515
if (isObjCContext() &&
1152411516
FS.getConversionSpecifier().getKind() == ConversionSpecifier::CArg) {
1152511517
if (ExprTy->isIntegralOrUnscopedEnumerationType() &&
@@ -11555,10 +11547,8 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
1155511547
std::tie(CastTy, CastTyName) = shouldNotPrintDirectly(S.Context, IntendedTy, E);
1155611548
if (!CastTy.isNull()) {
1155711549
// %zi/%zu and %td/%tu are OK to use for NSInteger/NSUInteger of type int
11558-
// (long in ASTContext). Only complain to pedants or when they're the
11559-
// underlying type of a scoped enum (which always needs a cast).
11560-
if (!IsScopedEnum &&
11561-
(CastTyName == "NSInteger" || CastTyName == "NSUInteger") &&
11550+
// (long in ASTContext). Only complain to pedants.
11551+
if ((CastTyName == "NSInteger" || CastTyName == "NSUInteger") &&
1156211552
(AT.isSizeT() || AT.isPtrdiffT()) &&
1156311553
AT.matchesType(S.Context, CastTy))
1156411554
Match = ArgType::NoMatchPedantic;
@@ -11613,15 +11603,20 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
1161311603
// should be printed as 'long' for 64-bit compatibility.)
1161411604
// Rather than emitting a normal format/argument mismatch, we want to
1161511605
// add a cast to the recommended type (and correct the format string
11616-
// if necessary). We should also do so for scoped enumerations.
11606+
// if necessary).
1161711607
SmallString<16> CastBuf;
1161811608
llvm::raw_svector_ostream CastFix(CastBuf);
1161911609
CastFix << (S.LangOpts.CPlusPlus ? "static_cast<" : "(");
11620-
IntendedTy.print(CastFix, S.Context.getPrintingPolicy());
11610+
if (IsScopedEnum) {
11611+
CastFix << AT.getRepresentativeType(S.Context).getAsString(
11612+
S.Context.getPrintingPolicy());
11613+
} else {
11614+
IntendedTy.print(CastFix, S.Context.getPrintingPolicy());
11615+
}
1162111616
CastFix << (S.LangOpts.CPlusPlus ? ">" : ")");
1162211617

1162311618
SmallVector<FixItHint,4> Hints;
11624-
if (AT.matchesType(S.Context, IntendedTy) != ArgType::Match ||
11619+
if ((!AT.matchesType(S.Context, IntendedTy) && !IsScopedEnum) ||
1162511620
ShouldNotPrintDirectly)
1162611621
Hints.push_back(FixItHint::CreateReplacement(SpecRange, os.str()));
1162711622

@@ -11649,7 +11644,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
1164911644
Hints.push_back(FixItHint::CreateInsertion(After, ")"));
1165011645
}
1165111646

11652-
if (ShouldNotPrintDirectly && !IsScopedEnum) {
11647+
if (ShouldNotPrintDirectly) {
1165311648
// The expression has a type that should not be printed directly.
1165411649
// We extract the name from the typedef because we don't want to show
1165511650
// the underlying type in the diagnostic.

clang/test/FixIt/format-darwin-enum-class.cpp

Lines changed: 0 additions & 35 deletions
This file was deleted.

clang/test/FixIt/format.cpp

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

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

2320
printf("%hd", N::E::One); // expected-warning{{format specifies type 'short' but the argument has type 'N::E'}}
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}:")"
21+
// CHECK: "static_cast<short>("
2722

2823
printf("%hu", N::E::One); // expected-warning{{format specifies type 'unsigned short' but the argument has type 'N::E'}}
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}:")"
24+
// CHECK: "static_cast<unsigned short>("
3225

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

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-
4230
printf("%d", NEVal); // expected-warning{{format specifies type 'int' but the argument has type 'N::E'}}
4331
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:16-[[@LINE-1]]:16}:"static_cast<int>("
4432
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:21-[[@LINE-2]]:21}:")"
@@ -70,8 +58,4 @@ void a(N::E NEVal, S *SPtr, S &SRef) {
7058
SRef.Type);
7159
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:7-[[@LINE-1]]:7}:"static_cast<int>("
7260
// 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}:")"
7761
}

clang/test/SemaCXX/format-strings.cpp

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -213,28 +213,4 @@ void f() {
213213

214214

215215
}
216-
217-
namespace ScopedEnumerations {
218-
enum class Scoped1 { One };
219-
enum class Scoped2 : unsigned short { Two };
220-
221-
void f(Scoped1 S1, Scoped2 S2) {
222-
printf("%hhd", S1); // expected-warning {{format specifies type 'char' but the argument has type 'Scoped1'}}
223-
printf("%hd", S1); // expected-warning {{format specifies type 'short' but the argument has type 'Scoped1'}}
224-
printf("%d", S1); // expected-warning {{format specifies type 'int' but the argument has type 'Scoped1'}}
225-
226-
printf("%hhd", S2); // expected-warning {{format specifies type 'char' but the argument has type 'Scoped2'}}
227-
printf("%hd", S2); // expected-warning {{format specifies type 'short' but the argument has type 'Scoped2'}}
228-
printf("%d", S2); // expected-warning {{format specifies type 'int' but the argument has type 'Scoped2'}}
229-
230-
scanf("%hhd", &S1); // expected-warning {{format specifies type 'char *' but the argument has type 'Scoped1 *'}}
231-
scanf("%hd", &S1); // expected-warning {{format specifies type 'short *' but the argument has type 'Scoped1 *'}}
232-
scanf("%d", &S1); // expected-warning {{format specifies type 'int *' but the argument has type 'Scoped1 *'}}
233-
234-
scanf("%hhd", &S2); // expected-warning {{format specifies type 'char *' but the argument has type 'Scoped2 *'}}
235-
scanf("%hd", &S2); // expected-warning {{format specifies type 'short *' but the argument has type 'Scoped2 *'}}
236-
scanf("%d", &S2); // expected-warning {{format specifies type 'int *' but the argument has type 'Scoped2 *'}}
237-
}
238-
}
239-
240216
#endif

0 commit comments

Comments
 (0)