This is my first patch. It's targeted at the parser/diagnostics. The goal of the patch is to anticipate missing commas in initializer lists and report them appropriately as errors, instead of the current "expected '}' to match '}'" errors.
In summary, It detects missing commas only when successfully parsing the next element in the list. An example input/output pair are also attached for your convenience. Please inform me of any requested changes. Index: include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- include/clang/Basic/DiagnosticParseKinds.td (revision 301985) +++ include/clang/Basic/DiagnosticParseKinds.td (working copy) @@ -164,6 +164,7 @@ def err_at_defs_cxx : Error<"@defs is not supported in Objective-C++">; def err_at_in_class : Error<"unexpected '@' in member specification">; def err_unexpected_semi : Error<"unexpected ';' before %0">; +def err_expected_comma : Error<"expected ',' before initializer">; def err_expected_fn_body : Error< "expected function body after function declarator">; Index: include/clang/Parse/RAIIObjectsForParser.h =================================================================== --- include/clang/Parse/RAIIObjectsForParser.h (revision 301985) +++ include/clang/Parse/RAIIObjectsForParser.h (working copy) @@ -440,6 +440,13 @@ return diagnoseMissingClose(); } + + bool willClose(){ + if (P.Tok.is(Close)) + return false; + return true; + } + void skipToEnd(); }; Index: lib/Parse/ParseInit.cpp =================================================================== --- lib/Parse/ParseInit.cpp (revision 301985) +++ lib/Parse/ParseInit.cpp (working copy) @@ -409,6 +409,8 @@ Actions, EnterExpressionEvaluationContext::InitList); bool InitExprsOk = true; + bool maybeMissingComma = false; + Token startOfNextIni; while (1) { // Handle Microsoft __if_exists/if_not_exists if necessary. @@ -427,6 +429,8 @@ // If we know that this cannot be a designation, just parse the nested // initializer directly. ExprResult SubElt; + startOfNextIni = Tok; + if (MayBeDesignationStart()) SubElt = ParseInitializerWithPotentialDesignator(); else @@ -457,9 +461,25 @@ } } - // If we don't have a comma continued list, we're done. - if (Tok.isNot(tok::comma)) break; + if(maybeMissingComma){ + //Here we would have checked if InitExprsOk is true, + //but it's implied to be ok because of the previous break + //Now we know the compilee very likely forgot the comma + Diag(startOfNextIni.getLocation(), diag::err_expected_comma) + << FixItHint::CreateInsertion(startOfNextIni.getLocation().getLocWithOffset(-1), ","); + maybeMissingComma = false; + } + // If we don't have a comma continued list, we're done (maybe). + if (Tok.isNot(tok::comma)){ + if(!T.willClose()){ + //This is a ok list, no missing commas. + break; + } + maybeMissingComma = true; + continue; + } + // TODO: save comma locations if some client cares. ConsumeToken();
Index: include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- include/clang/Basic/DiagnosticParseKinds.td (revision 301985) +++ include/clang/Basic/DiagnosticParseKinds.td (working copy) @@ -164,6 +164,7 @@ def err_at_defs_cxx : Error<"@defs is not supported in Objective-C++">; def err_at_in_class : Error<"unexpected '@' in member specification">; def err_unexpected_semi : Error<"unexpected ';' before %0">; +def err_expected_comma : Error<"expected ',' before initializer">; def err_expected_fn_body : Error< "expected function body after function declarator">; Index: include/clang/Parse/RAIIObjectsForParser.h =================================================================== --- include/clang/Parse/RAIIObjectsForParser.h (revision 301985) +++ include/clang/Parse/RAIIObjectsForParser.h (working copy) @@ -440,6 +440,13 @@ return diagnoseMissingClose(); } + + bool willClose(){ + if (P.Tok.is(Close)) + return false; + return true; + } + void skipToEnd(); }; Index: lib/Parse/ParseInit.cpp =================================================================== --- lib/Parse/ParseInit.cpp (revision 301985) +++ lib/Parse/ParseInit.cpp (working copy) @@ -409,6 +409,8 @@ Actions, EnterExpressionEvaluationContext::InitList); bool InitExprsOk = true; + bool maybeMissingComma = false; + Token startOfNextIni; while (1) { // Handle Microsoft __if_exists/if_not_exists if necessary. @@ -427,6 +429,8 @@ // If we know that this cannot be a designation, just parse the nested // initializer directly. ExprResult SubElt; + startOfNextIni = Tok; + if (MayBeDesignationStart()) SubElt = ParseInitializerWithPotentialDesignator(); else @@ -457,9 +461,25 @@ } } - // If we don't have a comma continued list, we're done. - if (Tok.isNot(tok::comma)) break; + if(maybeMissingComma){ + //Here we would have checked if InitExprsOk is true, + //but it's implied to be ok because of the previous break + //Now we know the compilee very likely forgot the comma + Diag(startOfNextIni.getLocation(), diag::err_expected_comma) + << FixItHint::CreateInsertion(startOfNextIni.getLocation().getLocWithOffset(-1), ","); + maybeMissingComma = false; + } + // If we don't have a comma continued list, we're done (maybe). + if (Tok.isNot(tok::comma)){ + if(!T.willClose()){ + //This is a ok list, no missing commas. + break; + } + maybeMissingComma = true; + continue; + } + // TODO: save comma locations if some client cares. ConsumeToken();
int g(){ return 0; } int main(){ int a[] = {1 22222 33333, 4}; int b[] = {g() g()}; int c[3][3] = { {1 2 3}, {1,2 3} {1, 2, 3} }; int d[] = {1,2,3}; }
missingCommasDiag.out
Description: Binary data
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits