[cfe-commits] r132138 - in /cfe/trunk: include/clang/Basic/DiagnosticParseKinds.td include/clang/Parse/Parser.h lib/Parse/ParseDeclCXX.cpp test/Parser/nested-namespaces-recovery.cpp
Richard Trieu
rtrieu at google.com
Thu May 26 13:11:09 PDT 2011
Author: rtrieu
Date: Thu May 26 15:11:09 2011
New Revision: 132138
URL: http://llvm.org/viewvc/llvm-project?rev=132138&view=rev
Log:
Add a fix-it and better error recovery for improperly nested namespaces. This will give a better error message for cases such as "namespace foo::bar::baz {}" and a suggested fix-it of "namespace foo { namespace bar { namespace baz {} } }"
Added:
cfe/trunk/test/Parser/nested-namespaces-recovery.cpp
Modified:
cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
cfe/trunk/include/clang/Parse/Parser.h
cfe/trunk/lib/Parse/ParseDeclCXX.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=132138&r1=132137&r2=132138&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Thu May 26 15:11:09 2011
@@ -161,6 +161,8 @@
def err_inline_namespace_alias : Error<"namespace alias cannot be inline">;
def err_namespace_nonnamespace_scope : Error<
"namespaces can only be defined in global or namespace scope">;
+def err_nested_namespaces_with_double_colon : Error<
+ "nested namespace definition must define each namespace separately">;
def err_expected_semi_after_attribute_list : Error<
"expected ';' after attribute list">;
def err_expected_semi_after_static_assert : Error<
Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=132138&r1=132137&r2=132138&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Thu May 26 15:11:09 2011
@@ -1720,6 +1720,12 @@
Decl *ParseNamespace(unsigned Context, SourceLocation &DeclEnd,
SourceLocation InlineLoc = SourceLocation());
+ void ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc,
+ std::vector<IdentifierInfo*>& Ident,
+ std::vector<SourceLocation>& NamespaceLoc,
+ unsigned int index, SourceLocation& InlineLoc,
+ SourceLocation& LBrace, ParsedAttributes& attrs,
+ SourceLocation& RBraceLoc);
Decl *ParseLinkage(ParsingDeclSpec &DS, unsigned Context);
Decl *ParseUsingDirectiveOrDeclaration(unsigned Context,
const ParsedTemplateInfo &TemplateInfo,
Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=132138&r1=132137&r2=132138&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Thu May 26 15:11:09 2011
@@ -60,12 +60,20 @@
SourceLocation IdentLoc;
IdentifierInfo *Ident = 0;
+ std::vector<SourceLocation> ExtraIdentLoc;
+ std::vector<IdentifierInfo*> ExtraIdent;
+ std::vector<SourceLocation> ExtraNamespaceLoc;
Token attrTok;
if (Tok.is(tok::identifier)) {
Ident = Tok.getIdentifierInfo();
IdentLoc = ConsumeToken(); // eat the identifier.
+ while (Tok.is(tok::coloncolon) && NextToken().is(tok::identifier)) {
+ ExtraNamespaceLoc.push_back(ConsumeToken());
+ ExtraIdent.push_back(Tok.getIdentifierInfo());
+ ExtraIdentLoc.push_back(ConsumeToken());
+ }
}
// Read label attributes, if present.
@@ -85,7 +93,12 @@
return ParseNamespaceAlias(NamespaceLoc, IdentLoc, Ident, DeclEnd);
}
+
if (Tok.isNot(tok::l_brace)) {
+ if (!ExtraIdent.empty()) {
+ Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
+ << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
+ }
Diag(Tok, Ident ? diag::err_expected_lbrace :
diag::err_expected_ident_lbrace);
return 0;
@@ -96,11 +109,44 @@
if (getCurScope()->isClassScope() || getCurScope()->isTemplateParamScope() ||
getCurScope()->isInObjcMethodScope() || getCurScope()->getBlockParent() ||
getCurScope()->getFnParent()) {
+ if (!ExtraIdent.empty()) {
+ Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
+ << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
+ }
Diag(LBrace, diag::err_namespace_nonnamespace_scope);
SkipUntil(tok::r_brace, false);
return 0;
}
+ if (!ExtraIdent.empty()) {
+ TentativeParsingAction TPA(*this);
+ SkipUntil(tok::r_brace, /*StopAtSemi*/false, /*DontConsume*/true);
+ Token rBraceToken = Tok;
+ TPA.Revert();
+
+ if (!rBraceToken.is(tok::r_brace)) {
+ Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
+ << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
+ } else {
+
+ 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;
+ for (int i = 0; i < ExtraIdent.size(); ++i) {
+ RBraces += "} ";
+ }
+ Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
+ << FixItHint::CreateReplacement(SourceRange(ExtraNamespaceLoc.front(),
+ ExtraIdentLoc.back()),
+ NamespaceFix)
+ << FixItHint::CreateInsertion(rBraceToken.getLocation(), RBraces);
+ }
+ }
+
// If we're still good, complain about inline namespaces in non-C++0x now.
if (!getLang().CPlusPlus0x && InlineLoc.isValid())
Diag(InlineLoc, diag::ext_inline_namespace);
@@ -115,23 +161,56 @@
PrettyDeclStackTraceEntry CrashInfo(Actions, NamespcDecl, NamespaceLoc,
"parsing namespace");
- while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
- ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
- MaybeParseMicrosoftAttributes(attrs);
- ParseExternalDeclaration(attrs);
- }
+ SourceLocation RBraceLoc;
+ // Parse the contents of the namespace. This includes parsing recovery on
+ // any improperly nested namespaces.
+ ParseInnerNamespace(ExtraIdentLoc, ExtraIdent, ExtraNamespaceLoc, 0,
+ InlineLoc, LBrace, attrs, RBraceLoc);
// Leave the namespace scope.
NamespaceScope.Exit();
- SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBrace);
Actions.ActOnFinishNamespaceDef(NamespcDecl, RBraceLoc);
DeclEnd = RBraceLoc;
return NamespcDecl;
}
+/// ParseInnerNamespace - Parse the contents of a namespace.
+void Parser::ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc,
+ std::vector<IdentifierInfo*>& Ident,
+ std::vector<SourceLocation>& NamespaceLoc,
+ unsigned int index, SourceLocation& InlineLoc,
+ SourceLocation& LBrace,
+ ParsedAttributes& attrs,
+ SourceLocation& RBraceLoc) {
+ if (index == Ident.size()) {
+ while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+ ParsedAttributesWithRange attrs(AttrFactory);
+ MaybeParseCXX0XAttributes(attrs);
+ MaybeParseMicrosoftAttributes(attrs);
+ ParseExternalDeclaration(attrs);
+ }
+ RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBrace);
+
+ return;
+ }
+
+ // Parse improperly nested namespaces.
+ ParseScope NamespaceScope(this, Scope::DeclScope);
+ Decl *NamespcDecl =
+ Actions.ActOnStartNamespaceDef(getCurScope(), SourceLocation(),
+ NamespaceLoc[index], IdentLoc[index],
+ Ident[index], LBrace, attrs.getList());
+
+ ParseInnerNamespace(IdentLoc, Ident, NamespaceLoc, ++index, InlineLoc,
+ LBrace, attrs, RBraceLoc);
+
+ NamespaceScope.Exit();
+
+ Actions.ActOnFinishNamespaceDef(NamespcDecl, RBraceLoc);
+}
+
/// ParseNamespaceAlias - Parse the part after the '=' in a namespace
/// alias definition.
///
Added: cfe/trunk/test/Parser/nested-namespaces-recovery.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/nested-namespaces-recovery.cpp?rev=132138&view=auto
==============================================================================
--- cfe/trunk/test/Parser/nested-namespaces-recovery.cpp (added)
+++ cfe/trunk/test/Parser/nested-namespaces-recovery.cpp Thu May 26 15:11:09 2011
@@ -0,0 +1,24 @@
+// RUN: cp %s %t
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: not %clang_cc1 -x c++ -fixit %t
+// RUN: %clang_cc1 -x c++ %t
+
+namespace foo1::foo2::foo3 { // expected-error {{nested namespace definition must define each namespace separately}}
+ int foo(int x) { return x; }
+}
+
+int foo(int x) {
+ return foo1::foo2::foo3::foo(x);
+}
+
+namespace bar1 {
+ namespace bar2 {
+ namespace bar3 {
+ int bar(int x) { return x; }
+ }
+ }
+}
+
+int bar(int x) {
+ return bar1::bar2::bar3::bar(x);
+}
More information about the cfe-commits
mailing list