зеркало из https://github.com/microsoft/clang.git
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 {} } }"
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@132138 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
f13654600b
Коммит
f858bd817e
|
@ -161,6 +161,8 @@ def err_unexpected_namespace_attributes_alias : Error<
|
|||
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<
|
||||
|
|
|
@ -1720,6 +1720,12 @@ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
|
|||
|
||||
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,
|
||||
|
|
|
@ -60,12 +60,20 @@ Decl *Parser::ParseNamespace(unsigned Context,
|
|||
|
||||
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 @@ Decl *Parser::ParseNamespace(unsigned Context,
|
|||
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 @@ Decl *Parser::ParseNamespace(unsigned Context,
|
|||
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 @@ Decl *Parser::ParseNamespace(unsigned Context,
|
|||
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.
|
||||
///
|
||||
|
|
|
@ -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);
|
||||
}
|
Загрузка…
Ссылка в новой задаче