#define LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICSCLIENT_H
#include "clang/Basic/Diagnostic.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/STLExtras.h"
#include <climits>
class DiagnosticsEngine;
class TextDiagnosticBuffer;
+class FileEntry;
/// VerifyDiagnosticConsumer - Create a diagnostic client which will use
/// markers in the input source to check that all the emitted diagnostics match
/// // expected-error-re {{variable has has type 'struct (.*)'}}
/// // expected-error-re {{variable has has type 'struct[[:space:]](.*)'}}
///
-class VerifyDiagnosticConsumer: public DiagnosticConsumer {
+class VerifyDiagnosticConsumer: public DiagnosticConsumer,
+ public CommentHandler {
public:
/// Directive - Abstract class representing a parsed verify directive.
///
};
private:
+ typedef llvm::DenseSet<FileID> FilesWithDiagnosticsSet;
+ typedef llvm::SmallPtrSet<const FileEntry *, 4> FilesWithDirectivesSet;
+
DiagnosticsEngine &Diags;
DiagnosticConsumer *PrimaryClient;
bool OwnsPrimaryClient;
OwningPtr<TextDiagnosticBuffer> Buffer;
- Preprocessor *CurrentPreprocessor;
+ const Preprocessor *CurrentPreprocessor;
+ FilesWithDiagnosticsSet FilesWithDiagnostics;
+ FilesWithDirectivesSet FilesWithDirectives;
ExpectedData ED;
- FileID FirstErrorFID; // FileID of first diagnostic
void CheckDiagnostics();
public:
virtual void EndSourceFile();
+ virtual bool HandleComment(Preprocessor &PP, SourceRange Comment);
+
virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info);
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/FileManager.h"
#include "clang/Frontend/VerifyDiagnosticConsumer.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/TextDiagnosticBuffer.h"
void VerifyDiagnosticConsumer::BeginSourceFile(const LangOptions &LangOpts,
const Preprocessor *PP) {
- // FIXME: Const hack, we screw up the preprocessor but in practice its ok
- // because it doesn't get reused. It would be better if we could make a copy
- // though.
- CurrentPreprocessor = const_cast<Preprocessor*>(PP);
+ CurrentPreprocessor = PP;
+ if (PP) const_cast<Preprocessor*>(PP)->addCommentHandler(this);
PrimaryClient->BeginSourceFile(LangOpts, PP);
}
void VerifyDiagnosticConsumer::EndSourceFile() {
+ if (CurrentPreprocessor)
+ const_cast<Preprocessor*>(CurrentPreprocessor)->removeCommentHandler(this);
CheckDiagnostics();
PrimaryClient->EndSourceFile();
void VerifyDiagnosticConsumer::HandleDiagnostic(
DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) {
- if (FirstErrorFID.isInvalid() && Info.hasSourceManager()) {
+ if (Info.hasSourceManager()) {
const SourceManager &SM = Info.getSourceManager();
- FirstErrorFID = SM.getFileID(Info.getLocation());
+ FilesWithDiagnostics.insert(SM.getFileID(Info.getLocation()));
}
// Send the diagnostic to the buffer, we will check it once we reach the end
// of the source file (or are destructed).
class ParseHelper
{
public:
- ParseHelper(const char *Begin, const char *End)
- : Begin(Begin), End(End), C(Begin), P(Begin), PEnd(NULL) { }
+ ParseHelper(StringRef S)
+ : Begin(S.begin()), End(S.end()), C(Begin), P(Begin), PEnd(NULL) { }
// Return true if string literal is next.
bool Next(StringRef S) {
/// ParseDirective - Go through the comment and see if it indicates expected
/// diagnostics. If so, then put them in the appropriate directive list.
///
-static void ParseDirective(const char *CommentStart, unsigned CommentLen,
- ExpectedData &ED, SourceManager &SM,
+/// Returns true if any valid directives were found.
+static bool ParseDirective(StringRef S, ExpectedData &ED, SourceManager &SM,
SourceLocation Pos, DiagnosticsEngine &Diags) {
// A single comment may contain multiple directives.
- for (ParseHelper PH(CommentStart, CommentStart+CommentLen); !PH.Done();) {
+ bool FoundDirective = false;
+ for (ParseHelper PH(S); !PH.Done();) {
// Search for token: expected
if (!PH.Search("expected"))
break;
Directive *D = Directive::create(RegexKind, Pos, ExpectedLoc, Text,
Min, Max);
std::string Error;
- if (D->isValid(Error))
+ if (D->isValid(Error)) {
DL->push_back(D);
- else {
+ FoundDirective = true;
+ } else {
Diags.Report(Pos.getLocWithOffset(ContentBegin-PH.Begin),
diag::err_verify_invalid_content)
<< KindStr << Error;
}
}
+
+ return FoundDirective;
+}
+
+/// HandleComment - Hook into the preprocessor and extract comments containing
+/// expected errors and warnings.
+bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP,
+ SourceRange Comment) {
+ SourceManager &SM = PP.getSourceManager();
+ SourceLocation CommentBegin = Comment.getBegin();
+
+ const char *CommentRaw = SM.getCharacterData(CommentBegin);
+ StringRef C(CommentRaw, SM.getCharacterData(Comment.getEnd()) - CommentRaw);
+
+ if (C.empty())
+ return false;
+
+ // Fold any "\<EOL>" sequences
+ size_t loc = C.find('\\');
+ if (loc == StringRef::npos) {
+ if (ParseDirective(C, ED, SM, CommentBegin, PP.getDiagnostics()))
+ if (const FileEntry *E = SM.getFileEntryForID(SM.getFileID(CommentBegin)))
+ FilesWithDirectives.insert(E);
+ return false;
+ }
+
+ std::string C2;
+ C2.reserve(C.size());
+
+ for (size_t last = 0;; loc = C.find('\\', last)) {
+ if (loc == StringRef::npos || loc == C.size()) {
+ C2 += C.substr(last);
+ break;
+ }
+ C2 += C.substr(last, loc-last);
+ last = loc + 1;
+
+ if (C[last] == '\n' || C[last] == '\r') {
+ ++last;
+
+ // Escape \r\n or \n\r, but not \n\n.
+ if (last < C.size())
+ if (C[last] == '\n' || C[last] == '\r')
+ if (C[last] != C[last-1])
+ ++last;
+ } else {
+ // This was just a normal backslash.
+ C2 += '\\';
+ }
+ }
+
+ if (!C2.empty())
+ if (ParseDirective(C2, ED, SM, CommentBegin, PP.getDiagnostics()))
+ if (const FileEntry *E = SM.getFileEntryForID(SM.getFileID(CommentBegin)))
+ FilesWithDirectives.insert(E);
+ return false;
}
/// FindExpectedDiags - Lex the main source file to find all of the
// expected errors and warnings.
-static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED, FileID FID) {
+static void FindExpectedDiags(const Preprocessor &PP, ExpectedData &ED,
+ FileID FID) {
// Create a raw lexer to pull all the comments out of FID.
if (FID.isInvalid())
return;
if (Comment.empty()) continue;
// Find all expected errors/warnings/notes.
- ParseDirective(&Comment[0], Comment.size(), ED, SM, Tok.getLocation(),
- PP.getDiagnostics());
+ ParseDirective(Comment, ED, SM, Tok.getLocation(), PP.getDiagnostics());
};
}
// markers. If not then any diagnostics are unexpected.
if (CurrentPreprocessor) {
SourceManager &SM = CurrentPreprocessor->getSourceManager();
- // Extract expected-error strings from main file.
- FindExpectedDiags(*CurrentPreprocessor, ED, SM.getMainFileID());
- // Only check for expectations in other diagnostic locations
- // if they are not the main file (via ID or FileEntry) - the main
- // file has already been looked at, and its expectations must not
- // be added twice.
- if (!FirstErrorFID.isInvalid() && FirstErrorFID != SM.getMainFileID()
- && (!SM.getFileEntryForID(FirstErrorFID)
- || (SM.getFileEntryForID(FirstErrorFID) !=
- SM.getFileEntryForID(SM.getMainFileID())))) {
- FindExpectedDiags(*CurrentPreprocessor, ED, FirstErrorFID);
- FirstErrorFID = FileID();
+ // Only check for expectations in other diagnostic locations not
+ // captured during normal parsing.
+ // FIXME: This check is currently necessary while synthesized files may
+ // not have their expected-* directives captured during parsing. These
+ // cases should be fixed and the following loop replaced with one which
+ // checks only during a debug build and asserts on a mismatch.
+ for (FilesWithDiagnosticsSet::iterator I = FilesWithDiagnostics.begin(),
+ End = FilesWithDiagnostics.end();
+ I != End; ++I) {
+ const FileEntry *E = SM.getFileEntryForID(*I);
+ if (!E || !FilesWithDirectives.count(E)) {
+ if (E)
+ FilesWithDirectives.insert(E);
+ FindExpectedDiags(*CurrentPreprocessor, ED, *I);
+ }
}
// Check that the expected diagnostics occurred.
--- /dev/null
+// Check that directives inside includes are included!
+// expected-error@1 {{include file test}}
--- /dev/null
+// RUN: %clang_cc1 -Wfatal-errors -verify %s 2>&1 | FileCheck %s
+
+#error first fatal
+// expected-error@-1 {{first fatal}}
+
+#error second fatal
+// expected-error@-1 {{second fatal}}
+
+
+// CHECK: error: 'error' diagnostics expected but not seen:
+// CHECK-NEXT: Line 6 (directive at {{.*}}verify-fatal.c:7): second fatal
+// CHECK-NEXT: 1 error generated.
--- /dev/null
+// RUN: %clang_cc1 -DTEST1 -verify %s
+// RUN: %clang_cc1 -DTEST2 -verify %s 2>&1 | FileCheck -check-prefix=CHECK2 %s
+// RUN: %clang_cc1 -DTEST3 -verify %s 2>&1 | FileCheck -check-prefix=CHECK3 %s
+// RUN: %clang_cc1 -DTEST4 -verify %s 2>&1 | FileCheck -check-prefix=CHECK4 %s
+// RUN: %clang_cc1 -DTEST5 -verify %s 2>&1 | FileCheck -check-prefix=CHECK5 %s
+
+// expected-warning@ malformed
+// expected-error@7 1 {{missing or invalid line number}}
+
+// expected-warning@0 malformed
+// expected-error@10 {{missing or invalid line number}}
+
+// expected-warning@-50 malformed
+// expected-error@13 {{missing or invalid line number}}
+
+// expected-warning malformed
+// expected-error@16 {{cannot find start}}
+
+// expected-error 0+ {{should also be ignored}}
+
+#ifdef TEST1
+#if 0
+// expected-error {{should be ignored}}
+#endif
+
+#error should not be ignored
+// expected-error@-1 1+ {{should not be ignored}}
+
+#line 90
+unexpected a; // expected-error@+0 + {{unknown type}}
+
+#line 60
+unexpected b; // expected-error@33 1-1 {{unknown type}}
+
+// expected-error@+2 {{file not found}} check that multi-line handled correctly: \
+
+#include "missing_header_file.include"
+#endif
+
+#ifdef TEST2
+#define MACRO some_value // expected-error {{define_error}}
+#undef MACRO extra_token // expected-warning {{undef_error}}
+#line -2 // expected-error {{line_error}}
+#error AAA // expected-error {{BBB}} <- this shall be part of diagnostic
+#warning CCC // expected-warning {{DDD}} <- this shall be part of diagnostic
+
+#if 0
+// This is encapsulated in "#if 0" so that the expected-* checks below
+// are not inadvertently included in the diagnostic checking!
+
+// CHECK2: error: 'error' diagnostics expected but not seen:
+// CHECK2-NEXT: Line 41: define_error
+// CHECK2-NEXT: Line 43: line_error
+// CHECK2-NEXT: error: 'error' diagnostics seen but not expected:
+// CHECK2-NEXT: Line 43: #line directive requires a positive integer argument
+// CHECK2-NEXT: Line 44: AAA // expected-error {{[{][{]BBB[}][}]}} <- this shall be part of diagnostic
+// CHECK2-NEXT: error: 'warning' diagnostics expected but not seen:
+// CHECK2-NEXT: Line 42: undef_error
+// CHECK2-NEXT: error: 'warning' diagnostics seen but not expected:
+// CHECK2-NEXT: Line 42: extra tokens at end of #undef directive
+// CHECK2-NEXT: Line 45: CCC // expected-warning {{[{][{]DDD[}][}]}} <- this shall be part of diagnostic
+// CHECK2-NEXT: 7 errors generated.
+#endif
+#endif
+
+#ifdef TEST3
+#ifndef TEST3 // expected-note {{line_67}}
+ // expected-note {{line_68_ignored}}
+# ifdef UNDEFINED // expected-note {{line_69_ignored}}
+# endif // expected-note {{line_70_ignored}}
+#elif defined(TEST3) // expected-note {{line_71}}
+# if 1 // expected-note {{line_72}}
+ // expected-note {{line_73}}
+# else // expected-note {{line_74}}
+ // expected-note {{line_75_ignored}}
+# ifndef TEST3 // expected-note {{line_76_ignored}}
+# endif // expected-note {{line_77_ignored}}
+# endif // expected-note {{line_78}}
+#endif
+
+// CHECK3: error: 'note' diagnostics expected but not seen:
+// CHECK3-NEXT: Line 67: line_67
+// CHECK3-NEXT: Line 71: line_71
+// CHECK3-NEXT: Line 72: line_72
+// CHECK3-NEXT: Line 73: line_73
+// CHECK3-NEXT: Line 74: line_74
+// CHECK3-NEXT: Line 78: line_78
+// CHECK3-NEXT: 6 errors generated.
+#endif
+
+#ifdef TEST4
+#include "missing_header_file.include" // expected-error {{include_error}}
+
+// CHECK4: error: 'error' diagnostics expected but not seen:
+// CHECK4-NEXT: Line 92: include_error
+// CHECK4-NEXT: error: 'error' diagnostics seen but not expected:
+// CHECK4-NEXT: Line 92: 'missing_header_file.include' file not found
+// CHECK4-NEXT: 2 errors generated.
+#endif
+
+#ifdef TEST5
+#include "verify-directive.h"
+// expected-error@50 {{source file test}}
+
+// CHECK5: error: 'error' diagnostics expected but not seen:
+// CHECK5-NEXT: Line 1 (directive at {{.*}}verify-directive.h:2): include file test
+// CHECK5-NEXT: Line 50 (directive at {{.*}}verify.c:103): source file test
+// CHECK5-NEXT: 2 errors generated.
+#endif
+
#error bar
//??/
-#error qux // expected-error {{qux}}
+#error qux
+// expected-error@-1 {{qux}}
// Trailing whitespace!
//\
// Test that we recover gracefully from conflict markers left in input files.
// PR5238
-// diff3 style
-<<<<<<< .mine // expected-error {{version control conflict marker in file}}
+// diff3 style expected-error@+1 {{version control conflict marker in file}}
+<<<<<<< .mine
int x = 4;
|||||||
int x = 123;
float x = 17;
>>>>>>> .r91107
-// normal style.
-<<<<<<< .mine // expected-error {{version control conflict marker in file}}
+// normal style expected-error@+1 {{version control conflict marker in file}}
+<<<<<<< .mine
typedef int y;
=======
typedef struct foo *y;
>>>>>>> .r91107
-// Perforce style.
->>>> ORIGINAL conflict-marker.c#6 // expected-error {{version control conflict marker in file}}
+// Perforce style expected-error@+1 {{version control conflict marker in file}}
+>>>> ORIGINAL conflict-marker.c#6
int z = 1;
==== THEIRS conflict-marker.c#7
int z = 0;
-// expected-warning{{umbrella header}}
+// expected-warning 0-1 {{umbrella header}}
+
+// FIXME: The "umbrella header" warning should be moved to a separate test.
+// This "0-1" is only here because the warning is only emitted when the
+// module is (otherwise) successfully included.
#ifndef MODULE_H
#define MODULE_H
@interface OtherClass
@end
-
-
-
-// in module: expected-note{{class method 'alloc' is assumed to return an instance of its receiver type ('Module *')}}
+// in module: expected-note@17{{class method 'alloc' is assumed to return an instance of its receiver type ('Module *')}}
void test_getModuleVersion() {
const char *version = getModuleVersion();
const char *version2 = [Module version];
#ifndef HEADER
#define HEADER
-int f(int) __attribute__((visibility("default"), overloadable)); // expected-note{{previous overload}}
+int f(int) __attribute__((visibility("default"), overloadable));
#else
double f(double); // expected-error{{overloadable}}
+ // expected-note@11{{previous overload}}
#endif
#else
//===----------------------------------------------------------------------===//
-#warning reached main file // expected-warning {{reached main file}}
+// expected-warning@+1 {{reached main file}}
+#warning reached main file
int g3 = NS::TS<int, 2>::value;
#define HEADER
template<int N> struct T {
- static_assert(N == 2, "N is not 2!"); // expected-error {{static_assert failed "N is not 2!"}}
+ static_assert(N == 2, "N is not 2!");
};
#else
+// expected-error@12 {{static_assert failed "N is not 2!"}}
T<1> t1; // expected-note {{in instantiation of template class 'T<1>' requested here}}
T<2> t2;
#ifndef HEADER_INCLUDED
#define HEADER_INCLUDED
-typedef auto f() -> int; // expected-note {{here}}
-typedef int g(); // expected-note {{here}}
+typedef auto f() -> int;
+typedef int g();
#else
typedef void f; // expected-error {{typedef redefinition with different types ('void' vs 'auto () -> int')}}
+ // expected-note@7 {{here}}
typedef void g; // expected-error {{typedef redefinition with different types ('void' vs 'int ()')}}
+ // expected-note@8 {{here}}
#endif
struct foo {
foo() = default;
- void bar() = delete; // expected-note{{deleted here}}
+ void bar() = delete;
};
struct baz {
- ~baz() = delete; // expected-note{{deleted here}}
+ ~baz() = delete;
};
class quux {
- ~quux() = default; // expected-note{{private here}}
+ ~quux() = default;
};
#else
foo::foo() { } // expected-error{{definition of explicitly defaulted default constructor}}
foo f;
void fn() {
- f.bar(); // expected-error{{deleted function}}
+ f.bar(); // expected-error{{deleted function}} expected-note@12{{deleted here}}
}
-baz bz; // expected-error{{deleted function}}
-quux qx; // expected-error{{private destructor}}
+baz bz; // expected-error{{deleted function}} expected-note@16{{deleted here}}
+quux qx; // expected-error{{private destructor}} expected-note@20{{private here}}
#endif
#ifndef PASS1
#define PASS1
struct foo {
- foo(int) : foo() { } // expected-note{{it delegates to}}
+ foo(int) : foo() { }
foo();
- foo(bool) : foo('c') { } // expected-note{{it delegates to}}
- foo(char) : foo(true) { } // expected-error{{creates a delegation cycle}} \
- // expected-note{{which delegates to}}
+ foo(bool) : foo('c') { }
+ foo(char) : foo(true) { }
};
#else
foo::foo() : foo(1) { } // expected-error{{creates a delegation cycle}} \
// expected-note{{which delegates to}}
+
+// expected-note@11{{it delegates to}}
+// expected-note@13{{it delegates to}}
+// expected-error@14{{creates a delegation cycle}}
+// expected-note@14{{which delegates to}}
#endif
#define HEADER_INCLUDED
struct B {
- B(); // expected-note {{here}}
+ B();
constexpr B(char) {}
};
-struct C { // expected-note {{not an aggregate and has no constexpr constructors}}
+struct C {
B b;
double d = 0.0;
};
static_assert(D(4).k == 9, "");
constexpr int f(C c) { return 0; } // expected-error {{not a literal type}}
+// expected-note@13 {{not an aggregate and has no constexpr constructors}}
constexpr B b; // expected-error {{constant expression}} expected-note {{non-constexpr}}
+ // expected-note@9 {{here}}
#endif
template<typename T> struct S {
enum class E {
- e = T() // expected-error {{conversion from 'double' to 'int'}}
+ e = T()
};
};
int k1 = (int)S<int>::E::e;
int k2 = (int)decltype(b)::e;
-int k3 = (int)decltype(c)::e; // expected-note {{here}}
+int k3 = (int)decltype(c)::e; // expected-error@10 {{conversion from 'double' to 'int'}} expected-note {{here}}
int k4 = (int)S<char>::E::e;
#endif
using size_t = decltype(sizeof(int));
int operator"" _foo(const char *p, size_t);
-template<typename T> auto f(T t) -> decltype(t + ""_foo) { return 0; } // expected-note {{substitution failure}}
+template<typename T> auto f(T t) -> decltype(t + ""_foo) { return 0; }
#else
int *l = f(&k);
struct S {};
int m = f(S()); // expected-error {{no matching}}
+ // expected-note@11 {{substitution failure}}
#endif
}
__if_not_exists(T::bar) {
- int *i = t; // expected-error{{no viable conversion from 'HasFoo' to 'int *'}}
+ int *i = t;
{ }
}
}
};
template void f(HasFoo); // expected-note{{in instantiation of function template specialization 'f<HasFoo>' requested here}}
+ // expected-error@14{{no viable conversion from 'HasFoo' to 'int *'}}
template void f(HasBar);
#endif
#elif !defined(HEADER2)
#define HEADER2
-@interface I // expected-note {{previous}}
+@interface I
@end
#else
typedef int I; // expected-error {{redefinition}}
+ // expected-note@15 {{previous}}
#endif
#ifndef HEADER_INCLUDED
#define HEADER_INCLUDED
-void func(struct Test); // expected-note{{'Test' declared here}}
+void func(struct Test);
#else
::Yest *T; // expected-error{{did you mean 'Test'}}
+ // expected-note@7{{'Test' declared here}}
#endif
extern float y;
extern int *ip, x;
-float z; // expected-note{{previous}}
+float z;
-int z2 = 17; // expected-note{{previous}}
+int z2 = 17;
#define MAKE_HAPPY(X) X##Happy
-int MAKE_HAPPY(Very); // expected-note{{previous definition is here}}
+int MAKE_HAPPY(Very);
#define A_MACRO_IN_THE_PCH 492
#define FUNCLIKE_MACRO(X, Y) X ## Y
int *ip2 = &x;
float *fp = &ip; // expected-warning{{incompatible pointer types}}
-double z; // expected-error{{redefinition}}
-int z2 = 18; // expected-error{{redefinition}}
-double VeryHappy; // expected-error{{redefinition}}
+double z; // expected-error{{redefinition}} expected-note@14{{previous}}
+int z2 = 18; // expected-error{{redefinition}} expected-note@16{{previous}}
+double VeryHappy; // expected-error{{redefinition}} expected-note@19{{previous definition is here}}
int Q = A_MACRO_IN_THE_PCH;
// These are checked by the RUN line.
#line 92 "blonk.c"
-#error ABC // expected-error {{#error ABC}}
-#error DEF // expected-error {{#error DEF}}
+#error ABC
+#error DEF
+// expected-error@-2 {{ABC}}
+#line 150
+// expected-error@-3 {{DEF}}
// Verify that linemarker diddling of the system header flag works.
// RUN: %clang_cc1 %s -Eonly -verify
+// expected-error@9 {{EOF}}
#define COMM / ## *
COMM // expected-error {{pasting formed '/*', an invalid preprocessing token}}
// Demonstrate that an invalid preprocessing token
// doesn't swallow the rest of the file...
-#error EOF // expected-error {{EOF}}
+#error EOF
#if __has_warning("not valid") // expected-warning {{__has_warning expected option name}}
#endif
+// expected-warning@+2 {{Should have -Wparentheses}}
#if __has_warning("-Wparentheses")
-#warning Should have -Wparentheses // expected-warning {{Should have -Wparentheses}}
+#warning Should have -Wparentheses
#endif
#if __has_warning(-Wfoo) // expected-error {{builtin warning check macro requires a parenthesized string}}
#endif
+// expected-warning@+3 {{Not a valid warning flag}}
#if __has_warning("-Wnot-a-valid-warning-flag-at-all")
#else
-#warning Not a valid warning flag // expected-warning {{Not a valid warning flag}}
-#endif
\ No newline at end of file
+#warning Not a valid warning flag
+#endif
// RUN: %clang_cc1 -fsyntax-only -fdeprecated-macro -verify %s
// RUN: %clang_cc1 -fsyntax-only -Werror %s
+// expected-warning@+2 {{This file is deprecated.}}
#ifdef __DEPRECATED
-#warning This file is deprecated. // expected-warning {{This file is deprecated.}}
+#warning This file is deprecated.
#endif