diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -173,7 +173,7 @@ "%2">; def err_verify_invalid_no_diags : Error< "%select{expected|'expected-no-diagnostics'}0 directive cannot follow " - "%select{'expected-no-diagnostics' directive|other expected directives}0">; + "%select{'expected-no-diagnostics' directive|directives that expect diagnostics}0">; def err_verify_no_directives : Error< "no expected directives found: consider use of 'expected-no-diagnostics'">; def err_verify_nonconst_addrspace : Error< diff --git a/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h b/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h --- a/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h +++ b/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h @@ -183,6 +183,30 @@ /// // expected-no-diagnostics /// \endcode /// +/// Additionally, you can use: +/// +/// \code +/// // expected-maybe-no-diagnostics +/// \endcode +/// +/// The "expected-no-diagnostics" and "expected-maybe-no-diagnostics" +/// directives have the same behavior except "expected-no-diagnostics" adds the +/// restriction that no diagnostics can be specified by other "expected-*" +/// directives. If both "expected-no-diagnostics" and +/// "expected-maybe-no-diagnostics" are specified, +/// "expected-maybe-no-diagnostics" is ignored. +/// +/// Because of its strictness, "expected-no-diagnostics" is almost always preferred, +/// but there are scenarios where "expected-maybe-no-diagnostics" is convenient. +/// For example, "expected-maybe-no-diagnostics" is useful for DR conformance tests +/// where dozens of distinct test cases are within the same physical file but use +/// the 'split-file' utility to split individual test cases into logical files +/// at runtime. In that case, a header file containing "expected-maybe-no-diagnostics" +/// can be force included into each RUN line in the physical file. The tests that +/// expect diagostics continue to pass or fail depending on whether the correct +/// diagnostics are emitted, but they do not fail automatically as they would +/// if "expected-no-diagnostics" and "expected-*" were combined within the same +/// test. class VerifyDiagnosticConsumer: public DiagnosticConsumer, public CommentHandler { public: @@ -251,7 +275,8 @@ HasNoDirectives, HasNoDirectivesReported, HasExpectedNoDiagnostics, - HasOtherExpectedDirectives + HasOtherExpectedDirectives, + HasExpectedMaybeNoDiagnostics, }; class MarkerTracker; diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp --- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -453,6 +453,7 @@ // Type in initial directive token: -{error|warning|note|no-diagnostics} bool NoDiag = false; + bool MaybeNoDiag = false; StringRef DType; if (DToken.endswith(DType="-error")) D.DL = ED ? &ED->Errors : nullptr; @@ -462,7 +463,11 @@ D.DL = ED ? &ED->Remarks : nullptr; else if (DToken.endswith(DType="-note")) D.DL = ED ? &ED->Notes : nullptr; - else if (DToken.endswith(DType="-no-diagnostics")) { + else if (DToken.endswith(DType="-maybe-no-diagnostics")) { + MaybeNoDiag = true; + if (D.RegexKind) + continue; + } else if (DToken.endswith(DType="-no-diagnostics")) { NoDiag = true; if (D.RegexKind) continue; @@ -477,6 +482,12 @@ if (!std::binary_search(Prefixes.begin(), Prefixes.end(), DToken)) continue; + if (MaybeNoDiag) { + if (Status == VerifyDiagnosticConsumer::HasNoDirectives) + Status = VerifyDiagnosticConsumer::HasExpectedMaybeNoDiagnostics; + continue; + } + if (NoDiag) { if (Status == VerifyDiagnosticConsumer::HasOtherExpectedDirectives) Diags.Report(Pos, diag::err_verify_invalid_no_diags) diff --git a/clang/test/Frontend/verify-maybe-no-diagnostics.c b/clang/test/Frontend/verify-maybe-no-diagnostics.c new file mode 100644 --- /dev/null +++ b/clang/test/Frontend/verify-maybe-no-diagnostics.c @@ -0,0 +1,161 @@ +// RUN: %clang_cc1 -DTEST_A1 -verify %s +// RUN: not %clang_cc1 -DTEST_A2 -verify %s 2>&1 | FileCheck --check-prefix=A2-CHECK %s +// RUN: %clang_cc1 -DTEST_B1 -verify %s +// RUN: %clang_cc1 -DTEST_B2 -verify %s +// RUN: %clang_cc1 -DTEST_C1 -verify %s +// RUN: not %clang_cc1 -DTEST_C2 -verify %s 2>&1 | FileCheck --check-prefix=C2-CHECK %s +// RUN: %clang_cc1 -DTEST_C3 -verify %s +// RUN: not %clang_cc1 -DTEST_C4 -verify %s 2>&1 | FileCheck --check-prefix=C4-CHECK %s +// RUN: not %clang_cc1 -DTEST_D1 -verify %s 2>&1 | FileCheck --check-prefix=D1-CHECK %s +// RUN: not %clang_cc1 -DTEST_D2 -verify %s 2>&1 | FileCheck --check-prefix=D2-CHECK %s +// RUN: not %clang_cc1 -DTEST_D3 -verify %s 2>&1 | FileCheck --check-prefix=D3-CHECK %s +// RUN: not %clang_cc1 -DTEST_D4 -verify %s 2>&1 | FileCheck --check-prefix=D4-CHECK %s +// RUN: not %clang_cc1 -DTEST_D5 -verify %s 2>&1 | FileCheck --check-prefix=D5-CHECK %s +// RUN: not %clang_cc1 -DTEST_D6 -verify %s 2>&1 | FileCheck --check-prefix=D6-CHECK %s +// RUN: not %clang_cc1 -DTEST_E1 -verify %s 2>&1 | FileCheck --check-prefix=E1-CHECK %s +// RUN: not %clang_cc1 -DTEST_E2 -verify %s 2>&1 | FileCheck --check-prefix=E2-CHECK %s +// RUN: not %clang_cc1 -DTEST_E3 -verify %s 2>&1 | FileCheck --check-prefix=E3-CHECK %s +// RUN: not %clang_cc1 -DTEST_E1 -verify=foo,bar %s 2>&1 | FileCheck --check-prefix=E1-CHECK %s +// RUN: not %clang_cc1 -DTEST_E2 -verify=foo,bar %s 2>&1 | FileCheck --check-prefix=E2-CHECK %s +// RUN: not %clang_cc1 -DTEST_E3 -verify=foo,bar %s 2>&1 | FileCheck --check-prefix=E3-CHECK %s + +#ifdef TEST_A1 +// expected-maybe-no-diagnostics +#endif + +#ifdef TEST_A2 +// expected-maybe-no-diagnostics-re + +// A2-CHECK: error: no expected directives found: consider use of 'expected-no-diagnostics' +// A2-CHECK-NEXT: 1 error generated. +#endif + +#ifdef TEST_B1 +// expected-maybe-no-diagnostics +// expected-no-diagnostics +#endif + +#ifdef TEST_B2 +// expected-no-diagnostics +// expected-maybe-no-diagnostics +#endif + +#ifdef TEST_C1 +// expected-maybe-no-diagnostics +#error test_c1 +// expected-error@-1 {{test_c1}} +#endif + +#ifdef TEST_C2 +// expected-maybe-no-diagnostics +#error test_c2 + +// C2-CHECK: error: 'error' diagnostics seen but not expected: +// C2-CHECK-NEXT: {{test_c2}} +// C2-CHECK-NEXT: 1 error generated. +#endif + +#ifdef TEST_C3 +#error test_c3 +// expected-error@-1 {{test_c3}} +// expected-maybe-no-diagnostics +#endif + +#ifdef TEST_C4 +#error test_c4 +// expected-maybe-no-diagnostics + +// C4-CHECK: error: 'error' diagnostics seen but not expected: +// C4-CHECK-NEXT: {{test_c4}} +// C4-CHECK-NEXT: 1 error generated. +#endif + +#ifdef TEST_D1 +// expected-maybe-no-diagnostics +#error test_d1 +// expected-error@-1 {{test_d1}} +// expected-no-diagnostics + +// D1-CHECK: error: 'error' diagnostics seen but not expected: +// D1-CHECK-NEXT: {{.*}} 'expected-no-diagnostics' directive cannot follow directives that expect diagnostics +// D1-CHECK-NEXT: 1 error generated. +#endif + +#ifdef TEST_D2 +// expected-maybe-no-diagnostics +// expected-no-diagnostics +#error test_d2 +// expected-error@-1 {{test_d2}} + +// D2-CHECK: error: 'error' diagnostics seen but not expected: +// D2-CHECK-NEXT: {{test_d2}} +// D2-CHECK-NEXT: {{.*}} expected directive cannot follow 'expected-no-diagnostics' directive +// D2-CHECK-NEXT: 2 errors generated. +#endif + +#ifdef TEST_D3 +// expected-no-diagnostics +// expected-maybe-no-diagnostics +#error test_d3 +// expected-error@-1 {{test_d3}} + +// D3-CHECK: error: 'error' diagnostics seen but not expected: +// D3-CHECK-NEXT: {{test_d3}} +// D3-CHECK-NEXT: {{.*}} expected directive cannot follow 'expected-no-diagnostics' directive +// D3-CHECK-NEXT: 2 errors generated. +#endif + +#ifdef TEST_D4 +// expected-no-diagnostics +#error test_d4 +// expected-error@-1 {{test_d4}} +// expected-maybe-no-diagnostics + +// D4-CHECK: error: 'error' diagnostics seen but not expected: +// D4-CHECK-NEXT: {{test_d4}} +// D4-CHECK-NEXT: {{.*}} expected directive cannot follow 'expected-no-diagnostics' directive +// D4-CHECK-NEXT: 2 errors generated. +#endif + +#ifdef TEST_D5 +#error test_d5 +// expected-error@-1 {{test_d5}} +// expected-no-diagnostics +// expected-maybe-no-diagnostics + +// D5-CHECK: error: 'error' diagnostics seen but not expected: +// D5-CHECK-NEXT: {{.*}} 'expected-no-diagnostics' directive cannot follow directives that expect diagnostics +// D5-CHECK-NEXT: 1 error generated. +#endif + +#ifdef TEST_D6 +#error test_d6 +// expected-error@-1 {{test_d6}} +// expected-maybe-no-diagnostics +// expected-no-diagnostics + +// D6-CHECK: error: 'error' diagnostics seen but not expected: +// D6-CHECK-NEXT: {{.*}} 'expected-no-diagnostics' directive cannot follow directives that expect diagnostics +// D6-CHECK-NEXT: 1 error generated. +#endif + +#ifdef TEST_E1 +// BOGUS-maybe-no-diagnostics + +// E1-CHECK: error: no expected directives found: consider use of 'expected-no-diagnostics' +// E1-CHECK-NEXT: 1 error generated. +#endif + +#ifdef TEST_E2 +// BOGUS-expected-maybe-no-diagnostics + +// E2-CHECK: error: no expected directives found: consider use of 'expected-no-diagnostics' +// E2-CHECK-NEXT: 1 error generated. +#endif + +#ifdef TEST_E3 +// expected-BOGUS-maybe-no-diagnostics + +// E3-CHECK: error: no expected directives found: consider use of 'expected-no-diagnostics' +// E3-CHECK-NEXT: 1 error generated. +#endif diff --git a/clang/test/Frontend/verify3.c b/clang/test/Frontend/verify3.c --- a/clang/test/Frontend/verify3.c +++ b/clang/test/Frontend/verify3.c @@ -19,7 +19,7 @@ // expected-no-diagnostics // CHECK2: error: 'error' diagnostics seen but not expected: -// CHECK2-NEXT: Line 19: 'expected-no-diagnostics' directive cannot follow other expected directives +// CHECK2-NEXT: Line 19: 'expected-no-diagnostics' directive cannot follow directives that expect diagnostics // CHECK2-NEXT: 1 error generated. #endif