"cannot find end ('}}') of expected %0">;
def err_verify_invalid_content : Error<
"invalid expected %0: %1">;
+def err_verify_missing_regex : Error<
+ "cannot find start of regex ('{{') in %0">;
def err_verify_inconsistent_diags : Error<
"'%0' diagnostics %select{expected|seen}1 but not %select{seen|expected}1: "
"%2">;
///
/// In this example, the diagnostic may appear only once, if at all.
///
-/// Regex matching mode may be selected by appending '-re' to type, such as:
+/// Regex matching mode may be selected by appending '-re' to type and
+/// including regexes wrapped in double curly braces in the directive, such as:
///
/// \code
-/// expected-error-re
+/// expected-error-re {{format specifies type 'wchar_t **' (aka '{{.+}}')}}
/// \endcode
///
/// Examples matching error: "variable has incomplete type 'struct s'"
/// // expected-error {{variable has incomplete type 'struct s'}}
/// // expected-error {{variable has incomplete type}}
///
-/// // expected-error-re {{variable has has type 'struct .'}}
-/// // expected-error-re {{variable has has type 'struct .*'}}
-/// // expected-error-re {{variable has has type 'struct (.*)'}}
-/// // expected-error-re {{variable has has type 'struct[[:space:]](.*)'}}
+/// // expected-error-re {{variable has type 'struct {{.}}'}}
+/// // expected-error-re {{variable has type 'struct {{.*}}'}}
+/// // expected-error-re {{variable has type 'struct {{(.*)}}'}}
+/// // expected-error-re {{variable has type 'struct{{[[:space:]](.*)}}'}}
/// \endcode
///
/// VerifyDiagnosticConsumer expects at least one expected-* directive to
class RegexDirective : public Directive {
public:
RegexDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
- StringRef Text, unsigned Min, unsigned Max)
- : Directive(DirectiveLoc, DiagnosticLoc, Text, Min, Max), Regex(Text) { }
+ StringRef Text, unsigned Min, unsigned Max, StringRef RegexStr)
+ : Directive(DirectiveLoc, DiagnosticLoc, Text, Min, Max), Regex(RegexStr) { }
virtual bool isValid(std::string &Error) {
if (Regex.isValid(Error))
return false;
}
+ // Return true if a CloseBrace that closes the OpenBrace at the current nest
+ // level is found. When true, P marks begin-position of CloseBrace.
+ bool SearchClosingBrace(StringRef OpenBrace, StringRef CloseBrace) {
+ unsigned Depth = 1;
+ P = C;
+ while (P < End) {
+ StringRef S(P, End - P);
+ if (S.startswith(OpenBrace)) {
+ ++Depth;
+ P += OpenBrace.size();
+ } else if (S.startswith(CloseBrace)) {
+ --Depth;
+ if (Depth == 0) {
+ PEnd = P + CloseBrace.size();
+ return true;
+ }
+ P += CloseBrace.size();
+ } else {
+ ++P;
+ }
+ }
+ return false;
+ }
+
// Advance 1-past previous next/search.
// Behavior is undefined if previous next/search failed.
bool Advance() {
const char* const ContentBegin = PH.C; // mark content begin
// Search for token: }}
- if (!PH.Search("}}")) {
+ if (!PH.SearchClosingBrace("{{", "}}")) {
Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
diag::err_verify_missing_end) << KindStr;
continue;
if (Text.empty())
Text.assign(ContentBegin, ContentEnd);
+ // Check that regex directives contain at least one regex.
+ if (RegexKind && Text.find("{{") == StringRef::npos) {
+ Diags.Report(Pos.getLocWithOffset(ContentBegin-PH.Begin),
+ diag::err_verify_missing_regex) << Text;
+ return false;
+ }
+
// Construct new directive.
Directive *D = Directive::create(RegexKind, Pos, ExpectedLoc, Text,
Min, Max);
ED.Notes.clear();
}
+// Add the characters from FixedStr to RegexStr, escaping as needed. This
+// avoids the need for backslash-escaping in common patterns.
+static void AddFixedStringToRegEx(StringRef FixedStr, std::string &RegexStr) {
+ // FIXME: Expose FileCheck.cpp's Pattern::AddFixedStringToRegEx as a utility
+ // method in RegEx.
+
+ for (unsigned i = 0, e = FixedStr.size(); i != e; ++i) {
+ switch (FixedStr[i]) {
+ // These are the special characters matched in "p_ere_exp".
+ case '(':
+ case ')':
+ case '^':
+ case '$':
+ case '|':
+ case '*':
+ case '+':
+ case '?':
+ case '.':
+ case '[':
+ case '\\':
+ case '{':
+ RegexStr += '\\';
+ // FALL THROUGH.
+ default:
+ RegexStr += FixedStr[i];
+ break;
+ }
+ }
+}
+
Directive *Directive::create(bool RegexKind, SourceLocation DirectiveLoc,
SourceLocation DiagnosticLoc, StringRef Text,
unsigned Min, unsigned Max) {
- if (RegexKind)
- return new RegexDirective(DirectiveLoc, DiagnosticLoc, Text, Min, Max);
- return new StandardDirective(DirectiveLoc, DiagnosticLoc, Text, Min, Max);
+ if (!RegexKind)
+ return new StandardDirective(DirectiveLoc, DiagnosticLoc, Text, Min, Max);
+
+ // Parse the directive into a regular expression.
+ std::string RegexStr;
+ StringRef S = Text;
+ while (!S.empty()) {
+ if (S.startswith("{{")) {
+ S = S.drop_front(2);
+ size_t RegexMatchLength = S.find("}}");
+ assert(RegexMatchLength != StringRef::npos);
+ // Append the regex, enclosed in parentheses.
+ RegexStr += "(";
+ RegexStr.append(S.data(), RegexMatchLength);
+ RegexStr += ")";
+ S = S.drop_front(RegexMatchLength + 2);
+ } else {
+ size_t VerbatimMatchLength = S.find("{{");
+ if (VerbatimMatchLength == StringRef::npos)
+ VerbatimMatchLength = S.size();
+ // Escape and append the fixed string.
+ AddFixedStringToRegEx(S.substr(0, VerbatimMatchLength), RegexStr);
+ S = S.drop_front(VerbatimMatchLength);
+ }
+ }
+
+ return new RegexDirective(DirectiveLoc, DiagnosticLoc, Text, Min, Max, RegexStr);
}
int foo();
-int test() { // expected-warning-re{{test -> Total CFGBlocks: [0-9]+ \| Unreachable CFGBlocks: 0 \| Exhausted Block: no \| Empty WorkList: yes}}
+int test() { // expected-warning-re{{test -> Total CFGBlocks: {{[0-9]+}} | Unreachable CFGBlocks: 0 | Exhausted Block: no | Empty WorkList: yes}}
int a = 1;
a = 34 / 12;
struct s2 {
constexpr int mi1; // expected-error {{non-static data member cannot be constexpr; did you intend to make it const?}}
static constexpr int mi2; // expected-error {{requires an initializer}}
- mutable constexpr int mi3 = 3; // expected-error-re {{non-static data member cannot be constexpr$}} expected-error {{'mutable' and 'const' cannot be mixed}}
+ mutable constexpr int mi3 = 3; // expected-error-re {{non-static data member cannot be constexpr{{$}}}} expected-error {{'mutable' and 'const' cannot be mixed}}
};
// typedef
typedef constexpr int CI; // expected-error {{typedef cannot be constexpr}}
#if __cplusplus > 201103L
template<typename T> constexpr bool check() {
- T t; // expected-note-re 2{{non-constexpr constructor '[BE]'}}
+ T t; // expected-note-re 2{{non-constexpr constructor '{{[BE]}}'}}
return true;
}
static_assert(check<A>(), "");
template<typename T>
struct F :
- E<T, 0>, // expected-note-re 2{{'[BD]' is a virtual base class of base class 'E<}}
- E<T, 1> {}; // expected-note-re 2{{'[BD]' is a virtual base class of base class 'E<}}
+ E<T, 0>, // expected-note-re 2{{'{{[BD]}}' is a virtual base class of base class 'E<}}
+ E<T, 1> {}; // expected-note-re 2{{'{{[BD]}}' is a virtual base class of base class 'E<}}
template<typename T>
struct G : E<T, 0, true>, E<T, 0> {};
template<typename T>
struct J :
- E<T, 0>, // expected-note-re 2{{'[BD]' is a virtual base class of base class 'E<}}
- virtual T {}; // expected-note-re 2{{virtual base class '[BD]' declared here}}
+ E<T, 0>, // expected-note-re 2{{'{{[BD]}}' is a virtual base class of base class 'E<}}
+ virtual T {}; // expected-note-re 2{{virtual base class '{{[BD]}}' declared here}}
template<typename T> void move(T t) { t = static_cast<T&&>(t); }
- // expected-warning-re@-1 4{{defaulted move assignment operator of .* will move assign virtual base class '[BD]' multiple times}}
+ // expected-warning-re@-1 4{{defaulted move assignment operator of {{.*}} will move assign virtual base class '{{[BD]}}' multiple times}}
template void move(F<A>);
template void move(F<B>); // expected-note {{in instantiation of}}
template void move(F<C>);
double i = 0p+3; // expected-error{{invalid suffix 'p' on integer constant}}
#define PREFIX(x) foo ## x
double foo0p = 1, j = PREFIX(0p+3); // ok
-double k = 0x42_amp+3; // expected-error-re{{invalid suffix '_amp' on integer constant|no matching literal operator for call to 'operator "" _amp'}}
+double k = 0x42_amp+3; // expected-error-re{{{{invalid suffix '_amp' on integer constant|no matching literal operator for call to 'operator "" _amp'}}}}
struct s s2; // expected-error {{tentative definition has type}}
// regex matching
-struct s r1; // expected-error-re {{tentative definition has type 'struct s' that is never completed}}
-struct s r2; // expected-error-re {{tentative definition has type '.*[[:space:]]*.*' that is never completed}}
-struct s r3; // expected-error-re {{tentative definition has type '(.*)[[:space:]]*(.*)' that is never completed}}
-struct s r4; // expected-error-re {{^tentative}}
-struct s r5; // expected-error-re {{completed$}}
+struct s r1; // expected-error {{tentative definition has type 'struct s' that is never completed}}
+struct s r2; // expected-error-re {{tentative definition has type '{{.*[[:space:]]*.*}}' that is never completed}}
+struct s r3; // expected-error-re {{tentative definition has type '{{(.*)[[:space:]]*(.*)}}' that is never completed}}
+struct s r4; // expected-error-re {{{{^}}tentative}}
+struct s r5; // expected-error-re {{completed{{$}}}}
@interface EXP I @end // expected-error {{postfix attributes are not allowed on Objective-C directives, place them in front of '@interface'}}
EXP @interface I2 @end
-@implementation EXP I @end // expected-error-re {{postfix attributes are not allowed on Objective-C directives$}}
+@implementation EXP I @end // expected-error-re {{postfix attributes are not allowed on Objective-C directives{{$}}}}
// FIXME: Prefix attribute recovery skips until ';'
EXP @implementation I2 @end; // expected-error {{prefix attribute must be followed by an interface or protocol}}
-@class EXP OC; // expected-error-re {{postfix attributes are not allowed on Objective-C directives$}}
+@class EXP OC; // expected-error-re {{postfix attributes are not allowed on Objective-C directives{{$}}}}
EXP @class OC2; // expected-error {{prefix attribute must be followed by an interface or protocol}}
@protocol EXP P @end // expected-error {{postfix attributes are not allowed on Objective-C directives, place them in front of '@protocol'}}
// Test argument type check for the 'm' length modifier.
scanf("%ms", fp); // expected-warning{{format specifies type 'char **' but the argument has type 'float *'}}
- scanf("%mS", fp); // expected-warning-re{{format specifies type 'wchar_t \*\*' \(aka '[^']+'\) but the argument has type 'float \*'}}
+ scanf("%mS", fp); // expected-warning-re{{format specifies type 'wchar_t **' (aka '{{[^']+}}') but the argument has type 'float *'}}
scanf("%mc", fp); // expected-warning{{format specifies type 'char **' but the argument has type 'float *'}}
- scanf("%mC", fp); // expected-warning-re{{format specifies type 'wchar_t \*\*' \(aka '[^']+'\) but the argument has type 'float \*'}}
+ scanf("%mC", fp); // expected-warning-re{{format specifies type 'wchar_t **' (aka '{{[^']+}}') but the argument has type 'float *'}}
scanf("%m[abc]", fp); // expected-warning{{format specifies type 'char **' but the argument has type 'float *'}}
}
unsigned short g; // expected-error {{redefinition of 'g' with a different type: 'unsigned short' vs '__wchar_t'}}
// The type of a wide string literal is actually not __wchar_t.
-__wchar_t s[] = L"Hello world!"; // expected-error-re {{array initializer must be an initializer list$}}
+__wchar_t s[] = L"Hello world!"; // expected-error-re {{array initializer must be an initializer list{{$}}}}
// Do not suggest initializing with a string here, because it would not work.
-__wchar_t t[] = 1; // expected-error-re {{array initializer must be an initializer list$}}
+__wchar_t t[] = 1; // expected-error-re {{array initializer must be an initializer list{{$}}}}
__thread __private_extern__ int t4;
struct t5 { __thread int x; };
#ifdef __cplusplus
-// expected-error-re@-2 {{'(__thread|_Thread_local|thread_local)' is only allowed on variable declarations}}
+// expected-error-re@-2 {{'{{__thread|_Thread_local|thread_local}}' is only allowed on variable declarations}}
#else
// FIXME: The 'is only allowed on variable declarations' diagnostic is better here.
// expected-error@-5 {{type name does not allow storage class to be specified}}
static __thread int t10;
__thread __private_extern__ int t11;
#if __cplusplus < 201103L
- __thread auto int t12a; // expected-error-re {{cannot combine with previous '(__thread|_Thread_local)' declaration specifier}}
+ __thread auto int t12a; // expected-error-re {{cannot combine with previous '{{__thread|_Thread_local}}' declaration specifier}}
auto __thread int t12b; // expected-error {{cannot combine with previous 'auto' declaration specifier}}
#elif !defined(CXX11)
- __thread auto t12a = 0; // expected-error-re {{'_Thread_local' variables must have global storage}}
- auto __thread t12b = 0; // expected-error-re {{'_Thread_local' variables must have global storage}}
+ __thread auto t12a = 0; // expected-error {{'_Thread_local' variables must have global storage}}
+ auto __thread t12b = 0; // expected-error {{'_Thread_local' variables must have global storage}}
#endif
- __thread register int t13a; // expected-error-re {{cannot combine with previous '(__thread|_Thread_local|thread_local)' declaration specifier}}
+ __thread register int t13a; // expected-error-re {{cannot combine with previous '{{__thread|_Thread_local|thread_local}}' declaration specifier}}
register __thread int t13b; // expected-error {{cannot combine with previous 'register' declaration specifier}}
}
-__thread typedef int t14; // expected-error-re {{cannot combine with previous '(__thread|_Thread_local|thread_local)' declaration specifier}}
+__thread typedef int t14; // expected-error-re {{cannot combine with previous '{{__thread|_Thread_local|thread_local}}' declaration specifier}}
__thread int t15; // expected-note {{previous declaration is here}}
extern int t15; // expected-error {{non-thread-local declaration of 't15' follows thread-local declaration}}
extern int t16; // expected-note {{previous declaration is here}}
void h() {
// Do not suggest '()' since an int argument is required
- q1<int>; // expected-error-re{{reference to non-static member function must be called$}}
+ q1<int>; // expected-error-re{{reference to non-static member function must be called{{$}}}}
// Suggest '()' since there's a default value for the only argument & the
// type argument is already provided
q2<int>; // expected-error{{reference to non-static member function must be called; did you mean to call it with no arguments?}}
// already provided
q3<int>; // expected-error{{reference to non-static member function must be called; did you mean to call it with no arguments?}}
// Do not suggest '()' since another type argument is required
- q4<int>; // expected-error-re{{reference to non-static member function must be called$}}
+ q4<int>; // expected-error-re{{reference to non-static member function must be called{{$}}}}
// Suggest '()' since the type parameter has a default value
q5; // expected-error{{reference to non-static member function must be called; did you mean to call it with no arguments?}}
}
};
template <class T> void call_func(T t) {
- t->func(); // expected-error-re 2 {{member reference type 'PR15045::bar' is not a pointer$}} \
+ t->func(); // expected-error-re 2 {{member reference type 'PR15045::bar' is not a pointer{{$}}}} \
// expected-note {{did you mean to use '.' instead?}}
}
// Make sure a fixit isn't given in the case that the '->' isn't actually
// the problem (the problem is with the return value of an operator->).
- f->func(); // expected-error-re {{member reference type 'PR15045::bar' is not a pointer$}}
+ f->func(); // expected-error-re {{member reference type 'PR15045::bar' is not a pointer{{$}}}}
call_func(e); // expected-note {{in instantiation of function template specialization 'PR15045::call_func<PR15045::bar>' requested here}}
void g(int&); // expected-note{{type of 1st parameter of member declaration does not match definition ('int &' vs 'const int &')}}
}
-void A::f() {} // expected-error-re{{out-of-line definition of 'f' does not match any declaration in namespace 'A'$}}
+void A::f() {} // expected-error-re{{out-of-line definition of 'f' does not match any declaration in namespace 'A'{{$}}}}
void A::g(const int&) { } // expected-error{{out-of-line definition of 'g' does not match any declaration in namespace 'A'}}
template<int N> struct B {
A<N-1> operator->(); // expected-note +{{'operator->' declared here produces an object of type 'A<}}
#if MAX != 2
- // expected-note-re@-2 {{(skipping (120|2) 'operator->'s in backtrace)}}
+ // expected-note-re@-2 {{(skipping {{120|2}} 'operator->'s in backtrace)}}
#endif
};
int n = good->n;
B<MAX/2 + 1> bad;
-int m = bad->n; // expected-error-re {{use of 'operator->' on type 'B<(2|10|128) / 2 \+ 1>' would invoke a sequence of more than (2|10|128) 'operator->' calls}}
+int m = bad->n; // expected-error-re {{use of 'operator->' on type 'B<{{2|10|128}} / 2 + 1>' would invoke a sequence of more than {{2|10|128}} 'operator->' calls}}
// expected-note@-1 {{use -foperator-arrow-depth=N to increase 'operator->' limit}}
};
}
// FIXME: Typo correction should remove the 'gatekeeper_v1::' name specifier
- gatekeeper_v1::closure_t *x; // expected-error-re {{no type named 'closure_t' in namespace 'gatekeeper_v1'$}}
+ gatekeeper_v1::closure_t *x; // expected-error-re {{no type named 'closure_t' in namespace 'gatekeeper_v1'{{$}}}}
}
namespace Foo {
void test_a() {
a::a::i = 3; // expected-error{{no member named 'i' in namespace 'a::a'; did you mean 'a::a::a::i'?}}
a::a::a::i = 4;
- a::a::j = 3; // expected-error-re{{no member named 'j' in namespace 'a::a'$}}
+ a::a::j = 3; // expected-error-re{{no member named 'j' in namespace 'a::a'{{$}}}}
}
struct Undef { // expected-note{{definition of 'Undef' is not complete until the closing '}'}}
namespace bogus_keyword_suggestion {
void test() {
- status = "OK"; // expected-error-re {{use of undeclared identifier 'status'$}}
- return status; // expected-error-re {{use of undeclared identifier 'status'$}}
+ status = "OK"; // expected-error-re {{use of undeclared identifier 'status'{{$}}}}
+ return status; // expected-error-re {{use of undeclared identifier 'status'{{$}}}}
}
}
};
// should be void T::f();
void f() {
- data_struct->foo(); // expected-error-re{{use of undeclared identifier 'data_struct'$}}
+ data_struct->foo(); // expected-error-re{{use of undeclared identifier 'data_struct'{{$}}}}
}
namespace PR12287 {
void testAccess() {
Figure obj;
switch (obj.type()) { // expected-warning {{enumeration values 'SQUARE', 'TRIANGLE', and 'CIRCLE' not handled in switch}}
- case SQUARE: // expected-error-re {{use of undeclared identifier 'SQUARE'$}}
- case TRIANGLE: // expected-error-re {{use of undeclared identifier 'TRIANGLE'$}}
- case CIRCE: // expected-error-re {{use of undeclared identifier 'CIRCE'$}}
+ case SQUARE: // expected-error-re {{use of undeclared identifier 'SQUARE'{{$}}}}
+ case TRIANGLE: // expected-error-re {{use of undeclared identifier 'TRIANGLE'{{$}}}}
+ case CIRCE: // expected-error-re {{use of undeclared identifier 'CIRCE'{{$}}}}
break;
}
}
long readline(const char *, char *, unsigned long);
void assign_to_unknown_var() {
- deadline_ = 1; // expected-error-re {{use of undeclared identifier 'deadline_'$}}
+ deadline_ = 1; // expected-error-re {{use of undeclared identifier 'deadline_'{{$}}}}
}
namespace no_ns_before_dot {
namespace re2 {}
void test() {
- req.set_check(false); // expected-error-re {{use of undeclared identifier 'req'$}}
+ req.set_check(false); // expected-error-re {{use of undeclared identifier 'req'{{$}}}}
}
}
int flibberdy(); // expected-note{{'flibberdy' declared here}}
int no_correction() {
return hibberdy() + // expected-error{{use of undeclared identifier 'hibberdy'; did you mean 'flibberdy'?}}
- gibberdy(); // expected-error-re{{use of undeclared identifier 'gibberdy'$}}
+ gibberdy(); // expected-error-re{{use of undeclared identifier 'gibberdy'{{$}}}}
};
}
struct Data {};
}
- std::ostream &print(std::ostream &out, int); // expected-note-re {{should be declared prior to the call site$}}
+ std::ostream &print(std::ostream &out, int); // expected-note-re {{should be declared prior to the call site{{$}}}}
std::ostream &print(std::ostream &out, ns::Data); // expected-note {{should be declared prior to the call site or in namespace 'PR10053::my_file2_a::ns'}}
std::ostream &print(std::ostream &out, std::vector<ns2::Data>); // expected-note {{should be declared prior to the call site or in namespace 'PR10053::my_file2_a::ns2'}}
std::ostream &print(std::ostream &out, std::pair<ns::Data, ns2::Data>); // expected-note {{should be declared prior to the call site or in an associated namespace of one of its arguments}}
struct X {};
};
using size_t = decltype(sizeof(0));
-void *operator new(size_t, OperatorNew::X); // expected-note-re {{should be declared prior to the call site$}}
+void *operator new(size_t, OperatorNew::X); // expected-note-re {{should be declared prior to the call site{{$}}}}
template void OperatorNew::f(OperatorNew::X); // expected-note {{instantiation of}}
};
template struct B<A>;
-template struct C<A>; // expected-note-re 1+ {{in instantiation of member function 'PR16014::C<PR16014::A>::.*' requested here}}
+template struct C<A>; // expected-note-re 1+ {{in instantiation of member function 'PR16014::C<PR16014::A>::{{.*}}' requested here}}
template <typename T> struct D : T {
struct Inner {
void foo() {
pair<ExampleItemSet::iterator, int> i; // expected-error {{template argument for template type parameter must be a type; did you forget 'typename'?}}
- pair<this->ExampleItemSet::iterator, int> i; // expected-error-re {{template argument for template type parameter must be a type$}}
- pair<ExampleItemSet::operator[], int> i; // expected-error-re {{template argument for template type parameter must be a type$}}
+ pair<this->ExampleItemSet::iterator, int> i; // expected-error-re {{template argument for template type parameter must be a type{{$}}}}
+ pair<ExampleItemSet::operator[], int> i; // expected-error-re {{template argument for template type parameter must be a type{{$}}}}
}
pair<ExampleItemSet::iterator, int> elt; // expected-error {{template argument for template type parameter must be a type; did you forget 'typename'?}}