[PATCH] Better macro error messages involving initializer lists

Richard Smith richard at metafoo.co.uk
Mon Jul 1 16:33:21 PDT 2013


  This looks essentially reasonable (assuming the extra Token copying doesn't cause any measurable slowdown for preprocessor-intensive code -- there are some boost libraries that might be worth checking here).

  You need to rebase this patch; it will conflict with the MS ignored commas patch which landed last week.


================
Comment at: include/clang/Basic/DiagnosticLexKinds.td:463-464
@@ -462,1 +462,4 @@
   "too many arguments provided to function-like macro invocation">;
+def note_suggest_parens_for_macro : Note<
+  "braced lists require parenthesis to be recognized inside macros">;
+def note_cannot_use_init_list_as_macro_argument : Note<
----------------
This is ambiguous, and could be read as "braced lists require that parentheses are recognized inside macros". Maybe "parentheses are required around macro argument containing braced initializer list"?

================
Comment at: lib/Lex/PPMacroExpansion.cpp:447
@@ +446,3 @@
+  // Checks that braces and parens are properly nested.  If not, return.
+  SmallVector<bool, 8> IsParen;
+  for (SmallVector<Token, 64>::iterator TokenIterator = MacroTokens.begin(),
----------------
Using an enum for paren/brace instead of bool here would be clearer.

================
Comment at: lib/Lex/PPMacroExpansion.cpp:451-463
@@ +450,15 @@
+       TokenIterator != TokenEnd; ++TokenIterator) {
+    if (TokenIterator->is(tok::l_paren)) {
+      IsParen.push_back(true);
+    } else if (TokenIterator->is(tok::r_paren)) {
+      if (IsParen.empty() || !IsParen.back())
+        return 0;
+      IsParen.pop_back();
+    } else if (TokenIterator->is(tok::l_brace)) {
+      IsParen.push_back(false);
+    } else if (TokenIterator->is(tok::r_brace)) {
+      if (IsParen.empty() || IsParen.back())
+        return 0;
+      IsParen.pop_back();
+    }
+  }
----------------
Have you considered trying to also match angle-brackets if matching braces doesn't work? That would be useful for a number of template cases.

================
Comment at: lib/Lex/PPMacroExpansion.cpp:500
@@ +499,3 @@
+      // End of argument.
+      if (!FoundComma || !FoundBrace) {
+        CorrectedMacroTokens.insert(CorrectedMacroTokens.end(),
----------------
Do you need the FoundBrace check here? It looks like FoundComma implies FoundBrace, so you can remove the FoundBrace variable entirely.

================
Comment at: lib/Lex/PPMacroExpansion.cpp:469
@@ +468,3 @@
+  unsigned Braces = 0;
+  bool FoundComma = false;
+  bool FoundBrace = false;
----------------
Can you make this variable name more descriptive or add a comment? Something which more explicitly says that this tracks whether the current corrected argument includes a braced but unparenthesized comma.

================
Comment at: lib/Lex/PPMacroExpansion.cpp:503-506
@@ +502,6 @@
+                                    ArgStart, TokenIterator);
+      } else if (ArgStart->is(tok::l_brace) &&
+                 (TokenIterator - 1)->is(tok::r_brace)) {
+        InitLists.push_back(SourceRange(ArgStart->getLocation(),
+                                        (TokenIterator - 1)->getLocation()));
+      } else {
----------------
This note isn't appropriate if the argument is of the form "{...} stuff {...}". Perhaps you shouldn't give a note at all for that case?

================
Comment at: lib/Lex/PPMacroExpansion.cpp:510-513
@@ +509,6 @@
+                                         TokenIterator->getLocation()));
+        CorrectedMacroTokens.push_back(MacroTokens.front());
+        CorrectedMacroTokens.insert(CorrectedMacroTokens.end(),
+                                    ArgStart, TokenIterator);
+        CorrectedMacroTokens.push_back(MacroTokens.back());
+      }
----------------
Reusing MacroTokens.front() and MacroTokens.back() here will give surprising source locations. Perhaps put the ( at the location of the first token, and put the ) past the end of the location of the last token instead (that is, at the locations where you point the fix-its)?

================
Comment at: lib/Lex/PPMacroExpansion.cpp:512
@@ +511,3 @@
+        CorrectedMacroTokens.insert(CorrectedMacroTokens.end(),
+                                    ArgStart, TokenIterator);
+        CorrectedMacroTokens.push_back(MacroTokens.back());
----------------
The TokenIterator location here should really be the location past the end of the prior token. Imagine we had:

    MACRO(
      vector<int>{1, 2, 3}
    )

We'd want the ) suggested after the }, not before the ).

================
Comment at: lib/Lex/PPMacroExpansion.cpp:503-504
@@ +502,4 @@
+                                    ArgStart, TokenIterator);
+      } else if (ArgStart->is(tok::l_brace) &&
+                 (TokenIterator - 1)->is(tok::r_brace)) {
+        InitLists.push_back(SourceRange(ArgStart->getLocation(),
----------------
Richard Smith wrote:
> This note isn't appropriate if the argument is of the form "{...} stuff {...}". Perhaps you shouldn't give a note at all for that case?
The parens fix-up won't work in any case where the ArgStart is l_brace, no matter what the end token is. It's a shame that we don't recover well in this case; it'd be nice to treat the argument as a single item regardless, but the current factoring of the code makes that very hard.

Have you considered making this code directly produce MacroArgs instead (maybe performing these checks as a fixup after the handling in ProcessFunctionLikeMacroArgTokens), so that you can produce arguments with embedded commas? Alternatively, we now have the Token::IgnoredComma flag that you can use to indicate that a comma is not a macro argument separator; you could use that for recovery.


http://llvm-reviews.chandlerc.com/D986



More information about the cfe-commits mailing list