r186971 - Add new diagnostic messages when too many arguments are presented to a
Richard Trieu
rtrieu at google.com
Tue Jul 23 11:01:49 PDT 2013
Author: rtrieu
Date: Tue Jul 23 13:01:49 2013
New Revision: 186971
URL: http://llvm.org/viewvc/llvm-project?rev=186971&view=rev
Log:
Add new diagnostic messages when too many arguments are presented to a
function-like macro. Clang will attempt to correct the arguments by detecting
braced initializer lists:
1) If possible, suggest parentheses around arguments
containing braced lists which will give the proper number of arguments.
2) If a braced list is detected at the start of a macro argument, it cannot be
corrected by parentheses. Instead, just point out the location of these
braced lists.
Added:
cfe/trunk/test/Preprocessor/macro_with_initializer_list.cpp
Modified:
cfe/trunk/include/clang/Basic/Diagnostic.h
cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
cfe/trunk/lib/Lex/PPMacroExpansion.cpp
cfe/trunk/test/Preprocessor/macro_fn.c
Modified: cfe/trunk/include/clang/Basic/Diagnostic.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Diagnostic.h?rev=186971&r1=186970&r2=186971&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Diagnostic.h (original)
+++ cfe/trunk/include/clang/Basic/Diagnostic.h Tue Jul 23 13:01:49 2013
@@ -990,6 +990,10 @@ public:
bool hasMaxRanges() const {
return NumRanges == DiagnosticsEngine::MaxRanges;
}
+
+ bool hasMaxFixItHints() const {
+ return NumFixits == DiagnosticsEngine::MaxFixItHints;
+ }
};
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
Modified: cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td?rev=186971&r1=186970&r2=186971&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td Tue Jul 23 13:01:49 2013
@@ -460,6 +460,11 @@ def err_unterm_macro_invoc : Error<
"unterminated function-like macro invocation">;
def err_too_many_args_in_macro_invoc : Error<
"too many arguments provided to function-like macro invocation">;
+def note_suggest_parens_for_macro : Note<
+ "parentheses are required around macro argument containing braced "
+ "initializer list">;
+def note_init_list_at_beginning_of_macro_argument : Note<
+ "cannot use initializer list at the beginning of an macro argument">;
def err_too_few_args_in_macro_invoc : Error<
"too few arguments provided to function-like macro invocation">;
def err_pp_bad_paste : Error<
Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=186971&r1=186970&r2=186971&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original)
+++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Tue Jul 23 13:01:49 2013
@@ -390,6 +390,136 @@ bool Preprocessor::HandleMacroExpandedId
return false;
}
+enum Bracket {
+ Brace,
+ Paren
+};
+
+/// CheckMatchedBrackets - Returns true if the braces and parentheses in the
+/// token vector are properly nested.
+static bool CheckMatchedBrackets(const SmallVectorImpl<Token> &Tokens) {
+ SmallVector<Bracket, 8> Brackets;
+ for (SmallVectorImpl<Token>::const_iterator I = Tokens.begin(),
+ E = Tokens.end();
+ I != E; ++I) {
+ if (I->is(tok::l_paren)) {
+ Brackets.push_back(Paren);
+ } else if (I->is(tok::r_paren)) {
+ if (Brackets.empty() || Brackets.back() == Brace)
+ return false;
+ Brackets.pop_back();
+ } else if (I->is(tok::l_brace)) {
+ Brackets.push_back(Brace);
+ } else if (I->is(tok::r_brace)) {
+ if (Brackets.empty() || Brackets.back() == Paren)
+ return false;
+ Brackets.pop_back();
+ }
+ }
+ if (!Brackets.empty())
+ return false;
+ return true;
+}
+
+/// GenerateNewArgTokens - Returns true if OldTokens can be converted to a new
+/// vector of tokens in NewTokens. The new number of arguments will be placed
+/// in NumArgs and the ranges which need to surrounded in parentheses will be
+/// in ParenHints.
+/// Returns false if the token stream cannot be changed. If this is because
+/// of an initializer list starting a macro argument, the range of those
+/// initializer lists will be place in InitLists.
+static bool GenerateNewArgTokens(Preprocessor &PP,
+ SmallVectorImpl<Token> &OldTokens,
+ SmallVectorImpl<Token> &NewTokens,
+ unsigned &NumArgs,
+ SmallVectorImpl<SourceRange> &ParenHints,
+ SmallVectorImpl<SourceRange> &InitLists) {
+ if (!CheckMatchedBrackets(OldTokens))
+ return false;
+
+ // Once it is known that the brackets are matched, only a simple count of the
+ // braces is needed.
+ unsigned Braces = 0;
+
+ // First token of a new macro argument.
+ SmallVectorImpl<Token>::iterator ArgStartIterator = OldTokens.begin();
+
+ // First closing brace in a new macro argument. Used to generate
+ // SourceRanges for InitLists.
+ SmallVectorImpl<Token>::iterator ClosingBrace = OldTokens.end();
+ NumArgs = 0;
+ Token TempToken;
+ // Set to true when a macro separator token is found inside a braced list.
+ // If true, the fixed argument spans multiple old arguments and ParenHints
+ // will be updated.
+ bool FoundSeparatorToken = false;
+ for (SmallVectorImpl<Token>::iterator I = OldTokens.begin(),
+ E = OldTokens.end();
+ I != E; ++I) {
+ if (I->is(tok::l_brace)) {
+ ++Braces;
+ } else if (I->is(tok::r_brace)) {
+ --Braces;
+ if (Braces == 0 && ClosingBrace == E && FoundSeparatorToken)
+ ClosingBrace = I;
+ } else if (I->is(tok::eof)) {
+ // EOF token is used to separate macro arguments
+ if (Braces != 0) {
+ // Assume comma separator is actually braced list separator and change
+ // it back to a comma.
+ FoundSeparatorToken = true;
+ I->setKind(tok::comma);
+ I->setLength(1);
+ } else { // Braces == 0
+ // Separator token still separates arguments.
+ ++NumArgs;
+
+ // If the argument starts with a brace, it can't be fixed with
+ // parentheses. A different diagnostic will be given.
+ if (FoundSeparatorToken && ArgStartIterator->is(tok::l_brace)) {
+ InitLists.push_back(
+ SourceRange(ArgStartIterator->getLocation(),
+ PP.getLocForEndOfToken(ClosingBrace->getLocation())));
+ ClosingBrace = E;
+ }
+
+ // Add left paren
+ if (FoundSeparatorToken) {
+ TempToken.startToken();
+ TempToken.setKind(tok::l_paren);
+ TempToken.setLocation(ArgStartIterator->getLocation());
+ TempToken.setLength(0);
+ NewTokens.push_back(TempToken);
+ }
+
+ // Copy over argument tokens
+ NewTokens.insert(NewTokens.end(), ArgStartIterator, I);
+
+ // Add right paren and store the paren locations in ParenHints
+ if (FoundSeparatorToken) {
+ SourceLocation Loc = PP.getLocForEndOfToken((I - 1)->getLocation());
+ TempToken.startToken();
+ TempToken.setKind(tok::r_paren);
+ TempToken.setLocation(Loc);
+ TempToken.setLength(0);
+ NewTokens.push_back(TempToken);
+ ParenHints.push_back(SourceRange(ArgStartIterator->getLocation(),
+ Loc));
+ }
+
+ // Copy separator token
+ NewTokens.push_back(*I);
+
+ // Reset values
+ ArgStartIterator = I + 1;
+ FoundSeparatorToken = false;
+ }
+ }
+ }
+
+ return !ParenHints.empty() && InitLists.empty();
+}
+
/// ReadFunctionLikeMacroArgs - After reading "MACRO" and knowing that the next
/// token is the '(' of the macro, this method is invoked to read all of the
/// actual arguments specified for the macro invocation. This returns null on
@@ -415,6 +545,8 @@ MacroArgs *Preprocessor::ReadFunctionLik
SmallVector<Token, 64> ArgTokens;
bool ContainsCodeCompletionTok = false;
+ SourceLocation TooManyArgsLoc;
+
unsigned NumActuals = 0;
while (Tok.isNot(tok::r_paren)) {
if (ContainsCodeCompletionTok && (Tok.is(tok::eof) || Tok.is(tok::eod)))
@@ -504,22 +636,15 @@ MacroArgs *Preprocessor::ReadFunctionLik
// If this is not a variadic macro, and too many args were specified, emit
// an error.
- if (!isVariadic && NumFixedArgsLeft == 0) {
+ if (!isVariadic && NumFixedArgsLeft == 0 && TooManyArgsLoc.isInvalid()) {
if (ArgTokens.size() != ArgTokenStart)
- ArgStartLoc = ArgTokens[ArgTokenStart].getLocation();
-
- if (!ContainsCodeCompletionTok) {
- // Emit the diagnostic at the macro name in case there is a missing ).
- // Emitting it at the , could be far away from the macro name.
- Diag(ArgStartLoc, diag::err_too_many_args_in_macro_invoc);
- Diag(MI->getDefinitionLoc(), diag::note_macro_here)
- << MacroName.getIdentifierInfo();
- return 0;
- }
+ TooManyArgsLoc = ArgTokens[ArgTokenStart].getLocation();
+ else
+ TooManyArgsLoc = ArgStartLoc;
}
- // Empty arguments are standard in C99 and C++0x, and are supported as an extension in
- // other modes.
+ // Empty arguments are standard in C99 and C++0x, and are supported as an
+ // extension in other modes.
if (ArgTokens.size() == ArgTokenStart && !LangOpts.C99)
Diag(Tok, LangOpts.CPlusPlus11 ?
diag::warn_cxx98_compat_empty_fnmacro_arg :
@@ -533,16 +658,66 @@ MacroArgs *Preprocessor::ReadFunctionLik
EOFTok.setLength(0);
ArgTokens.push_back(EOFTok);
++NumActuals;
- if (!ContainsCodeCompletionTok || NumFixedArgsLeft != 0) {
- assert(NumFixedArgsLeft != 0 && "Too many arguments parsed");
+ if (!ContainsCodeCompletionTok && NumFixedArgsLeft != 0)
--NumFixedArgsLeft;
- }
}
// Okay, we either found the r_paren. Check to see if we parsed too few
// arguments.
unsigned MinArgsExpected = MI->getNumArgs();
+ // If this is not a variadic macro, and too many args were specified, emit
+ // an error.
+ if (!isVariadic && NumActuals > MinArgsExpected &&
+ !ContainsCodeCompletionTok) {
+ // Emit the diagnostic at the macro name in case there is a missing ).
+ // Emitting it at the , could be far away from the macro name.
+ Diag(TooManyArgsLoc, diag::err_too_many_args_in_macro_invoc);
+ Diag(MI->getDefinitionLoc(), diag::note_macro_here)
+ << MacroName.getIdentifierInfo();
+
+ // Commas from braced initializer lists will be treated as argument
+ // separators inside macros. Attempt to correct for this with parentheses.
+ // TODO: See if this can be generalized to angle brackets for templates
+ // inside macro arguments.
+
+ SmallVector<Token, 64> FixedArgTokens;
+ unsigned FixedNumArgs = 0;
+ SmallVector<SourceRange, 4> ParenHints, InitLists;
+ if (!GenerateNewArgTokens(*this, ArgTokens, FixedArgTokens, FixedNumArgs,
+ ParenHints, InitLists)) {
+ if (!InitLists.empty()) {
+ DiagnosticBuilder DB =
+ Diag(MacroName,
+ diag::note_init_list_at_beginning_of_macro_argument);
+ for (SmallVector<SourceRange, 4>::iterator
+ Range = InitLists.begin(), RangeEnd = InitLists.end();
+ Range != RangeEnd; ++Range) {
+ if (DB.hasMaxRanges())
+ break;
+ DB << *Range;
+ }
+ }
+ return 0;
+ }
+ if (FixedNumArgs != MinArgsExpected)
+ return 0;
+
+ DiagnosticBuilder DB = Diag(MacroName, diag::note_suggest_parens_for_macro);
+ for (SmallVector<SourceRange, 4>::iterator
+ ParenLocation = ParenHints.begin(), ParenEnd = ParenHints.end();
+ ParenLocation != ParenEnd; ++ParenLocation) {
+ if (DB.hasMaxFixItHints())
+ break;
+ DB << FixItHint::CreateInsertion(ParenLocation->getBegin(), "(");
+ if (DB.hasMaxFixItHints())
+ break;
+ DB << FixItHint::CreateInsertion(ParenLocation->getEnd(), ")");
+ }
+ ArgTokens.swap(FixedArgTokens);
+ NumActuals = FixedNumArgs;
+ }
+
// See MacroArgs instance var for description of this.
bool isVarargsElided = false;
Modified: cfe/trunk/test/Preprocessor/macro_fn.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/macro_fn.c?rev=186971&r1=186970&r2=186971&view=diff
==============================================================================
--- cfe/trunk/test/Preprocessor/macro_fn.c (original)
+++ cfe/trunk/test/Preprocessor/macro_fn.c Tue Jul 23 13:01:49 2013
@@ -13,7 +13,8 @@ zero(1, 2, 3); /* expected-error {{to
one() /* ok */
one(a)
-one(a,) /* expected-error {{too many arguments provided to function-like macro invocation}} */
+one(a,) /* expected-error {{too many arguments provided to function-like macro invocation}} \
+ expected-warning {{empty macro arguments are a C99 feature}}*/
one(a, b) /* expected-error {{too many arguments provided to function-like macro invocation}} */
two() /* expected-error {{too few arguments provided to function-like macro invocation}} */
@@ -25,7 +26,7 @@ two(
, /* expected-warning {{empty macro arguments are a C99 feature}} */
, /* expected-warning {{empty macro arguments are a C99 feature}} \
expected-error {{too many arguments provided to function-like macro invocation}} */
- )
+ ) /* expected-warning {{empty macro arguments are a C99 feature}} */
two(,) /* expected-warning 2 {{empty macro arguments are a C99 feature}} */
Added: cfe/trunk/test/Preprocessor/macro_with_initializer_list.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/macro_with_initializer_list.cpp?rev=186971&view=auto
==============================================================================
--- cfe/trunk/test/Preprocessor/macro_with_initializer_list.cpp (added)
+++ cfe/trunk/test/Preprocessor/macro_with_initializer_list.cpp Tue Jul 23 13:01:49 2013
@@ -0,0 +1,182 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+namespace std {
+ template <class X>
+ class initializer_list {
+ public:
+ initializer_list();
+ };
+}
+
+class Foo {
+public:
+ Foo();
+ Foo(std::initializer_list<int>);
+ bool operator==(const Foo);
+ Foo operator+(const Foo);
+};
+
+#define EQ(x,y) (void)(x == y) // expected-note 6{{defined here}}
+void test_EQ() {
+ Foo F;
+ F = Foo{1,2};
+
+ EQ(F,F);
+ EQ(F,Foo());
+ EQ(F,Foo({1,2,3}));
+ EQ(Foo({1,2,3}),F);
+ EQ((Foo{1,2,3}),(Foo{1,2,3}));
+ EQ(F, F + F);
+ EQ(F, Foo({1,2,3}) + Foo({1,2,3}));
+ EQ(F, (Foo{1,2,3} + Foo{1,2,3}));
+
+ EQ(F,Foo{1,2,3});
+ // expected-error at -1 {{too many arguments provided}}
+ // expected-note at -2 {{parentheses are required}}
+ EQ(Foo{1,2,3},F);
+ // expected-error at -1 {{too many arguments provided}}
+ // expected-note at -2 {{parentheses are required}}
+ EQ(Foo{1,2,3},Foo{1,2,3});
+ // expected-error at -1 {{too many arguments provided}}
+ // expected-note at -2 {{parentheses are required}}
+
+ EQ(Foo{1,2,3} + Foo{1,2,3}, F);
+ // expected-error at -1 {{too many arguments provided}}
+ // expected-note at -2 {{parentheses are required}}
+ EQ(F, Foo({1,2,3}) + Foo{1,2,3});
+ // expected-error at -1 {{too many arguments provided}}
+ // expected-note at -2 {{parentheses are required}}
+ EQ(F, Foo{1,2,3} + Foo{1,2,3});
+ // expected-error at -1 {{too many arguments provided}}
+ // expected-note at -2 {{parentheses are required}}
+}
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{33:8-33:8}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{33:18-33:18}:")"
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{36:6-36:6}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{36:16-36:16}:")"
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{39:6-39:6}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{39:16-39:16}:")"
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{39:17-39:17}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{39:27-39:27}:")"
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{43:6-43:6}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{43:29-43:29}:")"
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{46:9-46:9}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{46:34-46:34}:")"
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{49:9-49:9}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{49:32-49:32}:")"
+
+#define NE(x,y) (void)(x != y) // expected-note 6{{defined here}}
+// Operator != isn't defined. This tests that the corrected macro arguments
+// are used in the macro expansion.
+void test_NE() {
+ Foo F;
+
+ NE(F,F);
+ // expected-error at -1 {{invalid operands}}
+ NE(F,Foo());
+ // expected-error at -1 {{invalid operands}}
+ NE(F,Foo({1,2,3}));
+ // expected-error at -1 {{invalid operands}}
+ NE((Foo{1,2,3}),(Foo{1,2,3}));
+ // expected-error at -1 {{invalid operands}}
+
+ NE(F,Foo{1,2,3});
+ // expected-error at -1 {{too many arguments provided}}
+ // expected-note at -2 {{parentheses are required}}
+ // expected-error at -3 {{invalid operands}}
+ NE(Foo{1,2,3},F);
+ // expected-error at -1 {{too many arguments provided}}
+ // expected-note at -2 {{parentheses are required}}
+ // expected-error at -3 {{invalid operands}}
+ NE(Foo{1,2,3},Foo{1,2,3});
+ // expected-error at -1 {{too many arguments provided}}
+ // expected-note at -2 {{parentheses are required}}
+ // expected-error at -3 {{invalid operands}}
+
+ NE(Foo{1,2,3} + Foo{1,2,3}, F);
+ // expected-error at -1 {{too many arguments provided}}
+ // expected-note at -2 {{parentheses are required}}
+ // expected-error at -3 {{invalid operands}}
+ NE(F, Foo({1,2,3}) + Foo{1,2,3});
+ // expected-error at -1 {{too many arguments provided}}
+ // expected-note at -2 {{parentheses are required}}
+ // expected-error at -3 {{invalid operands}}
+ NE(F, Foo{1,2,3} + Foo{1,2,3});
+ // expected-error at -1 {{too many arguments provided}}
+ // expected-note at -2 {{parentheses are required}}
+ // expected-error at -3 {{invalid operands}}
+}
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{89:8-89:8}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{89:18-89:18}:")"
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{93:6-93:6}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{93:16-93:16}:")"
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{97:6-97:6}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{97:16-97:16}:")"
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{97:17-97:17}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{97:27-97:27}:")"
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{102:6-102:6}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{102:29-102:29}:")"
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{106:9-106:9}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{106:34-106:34}:")"
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{110:9-110:9}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{110:32-110:32}:")"
+
+#define INIT(var, init) Foo var = init; // expected-note 3{{defined here}}
+// Can't use an initializer list as a macro argument. The commas in the list
+// will be interpretted as argument separaters and adding parenthesis will
+// make it no longer an initializer list.
+void test() {
+ INIT(a, Foo());
+ INIT(b, Foo({1, 2, 3}));
+ INIT(c, Foo());
+
+ INIT(d, Foo{1, 2, 3});
+ // expected-error at -1 {{too many arguments provided}}
+ // expected-note at -2 {{parentheses are required}}
+
+ // Can't be fixed by parentheses.
+ INIT(e, {1, 2, 3});
+ // expected-error at -1 {{too many arguments provided}}
+ // expected-error at -2 {{use of undeclared identifier}}
+ // expected-note at -3 {{cannot use initializer list at the beginning of an macro argument}}
+
+ // Can't be fixed by parentheses.
+ INIT(e, {1, 2, 3} + {1, 2, 3});
+ // expected-error at -1 {{too many arguments provided}}
+ // expected-error at -2 {{use of undeclared identifier}}
+ // expected-note at -3 {{cannot use initializer list at the beginning of an macro argument}}
+}
+
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{145:11-145:11}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{145:23-145:23}:")"
+
+#define M(name,a,b,c,d,e,f,g,h,i,j,k,l) \
+ Foo name = a + b + c + d + e + f + g + h + i + j + k + l;
+// expected-note at -2 2{{defined here}}
+void test2() {
+ M(F1, Foo(), Foo(), Foo(), Foo(), Foo(), Foo(),
+ Foo(), Foo(), Foo(), Foo(), Foo(), Foo());
+
+ M(F2, Foo{1,2,3}, Foo{1,2,3}, Foo{1,2,3}, Foo{1,2,3}, Foo{1,2,3}, Foo{1,2,3},
+ Foo{1,2,3}, Foo{1,2,3}, Foo{1,2,3}, Foo{1,2,3}, Foo{1,2,3}, Foo{1,2,3});
+ // expected-error at -2 {{too many arguments provided}}
+ // expected-note at -3 {{parentheses are required}}
+
+ M(F3, {1,2,3}, {1,2,3}, {1,2,3}, {1,2,3}, {1,2,3}, {1,2,3},
+ {1,2,3}, {1,2,3}, {1,2,3}, {1,2,3}, {1,2,3}, {1,2,3});
+ // expected-error at -2 {{too many arguments provided}}
+ // expected-error at -3 {{use of undeclared identifier}}
+ // expected-note at -4 {{cannot use initializer list at the beginning of an macro argument}}
+}
More information about the cfe-commits
mailing list