diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Sema/SemaChecking.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/Sema/SemaChecking.cpp | 25 |
1 files changed, 12 insertions, 13 deletions
diff --git a/contrib/llvm-project/clang/lib/Sema/SemaChecking.cpp b/contrib/llvm-project/clang/lib/Sema/SemaChecking.cpp index 8626fc6ea16f..a94f009f3fa6 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaChecking.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaChecking.cpp @@ -11166,12 +11166,15 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, ImplicitMatch == ArgType::NoMatchTypeConfusion) Match = ImplicitMatch; assert(Match != ArgType::MatchPromotion); + // Look through unscoped enums to their underlying type. bool IsEnum = false; bool IsScopedEnum = false; + QualType IntendedTy = ExprTy; if (auto EnumTy = ExprTy->getAs<EnumType>()) { + IntendedTy = EnumTy->getDecl()->getIntegerType(); if (EnumTy->isUnscopedEnumerationType()) { - ExprTy = EnumTy->getDecl()->getIntegerType(); + ExprTy = IntendedTy; // This controls whether we're talking about the underlying type or not, // which we only want to do when it's an unscoped enum. IsEnum = true; @@ -11183,7 +11186,6 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, // %C in an Objective-C context prints a unichar, not a wchar_t. // If the argument is an integer of some kind, believe the %C and suggest // a cast instead of changing the conversion specifier. - QualType IntendedTy = ExprTy; if (isObjCContext() && FS.getConversionSpecifier().getKind() == ConversionSpecifier::CArg) { if (ExprTy->isIntegralOrUnscopedEnumerationType() && @@ -11219,8 +11221,10 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, std::tie(CastTy, CastTyName) = shouldNotPrintDirectly(S.Context, IntendedTy, E); if (!CastTy.isNull()) { // %zi/%zu and %td/%tu are OK to use for NSInteger/NSUInteger of type int - // (long in ASTContext). Only complain to pedants. - if ((CastTyName == "NSInteger" || CastTyName == "NSUInteger") && + // (long in ASTContext). Only complain to pedants or when they're the + // underlying type of a scoped enum (which always needs a cast). + if (!IsScopedEnum && + (CastTyName == "NSInteger" || CastTyName == "NSUInteger") && (AT.isSizeT() || AT.isPtrdiffT()) && AT.matchesType(S.Context, CastTy)) Match = ArgType::NoMatchPedantic; @@ -11275,20 +11279,15 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, // should be printed as 'long' for 64-bit compatibility.) // Rather than emitting a normal format/argument mismatch, we want to // add a cast to the recommended type (and correct the format string - // if necessary). + // if necessary). We should also do so for scoped enumerations. SmallString<16> CastBuf; llvm::raw_svector_ostream CastFix(CastBuf); CastFix << (S.LangOpts.CPlusPlus ? "static_cast<" : "("); - if (IsScopedEnum) { - CastFix << AT.getRepresentativeType(S.Context).getAsString( - S.Context.getPrintingPolicy()); - } else { - IntendedTy.print(CastFix, S.Context.getPrintingPolicy()); - } + IntendedTy.print(CastFix, S.Context.getPrintingPolicy()); CastFix << (S.LangOpts.CPlusPlus ? ">" : ")"); SmallVector<FixItHint,4> Hints; - if ((!AT.matchesType(S.Context, IntendedTy) && !IsScopedEnum) || + if (AT.matchesType(S.Context, IntendedTy) != ArgType::Match || ShouldNotPrintDirectly) Hints.push_back(FixItHint::CreateReplacement(SpecRange, os.str())); @@ -11316,7 +11315,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, Hints.push_back(FixItHint::CreateInsertion(After, ")")); } - if (ShouldNotPrintDirectly) { + if (ShouldNotPrintDirectly && !IsScopedEnum) { // The expression has a type that should not be printed directly. // We extract the name from the typedef because we don't want to show // the underlying type in the diagnostic. |