Skip to content

Commit 2f6f637

Browse files
committed
Revert "Diagnose incorrect use of scoped enumerations in format strings"
This reverts commit 3632e2f.
1 parent 37d7fe7 commit 2f6f637

File tree

4 files changed

+7
-45
lines changed

4 files changed

+7
-45
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -672,11 +672,6 @@ Bug Fixes in This Version
672672
(`#50244 <https://github.com/llvm/llvm-project/issues/50244>`_).
673673
- Apply ``-fmacro-prefix-map`` to anonymous tags in template arguments
674674
(`#63219 <https://github.com/llvm/llvm-project/issues/63219>`_).
675-
- Clang now properly diagnoses format string mismatches involving scoped
676-
enumeration types. A scoped enumeration type is not promoted to an integer
677-
type by the default argument promotions, and thus this is UB. Clang's
678-
behavior now matches GCC's behavior in C++.
679-
(`#38717 <https://github.com/llvm/llvm-project/issues/38717>`_).
680675
- Fixed a failing assertion when implicitly defining a function within a GNU
681676
statement expression that appears outside of a function block scope. The
682677
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: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11500,18 +11500,12 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
1150011500
ImplicitMatch == ArgType::NoMatchTypeConfusion)
1150111501
Match = ImplicitMatch;
1150211502
assert(Match != ArgType::MatchPromotion);
11503-
// Look through unscoped enums to their underlying type.
11503+
// Look through enums to their underlying type.
1150411504
bool IsEnum = false;
1150511505
bool IsScopedEnum = false;
1150611506
if (auto EnumTy = ExprTy->getAs<EnumType>()) {
11507-
if (EnumTy->isUnscopedEnumerationType()) {
11508-
ExprTy = EnumTy->getDecl()->getIntegerType();
11509-
// This controls whether we're talking about the underlying type or not,
11510-
// which we only want to do when it's an unscoped enum.
11511-
IsEnum = true;
11512-
} else {
11513-
IsScopedEnum = true;
11514-
}
11507+
ExprTy = EnumTy->getDecl()->getIntegerType();
11508+
IsEnum = true;
1151511509
}
1151611510

1151711511
// %C in an Objective-C context prints a unichar, not a wchar_t.

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)