On May 19, 2011, at 4:14 PM, Richard Trieu wrote:

> 
> 
> On Sat, May 7, 2011 at 9:59 AM, Douglas Gregor <[email protected]> wrote:
> 
> On May 6, 2011, at 6:57 PM, Richard Trieu wrote:
> 
>> Moved fix-its from the notes to the error message.
>> 
>> On Fri, May 6, 2011 at 2:20 PM, Richard Trieu <[email protected]> wrote:
>> When improperly using "::" to nest namespaces, give a fix-it to correct it.  
>> Parsing will also recover as if they were properly nested.
>> 
>> namespace foo::bar {
>> }
>> 
>> Will result in a fix-it at "::" to change to " { namespace " and an 
>> additional right bracket at the end.
>> 
>> Patch attached and available through Code Review:
>> http://codereview.appspot.com/4452052/
> 
> +    // Unless we have "namepsace foo::bar {", just complain about a lack of 
> '{'.
> 
> Typo "namepsace".
> 
> +    if (!Tok.is(tok::coloncolon) || !NextToken().is(tok::identifier)) {
> +      Diag(Tok, Ident ? diag::err_expected_lbrace :
> +           diag::err_expected_ident_lbrace);
> +      return 0;
> +    }
> 
> +    // Otherwise, recover parsing as if the user had typed
> +    // "namespace foo { namespace bar {".
> +    TentativeParsingAction TPA(*this);
> +    SkipUntil(tok::l_brace, /*StopAtSemi*/false);
> +    SkipUntil(tok::r_brace, /*StopAtSemi*/false, /*DontConsume*/true);
> +    Token rBraceToken = Tok;
> +    rBraceToken.setKind(tok::r_brace);
> +    PP.EnterToken(rBraceToken);
> +    TPA.Revert();
> 
> IMO, this isn't robust enough for a Fix-It, because it isn't actually 
> checking for the presence of the '{' or the '}'. For example, if the 
> "namespace foo::bar" was at the end of the translation unit, it looks like we 
> could end up trying to change the end-of-file token to a right-brace.
> 
> I think it's fine to use tentative parsing here, but it should only be used 
> to identify where the '{' and '}' tokens are so we know that this could be a 
> well-formed namespace definition. Once we've figured that out, I'd prefer 
> that the code not try to change the token stream. Rather, I think it would be 
> better just to parse the
> 
>       namespace foo::bar {
>       
> and call the appropriate semantic actions to start the foo namespace, then 
> the bar namespace, and keep track of the results of each of those calls. 
> Then, when we see the closing '}', call the appropriate semantic actions to 
> complete those namespace definitions.
> 
> Also, this code is assuming that we're parsing something like
> 
>       namespace foo::bar {
>       }
> 
> but not
> 
>       namespace foo::bar::wibble {
>       }
> 
> Why not generalize it to an arbitrary-length identifier-and-:: definitions? 
> If this were a language feature, we'd want it to support an arbitrary depth.
> 
>       - Doug
> 
> Changed how the error recovery works.  Tentative parsing is still used to 
> locate the closing '}', but the token stream is no longer altered.  Instead 
> of an error for every nested namespace, only produce one error overall with 
> the fix-its.  Error message will also trigger, but without the fix-its, if 
> the namespace is not properly formed.  Arbitrary-length nested-namespaces are 
> now handled.

Great! Only two comments, then I think this patch can go in:

+      std::string NamespaceFix = "";
+      for (std::vector<IdentifierInfo*>::iterator I = ExtraIdent.begin(),
+           E = ExtraIdent.end(); I != E; ++I) {
+        NamespaceFix += " { namespace ";
+        NamespaceFix += (*I)->getName();
+      }
+      std::string RBraces(ExtraIdent.size(), '}');

It's just stylistic, but I'd prefer that that RBraces have spaces between each 
'}'.

+  // Parse improperly nested namespaces.
+  ParseScope NamespaceScope(this, Scope::DeclScope);
+  Decl *NamespcDecl =
+    Actions.ActOnStartNamespaceDef(getCurScope(), InlineLoc,
+                                   NamespaceLoc[index], IdentLoc[index],
+                                   Ident[index], LBrace, attrs.getList());

I think that InlineLoc should only be passed through for the innermost 
namespace, e.g., given

        inline namespace foo::bar {
        }

we should pass SourceLocation() for the location of "inline" for "foo", but 
pass InlineLoc for the location of "inline" for "bar".

Thanks for working on this!

        - Doug

_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to