From: Douglas Gregor Date: Tue, 12 Jan 2010 23:18:54 +0000 (+0000) Subject: Don't emit string-comparison or self-comparison warnings in X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d1e4d9bfd57f643d950eb1373f582bda4dfb8dc7;p=clang Don't emit string-comparison or self-comparison warnings in unevaluated contexts, because they only matter for code that will actually be evaluated at runtime. As part of this, I had to extend PartialDiagnostic to support fix-it hints. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@93266 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/PartialDiagnostic.h b/include/clang/Basic/PartialDiagnostic.h index ae11a755cc..0d970123f7 100644 --- a/include/clang/Basic/PartialDiagnostic.h +++ b/include/clang/Basic/PartialDiagnostic.h @@ -26,7 +26,8 @@ class DeclarationName; class PartialDiagnostic { struct Storage { - Storage() : NumDiagArgs(0), NumDiagRanges(0) { } + Storage() : NumDiagArgs(0), NumDiagRanges(0), NumCodeModificationHints(0) { + } enum { /// MaxArguments - The maximum number of arguments we can hold. We @@ -42,6 +43,10 @@ class PartialDiagnostic { /// NumDiagRanges - This is the number of ranges in the DiagRanges array. unsigned char NumDiagRanges; + /// \brief The number of code modifications hints in the + /// CodeModificationHints array. + unsigned char NumCodeModificationHints; + /// DiagArgumentsKind - This is an array of ArgumentKind::ArgumentKind enum /// values, with one for each argument. This specifies whether the argument /// is in DiagArgumentsStr or in DiagArguments. @@ -56,6 +61,12 @@ class PartialDiagnostic { /// DiagRanges - The list of ranges added to this diagnostic. It currently /// only support 10 ranges, could easily be extended if needed. SourceRange DiagRanges[10]; + + enum { MaxCodeModificationHints = 3 }; + + /// CodeModificationHints - If valid, provides a hint with some code + /// to insert, remove, or modify at a particular position. + CodeModificationHint CodeModificationHints[MaxCodeModificationHints]; }; /// DiagID - The diagnostic ID. @@ -84,6 +95,20 @@ class PartialDiagnostic { DiagStorage->DiagRanges[DiagStorage->NumDiagRanges++] = R; } + void AddCodeModificationHint(const CodeModificationHint &Hint) const { + if (Hint.isNull()) + return; + + if (!DiagStorage) + DiagStorage = new Storage; + + assert(DiagStorage->NumCodeModificationHints < + Storage::MaxCodeModificationHints && + "Too many code modification hints!"); + DiagStorage->CodeModificationHints[DiagStorage->NumCodeModificationHints++] + = Hint; + } + public: PartialDiagnostic(unsigned DiagID) : DiagID(DiagID), DiagStorage(0) { } @@ -130,6 +155,10 @@ public: // Add all ranges. for (unsigned i = 0, e = DiagStorage->NumDiagRanges; i != e; ++i) DB.AddSourceRange(DiagStorage->DiagRanges[i]); + + // Add all code modification hints + for (unsigned i = 0, e = DiagStorage->NumCodeModificationHints; i != e; ++i) + DB.AddCodeModificationHint(DiagStorage->CodeModificationHints[i]); } friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, @@ -165,6 +194,13 @@ public: friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, DeclarationName N); + + friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + const CodeModificationHint &Hint) { + PD.AddCodeModificationHint(Hint); + return PD; + } + }; inline PartialDiagnostic PDiag(unsigned DiagID = 0) { diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 26c2e176cf..c71fd98aa0 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -5196,7 +5196,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, if (DeclRefExpr* DRR = dyn_cast(RHSStripped)) if (DRL->getDecl() == DRR->getDecl() && !isa(DRL->getDecl())) - Diag(Loc, diag::warn_selfcomparison); + DiagRuntimeBehavior(Loc, PDiag(diag::warn_selfcomparison)); if (isa(LHSStripped)) LHSStripped = LHSStripped->IgnoreParenCasts(); @@ -5231,15 +5231,17 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, case BinaryOperator::NE: resultComparison = ") != 0"; break; default: assert(false && "Invalid comparison operator"); } - Diag(Loc, diag::warn_stringcompare) - << isa(literalStringStripped) - << literalString->getSourceRange() - << CodeModificationHint::CreateReplacement(SourceRange(Loc), ", ") - << CodeModificationHint::CreateInsertion(lex->getLocStart(), - "strcmp(") - << CodeModificationHint::CreateInsertion( - PP.getLocForEndOfToken(rex->getLocEnd()), - resultComparison); + + DiagRuntimeBehavior(Loc, + PDiag(diag::warn_stringcompare) + << isa(literalStringStripped) + << literalString->getSourceRange() + << CodeModificationHint::CreateReplacement(SourceRange(Loc), ", ") + << CodeModificationHint::CreateInsertion(lex->getLocStart(), + "strcmp(") + << CodeModificationHint::CreateInsertion( + PP.getLocForEndOfToken(rex->getLocEnd()), + resultComparison)); } } @@ -5503,7 +5505,7 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex, if (DeclRefExpr* DRL = dyn_cast(lex->IgnoreParens())) if (DeclRefExpr* DRR = dyn_cast(rex->IgnoreParens())) if (DRL->getDecl() == DRR->getDecl()) - Diag(Loc, diag::warn_selfcomparison); + DiagRuntimeBehavior(Loc, PDiag(diag::warn_selfcomparison)); } // Check for comparisons of floating point operands using != and ==. diff --git a/test/Sema/exprs.c b/test/Sema/exprs.c index 9059cac22e..9acc63fa41 100644 --- a/test/Sema/exprs.c +++ b/test/Sema/exprs.c @@ -87,6 +87,10 @@ int test12(const char *X) { return X == "foo"; // expected-warning {{comparison against a string literal is unspecified}} } +int test12b(const char *X) { + return sizeof(X == "foo"); // no-warning +} + // rdar://6719156 void test13( void (^P)()) { // expected-error {{blocks support disabled - compile with -fblocks}} diff --git a/test/Sema/self-comparison.c b/test/Sema/self-comparison.c index b2b06c209a..1baba2755f 100644 --- a/test/Sema/self-comparison.c +++ b/test/Sema/self-comparison.c @@ -31,3 +31,8 @@ int compare_enum() { enum { A }; return A == A; // no-warning } + +// Don't complain in unevaluated contexts. +int compare_sizeof(int x) { + return sizeof(x == x); // no-warning +}