def warn_drv_fine_grained_bitfield_accesses_ignored : Warning<
"option '-ffine-grained-bitfield-accesses' cannot be enabled together with a sanitizer; flag ignored">,
InGroup<OptionIgnored>;
+
+def note_drv_verify_prefix_spelling : Note<
+ "-verify prefixes must start with a letter and contain only alphanumeric"
+ " characters, hyphens, and underscores">;
}
/// prefixes removed.
std::vector<std::string> Remarks;
+ /// The prefixes for comment directives sought by -verify ("expected" by
+ /// default).
+ std::vector<std::string> VerifyPrefixes;
+
public:
// Define accessors/mutators for diagnostic options of enumeration type.
#define DIAGOPT(Name, Bits, Default)
HelpText<"Set the maximum number of source lines to show in a caret diagnostic">;
def fmessage_length : Separate<["-"], "fmessage-length">, MetaVarName<"<N>">,
HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">;
+def verify_EQ : CommaJoined<["-"], "verify=">,
+ MetaVarName<"<prefixes>">,
+ HelpText<"Verify diagnostic output using comment directives that start with"
+ " prefixes in the comma-separated sequence <prefixes>">;
def verify : Flag<["-"], "verify">,
- HelpText<"Verify diagnostic output using comment directives">;
+ HelpText<"Equivalent to -verify=expected">;
def verify_ignore_unexpected : Flag<["-"], "verify-ignore-unexpected">,
HelpText<"Ignore unexpected diagnostic messages">;
def verify_ignore_unexpected_EQ : CommaJoined<["-"], "verify-ignore-unexpected=">,
llvm::sys::Process::StandardErrHasColors());
}
+static bool checkVerifyPrefixes(const std::vector<std::string> &VerifyPrefixes,
+ DiagnosticsEngine *Diags) {
+ bool Success = true;
+ for (const auto &Prefix : VerifyPrefixes) {
+ // Every prefix must start with a letter and contain only alphanumeric
+ // characters, hyphens, and underscores.
+ auto BadChar = std::find_if(Prefix.begin(), Prefix.end(),
+ [](char C){return !isAlphanumeric(C)
+ && C != '-' && C != '_';});
+ if (BadChar != Prefix.end() || !isLetter(Prefix[0])) {
+ Success = false;
+ if (Diags) {
+ Diags->Report(diag::err_drv_invalid_value) << "-verify=" << Prefix;
+ Diags->Report(diag::note_drv_verify_prefix_spelling);
+ }
+ }
+ }
+ return Success;
+}
+
bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
DiagnosticsEngine *Diags,
bool DefaultDiagColor, bool DefaultShowOpt) {
Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info);
Opts.ShowParseableFixits = Args.hasArg(OPT_fdiagnostics_parseable_fixits);
Opts.ShowPresumedLoc = !Args.hasArg(OPT_fno_diagnostics_use_presumed_location);
- Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);
+ Opts.VerifyDiagnostics = Args.hasArg(OPT_verify) || Args.hasArg(OPT_verify_EQ);
+ Opts.VerifyPrefixes = Args.getAllArgValues(OPT_verify_EQ);
+ if (Args.hasArg(OPT_verify))
+ Opts.VerifyPrefixes.push_back("expected");
+ // Keep VerifyPrefixes in its original order for the sake of diagnostics, and
+ // then sort it to prepare for fast lookup using std::binary_search.
+ if (!checkVerifyPrefixes(Opts.VerifyPrefixes, Diags)) {
+ Opts.VerifyDiagnostics = false;
+ Success = false;
+ }
+ else
+ std::sort(Opts.VerifyPrefixes.begin(), Opts.VerifyPrefixes.end());
DiagnosticLevelMask DiagMask = DiagnosticLevelMask::None;
Success &= parseDiagnosticLevelMask("-verify-ignore-unexpected=",
Args.getAllArgValues(OPT_verify_ignore_unexpected_EQ),
return true;
}
- // Return true if string literal is found.
- // When true, P marks begin-position of S in content.
- bool Search(StringRef S, bool EnsureStartOfWord = false) {
+ // Return true if string literal S is matched in content.
+ // When true, P marks begin-position of the match, and calling Advance sets C
+ // to end-position of the match.
+ // If S is the empty string, then search for any letter instead (makes sense
+ // with FinishDirectiveToken=true).
+ // If EnsureStartOfWord, then skip matches that don't start a new word.
+ // If FinishDirectiveToken, then assume the match is the start of a comment
+ // directive for -verify, and extend the match to include the entire first
+ // token of that directive.
+ bool Search(StringRef S, bool EnsureStartOfWord = false,
+ bool FinishDirectiveToken = false) {
do {
- P = std::search(C, End, S.begin(), S.end());
- PEnd = P + S.size();
+ if (!S.empty()) {
+ P = std::search(C, End, S.begin(), S.end());
+ PEnd = P + S.size();
+ }
+ else {
+ P = C;
+ while (P != End && !isLetter(*P))
+ ++P;
+ PEnd = P + 1;
+ }
if (P == End)
break;
- if (!EnsureStartOfWord
- // Check if string literal starts a new word.
- || P == Begin || isWhitespace(P[-1])
- // Or it could be preceded by the start of a comment.
- || (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*')
- && P[-2] == '/'))
- return true;
- // Otherwise, skip and search again.
+ // If not start of word but required, skip and search again.
+ if (EnsureStartOfWord
+ // Check if string literal starts a new word.
+ && !(P == Begin || isWhitespace(P[-1])
+ // Or it could be preceded by the start of a comment.
+ || (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*')
+ && P[-2] == '/')))
+ continue;
+ if (FinishDirectiveToken) {
+ while (PEnd != End && (isAlphanumeric(*PEnd)
+ || *PEnd == '-' || *PEnd == '_'))
+ ++PEnd;
+ // Put back trailing digits and hyphens to be parsed later as a count
+ // or count range. Because -verify prefixes must start with letters,
+ // we know the actual directive we found starts with a letter, so
+ // we won't put back the entire directive word and thus record an empty
+ // string.
+ assert(isLetter(*P) && "-verify prefix must start with a letter");
+ while (isDigit(PEnd[-1]) || PEnd[-1] == '-')
+ --PEnd;
+ }
+ return true;
} while (Advance());
return false;
}
// A single comment may contain multiple directives.
bool FoundDirective = false;
for (ParseHelper PH(S); !PH.Done();) {
- // Search for token: expected
- if (!PH.Search("expected", true))
+ // Search for the initial directive token.
+ // If one prefix, save time by searching only for its directives.
+ // Otherwise, search for any potential directive token and check it later.
+ const auto &Prefixes = Diags.getDiagnosticOptions().VerifyPrefixes;
+ if (!(Prefixes.size() == 1 ? PH.Search(*Prefixes.begin(), true, true)
+ : PH.Search("", true, true)))
break;
PH.Advance();
- // Next token: -
- if (!PH.Next("-"))
- continue;
- PH.Advance();
+ // Default directive kind.
+ bool RegexKind = false;
+ const char* KindStr = "string";
+
+ // Parse the initial directive token in reverse so we can easily determine
+ // its exact actual prefix. If we were to parse it from the front instead,
+ // it would be harder to determine where the prefix ends because there
+ // might be multiple matching -verify prefixes because some might prefix
+ // others.
+ StringRef DToken(PH.P, PH.C - PH.P);
- // Next token: { error | warning | note }
+ // Regex in initial directive token: -re
+ if (DToken.endswith("-re")) {
+ RegexKind = true;
+ KindStr = "regex";
+ DToken = DToken.substr(0, DToken.size()-3);
+ }
+
+ // Type in initial directive token: -{error|warning|note|no-diagnostics}
DirectiveList *DL = nullptr;
- if (PH.Next("error"))
+ bool NoDiag = false;
+ StringRef DType;
+ if (DToken.endswith(DType="-error"))
DL = ED ? &ED->Errors : nullptr;
- else if (PH.Next("warning"))
+ else if (DToken.endswith(DType="-warning"))
DL = ED ? &ED->Warnings : nullptr;
- else if (PH.Next("remark"))
+ else if (DToken.endswith(DType="-remark"))
DL = ED ? &ED->Remarks : nullptr;
- else if (PH.Next("note"))
+ else if (DToken.endswith(DType="-note"))
DL = ED ? &ED->Notes : nullptr;
- else if (PH.Next("no-diagnostics")) {
+ else if (DToken.endswith(DType="-no-diagnostics")) {
+ NoDiag = true;
+ if (RegexKind)
+ continue;
+ }
+ else
+ continue;
+ DToken = DToken.substr(0, DToken.size()-DType.size());
+
+ // What's left in DToken is the actual prefix. That might not be a -verify
+ // prefix even if there is only one -verify prefix (for example, the full
+ // DToken is foo-bar-warning, but foo is the only -verify prefix).
+ if (!std::binary_search(Prefixes.begin(), Prefixes.end(), DToken))
+ continue;
+
+ if (NoDiag) {
if (Status == VerifyDiagnosticConsumer::HasOtherExpectedDirectives)
Diags.Report(Pos, diag::err_verify_invalid_no_diags)
<< /*IsExpectedNoDiagnostics=*/true;
else
Status = VerifyDiagnosticConsumer::HasExpectedNoDiagnostics;
continue;
- } else
- continue;
- PH.Advance();
-
+ }
if (Status == VerifyDiagnosticConsumer::HasExpectedNoDiagnostics) {
Diags.Report(Pos, diag::err_verify_invalid_no_diags)
<< /*IsExpectedNoDiagnostics=*/false;
if (!DL)
return true;
- // Default directive kind.
- bool RegexKind = false;
- const char* KindStr = "string";
-
- // Next optional token: -
- if (PH.Next("-re")) {
- PH.Advance();
- RegexKind = true;
- KindStr = "regex";
- }
-
// Next optional token: @
SourceLocation ExpectedLoc;
bool MatchAnyLine = false;
// Previously, these diagnostics were grouped by diagnostic level with all
// notes last.
//
-// RUN: not %clang_cc1 -O999 -std=bogus %s 2> %t
+// RUN: not %clang_cc1 -O999 -std=bogus -verify=-foo %s 2> %t
// RUN: FileCheck < %t %s
//
-// CHECK: warning: optimization level '-O999' is not supported
+// CHECK: error: invalid value '-foo' in '-verify='
+// CHECK-NEXT: note: -verify prefixes must start with a letter and contain only alphanumeric characters, hyphens, and underscores
+// CHECK-NEXT: warning: optimization level '-O999' is not supported
// CHECK-NEXT: error: invalid value 'bogus' in '-std=bogus'
// CHECK-NEXT: note: use {{.*}} for {{.*}} standard
--- /dev/null
+#if GC
+# define GCONST const
+#else
+# define GCONST
+#endif
+
+// gconst-note@8 {{variable 'glb' declared const here}}
+GCONST int glb = 5;
+
+
+// Check various correct prefix spellings and combinations.
+//
+// RUN: %clang_cc1 -DGC -verify=gconst %s
+// RUN: %clang_cc1 -Wcast-qual -DLC -verify=lconst %s
+// RUN: %clang_cc1 -DSC -verify=expected %s
+// RUN: %clang_cc1 -DSC -verify %s
+// RUN: %clang_cc1 -DSC -verify -verify %s
+// RUN: %clang_cc1 -verify=nconst %s
+// RUN: %clang_cc1 -verify=n-const %s
+// RUN: %clang_cc1 -verify=n_const %s
+// RUN: %clang_cc1 -verify=NConst %s
+// RUN: %clang_cc1 -verify=NConst2 %s
+// RUN: %clang_cc1 -Wcast-qual -DGC -DLC -verify=gconst,lconst %s
+// RUN: %clang_cc1 -Wcast-qual -DGC -DLC -DSC -verify=gconst,lconst,expected %s
+// RUN: %clang_cc1 -Wcast-qual -DGC -DLC -verify=gconst -verify=lconst %s
+// RUN: %clang_cc1 -Wcast-qual -DGC -DLC -DSC -verify=gconst,lconst -verify %s
+// RUN: %clang_cc1 -DGC -DSC -verify -verify=gconst -verify %s
+//
+// Duplicate prefixes.
+// RUN: %clang_cc1 -Wcast-qual -DGC -DLC -verify=gconst,lconst,gconst %s
+// RUN: %clang_cc1 -DGC -verify=gconst -verify=gconst,gconst %s
+// RUN: %clang_cc1 -DSC -verify=expected -verify=expected %s
+// RUN: %clang_cc1 -DSC -verify -verify=expected %s
+//
+// Various tortured cases: multiple directives with different prefixes per
+// line, prefixes used as comments, prefixes prefixing prefixes, and prefixes
+// with special suffixes.
+// RUN: %clang_cc1 -Wcast-qual -DLC -verify=foo %s
+// RUN: %clang_cc1 -DSC -verify=bar %s
+// RUN: %clang_cc1 -Wcast-qual -DLC -DSC -verify=foo,bar %s
+// RUN: %clang_cc1 -Wcast-qual -DLC -DSC -verify=bar,foo %s
+// RUN: %clang_cc1 -DSC -verify=foo-bar %s
+// RUN: %clang_cc1 -Wcast-qual -DLC -verify=bar-foo %s
+// RUN: %clang_cc1 -Wcast-qual -DLC -DSC -verify=foo,foo-bar %s
+// RUN: %clang_cc1 -Wcast-qual -DLC -DSC -verify=foo-bar,foo %s
+// RUN: %clang_cc1 -Wcast-qual -DLC -DSC -verify=bar,bar-foo %s
+// RUN: %clang_cc1 -Wcast-qual -DLC -DSC -verify=bar-foo,bar %s
+// RUN: %clang_cc1 -Wcast-qual -DLC -DSC -verify=foo-bar,bar-foo %s
+// RUN: %clang_cc1 -DSC -verify=foo-warning %s
+// RUN: %clang_cc1 -Wcast-qual -DLC -verify=bar-warning-re %s
+// RUN: %clang_cc1 -Wcast-qual -DLC -DSC -verify=foo,foo-warning %s
+// RUN: %clang_cc1 -Wcast-qual -DLC -DSC -verify=foo-warning,foo %s
+// RUN: %clang_cc1 -Wcast-qual -DLC -DSC -verify=bar,bar-warning-re %s
+// RUN: %clang_cc1 -Wcast-qual -DLC -DSC -verify=bar-warning-re,bar %s
+
+
+// Check invalid prefixes. Check that there's no additional output, which
+// might indicate that diagnostic verification became enabled even though it
+// was requested incorrectly. Check that prefixes are reported in command-line
+// order.
+//
+// RUN: not %clang_cc1 -verify=5abc,-xy,foo,_k -verify='#a,b$' %s 2> %t
+// RUN: FileCheck --check-prefixes=ERR %s < %t
+//
+// ERR-NOT: {{.}}
+// ERR: error: invalid value '5abc' in '-verify='
+// ERR-NEXT: note: -verify prefixes must start with a letter and contain only alphanumeric characters, hyphens, and underscores
+// ERR-NEXT: error: invalid value '-xy' in '-verify='
+// ERR-NEXT: note: -verify prefixes must start with a letter and contain only alphanumeric characters, hyphens, and underscores
+// ERR-NEXT: error: invalid value '_k' in '-verify='
+// ERR-NEXT: note: -verify prefixes must start with a letter and contain only alphanumeric characters, hyphens, and underscores
+// ERR-NEXT: error: invalid value '#a' in '-verify='
+// ERR-NEXT: note: -verify prefixes must start with a letter and contain only alphanumeric characters, hyphens, and underscores
+// ERR-NEXT: error: invalid value 'b$' in '-verify='
+// ERR-NEXT: note: -verify prefixes must start with a letter and contain only alphanumeric characters, hyphens, and underscores
+// ERR-NOT: {{.}}
+
+
+// Check that our test code actually has expected diagnostics when there's no
+// -verify.
+//
+// RUN: not %clang_cc1 -Wcast-qual -DGC -DLC -DSC %s 2> %t
+// RUN: FileCheck --check-prefix=ALL %s < %t
+//
+// ALL: cannot assign to variable 'glb' with const-qualified type 'const int'
+// ALL: variable 'glb' declared const here
+// ALL: cast from 'const int *' to 'int *' drops const qualifier
+// ALL: initializing 'int *' with an expression of type 'const int *' discards qualifiers
+
+
+#if LC
+# define LCONST const
+#else
+# define LCONST
+#endif
+
+#if SC
+# define SCONST const
+#else
+# define SCONST
+#endif
+
+void foo() {
+ LCONST int loc = 5;
+ SCONST static int sta = 5;
+ // We don't actually expect 1-2 occurrences of this error. We're just
+ // checking the parsing.
+ glb = 6; // gconst-error1-2 {{cannot assign to variable 'glb' with const-qualified type 'const int'}}
+ *(int*)(&loc) = 6; // lconst-warning {{cast from 'const int *' to 'int *' drops const qualifier}}
+ ; // Code, comments, and many directives with different prefixes per line, including cases where some prefixes (foo and bar) prefix others (such as foo-bar and bar-foo), such that some prefixes appear as normal comments and some have special suffixes (-warning and -re): foo-warning@-1 {{cast from 'const int *' to 'int *' drops const qualifier}} foo-bar-warning@+1 {{initializing 'int *' with an expression of type 'const int *' discards qualifiers}} foo-warning-warning@+1 {{initializing 'int *' with an expression of type 'const int *' discards qualifiers}} bar-warning-re-warning@-1 {{cast from 'const int *' to 'int *' drops const qualifier}} bar-foo-warning@-1 {{cast from 'const int *' to 'int *' drops const qualifier}} bar-warning@+1 {{initializing 'int *' with an expression of type 'const int *' discards qualifiers}}
+ int *p = &sta; // expected-warning {{initializing 'int *' with an expression of type 'const int *' discards qualifiers}}
+}
+
+// nconst-no-diagnostics
+// n-const-no-diagnostics
+// n_const-no-diagnostics
+// NConst-no-diagnostics
+// NConst2-no-diagnostics
-// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -verify %s
-// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -verify %s
-// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -Wno-tautological-unsigned-enum-zero-compare -verify %s
+// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only \
+// RUN: -verify=unsigned,unsigned-signed %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only \
+// RUN: -verify=unsigned-signed %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only \
+// RUN: -Wno-tautological-unsigned-enum-zero-compare \
+// RUN: -verify=silence %s
// Okay, this is where it gets complicated.
// Then default enum sigdness is target-specific.
enum B { B_a = -1 };
enum B b;
-#ifdef UNSIGNED
- if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
- return 0;
- if (0 >= a)
- return 0;
- if (a > 0)
- return 0;
- if (0 <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
- return 0;
- if (a <= 0)
- return 0;
- if (0 > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
- return 0;
- if (a >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
- return 0;
- if (0 < a)
- return 0;
-
- if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
- return 0;
- if (0U >= a)
- return 0;
- if (a > 0U)
- return 0;
- if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
- return 0;
- if (a <= 0U)
- return 0;
- if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
- return 0;
- if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
- return 0;
- if (0U < a)
- return 0;
-
- if (b < 0)
- return 0;
- if (0 >= b)
- return 0;
- if (b > 0)
- return 0;
- if (0 <= b)
- return 0;
- if (b <= 0)
- return 0;
- if (0 > b)
- return 0;
- if (b >= 0)
- return 0;
- if (0 < b)
- return 0;
-
- if (b < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
- return 0;
- if (0U >= b)
- return 0;
- if (b > 0U)
- return 0;
- if (0U <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
- return 0;
- if (b <= 0U)
- return 0;
- if (0U > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
- return 0;
- if (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
- return 0;
- if (0U < b)
- return 0;
-#elif defined(SIGNED)
- if (a < 0)
- return 0;
- if (0 >= a)
- return 0;
- if (a > 0)
- return 0;
- if (0 <= a)
- return 0;
- if (a <= 0)
- return 0;
- if (0 > a)
- return 0;
- if (a >= 0)
- return 0;
- if (0 < a)
- return 0;
-
- if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
- return 0;
- if (0U >= a)
- return 0;
- if (a > 0U)
- return 0;
- if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
- return 0;
- if (a <= 0U)
- return 0;
- if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
- return 0;
- if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
- return 0;
- if (0U < a)
- return 0;
-
- if (b < 0)
- return 0;
- if (0 >= b)
- return 0;
- if (b > 0)
- return 0;
- if (0 <= b)
- return 0;
- if (b <= 0)
- return 0;
- if (0 > b)
- return 0;
- if (b >= 0)
- return 0;
- if (0 < b)
- return 0;
-
- if (b < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
- return 0;
- if (0U >= b)
- return 0;
- if (b > 0U)
- return 0;
- if (0U <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
- return 0;
- if (b <= 0U)
- return 0;
- if (0U > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
- return 0;
- if (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
- return 0;
- if (0U < b)
- return 0;
-#else
- // expected-no-diagnostics
+ // silence-no-diagnostics
- if (a < 0)
+ if (a < 0) // unsigned-warning {{comparison of unsigned enum expression < 0 is always false}}
return 0;
if (0 >= a)
return 0;
if (a > 0)
return 0;
- if (0 <= a)
+ if (0 <= a) // unsigned-warning {{comparison of 0 <= unsigned enum expression is always true}}
return 0;
if (a <= 0)
return 0;
- if (0 > a)
+ if (0 > a) // unsigned-warning {{comparison of 0 > unsigned enum expression is always false}}
return 0;
- if (a >= 0)
+ if (a >= 0) // unsigned-warning {{comparison of unsigned enum expression >= 0 is always true}}
return 0;
if (0 < a)
return 0;
- if (a < 0U)
+ if (a < 0U) // unsigned-signed-warning {{comparison of unsigned enum expression < 0 is always false}}
return 0;
if (0U >= a)
return 0;
if (a > 0U)
return 0;
- if (0U <= a)
+ if (0U <= a) // unsigned-signed-warning {{comparison of 0 <= unsigned enum expression is always true}}
return 0;
if (a <= 0U)
return 0;
- if (0U > a)
+ if (0U > a) // unsigned-signed-warning {{comparison of 0 > unsigned enum expression is always false}}
return 0;
- if (a >= 0U)
+ if (a >= 0U) // unsigned-signed-warning {{comparison of unsigned enum expression >= 0 is always true}}
return 0;
if (0U < a)
return 0;
if (0 < b)
return 0;
- if (b < 0U)
+ if (b < 0U) // unsigned-signed-warning {{comparison of unsigned enum expression < 0 is always false}}
return 0;
if (0U >= b)
return 0;
if (b > 0U)
return 0;
- if (0U <= b)
+ if (0U <= b) // unsigned-signed-warning {{comparison of 0 <= unsigned enum expression is always true}}
return 0;
if (b <= 0U)
return 0;
- if (0U > b)
+ if (0U > b) // unsigned-signed-warning {{comparison of 0 > unsigned enum expression is always false}}
return 0;
- if (b >= 0U)
+ if (b >= 0U) // unsigned-signed-warning {{comparison of unsigned enum expression >= 0 is always true}}
return 0;
if (0U < b)
return 0;
-#endif
if (a == 0)
return 0;
-// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -verify %s
-// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -verify %s
-// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-win32 -fsyntax-only -DSILENCE -Wno-tautological-unsigned-enum-zero-compare -verify %s
+// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-linux-gnu -fsyntax-only \
+// RUN: -verify=unsigned,unsigned-signed %s
+// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-win32 -fsyntax-only \
+// RUN: -verify=unsigned-signed %s
+// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-win32 -fsyntax-only \
+// RUN: -Wno-tautological-unsigned-enum-zero-compare \
+// RUN: -verify=silence %s
+
+// silence-no-diagnostics
int main() {
// On Windows, all enumerations have a fixed underlying type, which is 'int'
enum C : signed { C_foo = 0, C_bar, };
enum C c;
-#ifdef UNSIGNED
- if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+ if (a < 0) // unsigned-warning {{comparison of unsigned enum expression < 0 is always false}}
return 0;
if (0 >= a)
return 0;
if (a > 0)
return 0;
- if (0 <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+ if (0 <= a) // unsigned-warning {{comparison of 0 <= unsigned enum expression is always true}}
return 0;
if (a <= 0)
return 0;
- if (0 > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+ if (0 > a) // unsigned-warning {{comparison of 0 > unsigned enum expression is always false}}
return 0;
- if (a >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+ if (a >= 0) // unsigned-warning {{comparison of unsigned enum expression >= 0 is always true}}
return 0;
if (0 < a)
return 0;
- if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+ // FIXME: As below, the issue here is that the enumeration is promoted to
+ // unsigned.
+ if (a < 0U) // unsigned-signed-warning {{comparison of unsigned enum expression < 0 is always false}}
return 0;
if (0U >= a)
return 0;
if (a > 0U)
return 0;
- if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+ if (0U <= a) // unsigned-signed-warning {{comparison of 0 <= unsigned enum expression is always true}}
return 0;
if (a <= 0U)
return 0;
- if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+ if (0U > a) // unsigned-signed-warning {{comparison of 0 > unsigned enum expression is always false}}
return 0;
- if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+ if (a >= 0U) // unsigned-signed-warning {{comparison of unsigned enum expression >= 0 is always true}}
return 0;
if (0U < a)
return 0;
- if (b < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+ if (b < 0) // unsigned-signed-warning {{comparison of unsigned enum expression < 0 is always false}}
return 0;
if (0 >= b)
return 0;
if (b > 0)
return 0;
- if (0 <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+ if (0 <= b) // unsigned-signed-warning {{comparison of 0 <= unsigned enum expression is always true}}
return 0;
if (b <= 0)
return 0;
- if (0 > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+ if (0 > b) // unsigned-signed-warning {{comparison of 0 > unsigned enum expression is always false}}
return 0;
- if (b >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+ if (b >= 0) // unsigned-signed-warning {{comparison of unsigned enum expression >= 0 is always true}}
return 0;
if (0 < b)
return 0;
- if (b < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+ if (b < 0U) // unsigned-signed-warning {{comparison of unsigned enum expression < 0 is always false}}
return 0;
if (0U >= b)
return 0;
if (b > 0U)
return 0;
- if (0U <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+ if (0U <= b) // unsigned-signed-warning {{comparison of 0 <= unsigned enum expression is always true}}
return 0;
if (b <= 0U)
return 0;
- if (0U > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+ if (0U > b) // unsigned-signed-warning {{comparison of 0 > unsigned enum expression is always false}}
return 0;
- if (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+ if (b >= 0U) // unsigned-signed-warning {{comparison of unsigned enum expression >= 0 is always true}}
return 0;
if (0U < b)
return 0;
// FIXME: These diagnostics are terrible. The issue here is that the signed
// enumeration value was promoted to an unsigned type.
- if (c < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
- return 0;
- if (0U >= c)
- return 0;
- if (c > 0U)
- return 0;
- if (0U <= c) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
- return 0;
- if (c <= 0U)
- return 0;
- if (0U > c) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
- return 0;
- if (c >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
- return 0;
- if (0U < c)
- return 0;
-#elif defined(SIGNED)
- if (a < 0)
- return 0;
- if (0 >= a)
- return 0;
- if (a > 0)
- return 0;
- if (0 <= a)
- return 0;
- if (a <= 0)
- return 0;
- if (0 > a)
- return 0;
- if (a >= 0)
- return 0;
- if (0 < a)
- return 0;
-
- // FIXME: As above, the issue here is that the enumeration is promoted to
- // unsigned.
- if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
- return 0;
- if (0U >= a)
- return 0;
- if (a > 0U)
- return 0;
- if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
- return 0;
- if (a <= 0U)
- return 0;
- if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
- return 0;
- if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
- return 0;
- if (0U < a)
- return 0;
-
- if (b < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
- return 0;
- if (0 >= b)
- return 0;
- if (b > 0)
- return 0;
- if (0 <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
- return 0;
- if (b <= 0)
- return 0;
- if (0 > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
- return 0;
- if (b >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
- return 0;
- if (0 < b)
- return 0;
-
- if (b < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
- return 0;
- if (0U >= b)
- return 0;
- if (b > 0U)
- return 0;
- if (0U <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
- return 0;
- if (b <= 0U)
- return 0;
- if (0U > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
- return 0;
- if (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
- return 0;
- if (0U < b)
- return 0;
-
- if (c < 0)
- return 0;
- if (0 >= c)
- return 0;
- if (c > 0)
- return 0;
- if (0 <= c)
- return 0;
- if (c <= 0)
- return 0;
- if (0 > c)
- return 0;
- if (c >= 0)
- return 0;
- if (0 < c)
- return 0;
-
- if (c < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+ if (c < 0U) // unsigned-signed-warning {{comparison of unsigned enum expression < 0 is always false}}
return 0;
if (0U >= c)
return 0;
if (c > 0U)
return 0;
- if (0U <= c) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+ if (0U <= c) // unsigned-signed-warning {{comparison of 0 <= unsigned enum expression is always true}}
return 0;
if (c <= 0U)
return 0;
- if (0U > c) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+ if (0U > c) // unsigned-signed-warning {{comparison of 0 > unsigned enum expression is always false}}
return 0;
- if (c >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+ if (c >= 0U) // unsigned-signed-warning {{comparison of unsigned enum expression >= 0 is always true}}
return 0;
if (0U < c)
return 0;
-#else
- // expected-no-diagnostics
- if (a < 0)
- return 0;
- if (0 >= a)
- return 0;
- if (a > 0)
- return 0;
- if (0 <= a)
- return 0;
- if (a <= 0)
- return 0;
- if (0 > a)
- return 0;
- if (a >= 0)
- return 0;
- if (0 < a)
- return 0;
-
- if (a < 0U)
- return 0;
- if (0U >= a)
- return 0;
- if (a > 0U)
- return 0;
- if (0U <= a)
- return 0;
- if (a <= 0U)
- return 0;
- if (0U > a)
- return 0;
- if (a >= 0U)
- return 0;
- if (0U < a)
- return 0;
-
- if (b < 0)
- return 0;
- if (0 >= b)
- return 0;
- if (b > 0)
- return 0;
- if (0 <= b)
- return 0;
- if (b <= 0)
- return 0;
- if (0 > b)
- return 0;
- if (b >= 0)
- return 0;
- if (0 < b)
- return 0;
-
- if (b < 0U)
- return 0;
- if (0U >= b)
- return 0;
- if (b > 0U)
- return 0;
- if (0U <= b)
- return 0;
- if (b <= 0U)
- return 0;
- if (0U > b)
- return 0;
- if (b >= 0U)
- return 0;
- if (0U < b)
- return 0;
-
- if (c < 0)
- return 0;
- if (0 >= c)
- return 0;
- if (c > 0)
- return 0;
- if (0 <= c)
- return 0;
- if (c <= 0)
- return 0;
- if (0 > c)
- return 0;
- if (c >= 0)
- return 0;
- if (0 < c)
- return 0;
-
- if (c < 0U)
- return 0;
- if (0U >= c)
- return 0;
- if (c > 0U)
- return 0;
- if (0U <= c)
- return 0;
- if (c <= 0U)
- return 0;
- if (0U > c)
- return 0;
- if (c >= 0U)
- return 0;
- if (0U < c)
- return 0;
-#endif
return 1;
}
enum A a;
// used to crash in llvm::APSInt::getMaxValue()
-#ifndef SILENCE
- if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
-#else
- if (a > 0)
-#endif
+ if (a < 0) // unsigned-signed-warning {{comparison of unsigned enum expression < 0 is always false}}
return 0;
return 1;
-// RUN: %clang_cc1 -fsyntax-only -DTEST -verify %s
-// RUN: %clang_cc1 -fsyntax-only -Wno-tautological-unsigned-zero-compare -verify %s
-// RUN: %clang_cc1 -fsyntax-only -DTEST -verify -x c++ %s
-// RUN: %clang_cc1 -fsyntax-only -Wno-tautological-unsigned-zero-compare -verify -x c++ %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-tautological-unsigned-zero-compare -verify=silence %s
+// RUN: %clang_cc1 -fsyntax-only -verify -x c++ %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-tautological-unsigned-zero-compare -verify=silence -x c++ %s
unsigned uvalue(void);
signed int svalue(void);
void TFunc() {
// Make sure that we do warn for normal variables in template functions !
unsigned char c = svalue();
-#ifdef TEST
if (c < 0) // expected-warning {{comparison of unsigned expression < 0 is always false}}
return;
-#else
- if (c < 0)
- return;
-#endif
if (c < macro(0))
return;
unsigned un = uvalue();
-#ifdef TEST
+ // silence-no-diagnostics
+
if (un == 0)
return 0;
if (un != 0)
return 0;
if (0UL >= un)
return 0;
-#else
-// expected-no-diagnostics
- if (un == 0)
- return 0;
- if (un != 0)
- return 0;
- if (un < 0)
- return 0;
- if (un <= 0)
- return 0;
- if (un > 0)
- return 0;
- if (un >= 0)
- return 0;
-
- if (0 == un)
- return 0;
- if (0 != un)
- return 0;
- if (0 < un)
- return 0;
- if (0 <= un)
- return 0;
- if (0 > un)
- return 0;
- if (0 >= un)
- return 0;
-
- if (un == 0UL)
- return 0;
- if (un != 0UL)
- return 0;
- if (un < 0UL)
- return 0;
- if (un <= 0UL)
- return 0;
- if (un > 0UL)
- return 0;
- if (un >= 0UL)
- return 0;
-
- if (0UL == un)
- return 0;
- if (0UL != un)
- return 0;
- if (0UL < un)
- return 0;
- if (0UL <= un)
- return 0;
- if (0UL > un)
- return 0;
- if (0UL >= un)
- return 0;
-#endif
signed int a = svalue();
-#ifdef TEST
if (a == 0)
return 0;
if (a != 0)
return 0;
if (0UL >= a)
return 0;
-#else
-// expected-no-diagnostics
- if (a == 0)
- return 0;
- if (a != 0)
- return 0;
- if (a < 0)
- return 0;
- if (a <= 0)
- return 0;
- if (a > 0)
- return 0;
- if (a >= 0)
- return 0;
-
- if (0 == a)
- return 0;
- if (0 != a)
- return 0;
- if (0 < a)
- return 0;
- if (0 <= a)
- return 0;
- if (0 > a)
- return 0;
- if (0 >= a)
- return 0;
-
- if (a == 0UL)
- return 0;
- if (a != 0UL)
- return 0;
- if (a < 0UL)
- return 0;
- if (a <= 0UL)
- return 0;
- if (a > 0UL)
- return 0;
- if (a >= 0UL)
- return 0;
-
- if (0UL == a)
- return 0;
- if (0UL != a)
- return 0;
- if (0UL < a)
- return 0;
- if (0UL <= a)
- return 0;
- if (0UL > a)
- return 0;
- if (0UL >= a)
- return 0;
-#endif
float fl = 0;