зеркало из https://github.com/microsoft/clang-1.git
Try harder to recognize hidden tag type names in potential declarations instead
of giving unhelpful errors about undeclared identifers and missing semicolons. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@155965 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
2a6e30d9ec
Коммит
12f3297fbe
|
@ -470,6 +470,55 @@ static bool isResultTypeOrTemplate(LookupResult &R, const Token &NextToken) {
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result,
|
||||
Scope *S, CXXScopeSpec &SS,
|
||||
IdentifierInfo *&Name,
|
||||
SourceLocation NameLoc) {
|
||||
Result.clear(Sema::LookupTagName);
|
||||
SemaRef.LookupParsedName(Result, S, &SS);
|
||||
if (TagDecl *Tag = Result.getAsSingle<TagDecl>()) {
|
||||
const char *TagName = 0;
|
||||
const char *FixItTagName = 0;
|
||||
switch (Tag->getTagKind()) {
|
||||
case TTK_Class:
|
||||
TagName = "class";
|
||||
FixItTagName = "class ";
|
||||
break;
|
||||
|
||||
case TTK_Enum:
|
||||
TagName = "enum";
|
||||
FixItTagName = "enum ";
|
||||
break;
|
||||
|
||||
case TTK_Struct:
|
||||
TagName = "struct";
|
||||
FixItTagName = "struct ";
|
||||
break;
|
||||
|
||||
case TTK_Union:
|
||||
TagName = "union";
|
||||
FixItTagName = "union ";
|
||||
break;
|
||||
}
|
||||
|
||||
SemaRef.Diag(NameLoc, diag::err_use_of_tag_name_without_tag)
|
||||
<< Name << TagName << SemaRef.getLangOpts().CPlusPlus
|
||||
<< FixItHint::CreateInsertion(NameLoc, FixItTagName);
|
||||
|
||||
LookupResult R(SemaRef, Name, NameLoc, Sema::LookupOrdinaryName);
|
||||
if (SemaRef.LookupParsedName(R, S, &SS)) {
|
||||
for (LookupResult::iterator I = R.begin(), IEnd = R.end();
|
||||
I != IEnd; ++I)
|
||||
SemaRef.Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type)
|
||||
<< Name << TagName;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Result.clear(Sema::LookupOrdinaryName);
|
||||
return false;
|
||||
}
|
||||
|
||||
Sema::NameClassification Sema::ClassifyName(Scope *S,
|
||||
CXXScopeSpec &SS,
|
||||
IdentifierInfo *&Name,
|
||||
|
@ -533,49 +582,9 @@ Corrected:
|
|||
// In C, we first see whether there is a tag type by the same name, in
|
||||
// which case it's likely that the user just forget to write "enum",
|
||||
// "struct", or "union".
|
||||
if (!getLangOpts().CPlusPlus && !SecondTry) {
|
||||
Result.clear(LookupTagName);
|
||||
LookupParsedName(Result, S, &SS);
|
||||
if (TagDecl *Tag = Result.getAsSingle<TagDecl>()) {
|
||||
const char *TagName = 0;
|
||||
const char *FixItTagName = 0;
|
||||
switch (Tag->getTagKind()) {
|
||||
case TTK_Class:
|
||||
TagName = "class";
|
||||
FixItTagName = "class ";
|
||||
break;
|
||||
|
||||
case TTK_Enum:
|
||||
TagName = "enum";
|
||||
FixItTagName = "enum ";
|
||||
break;
|
||||
|
||||
case TTK_Struct:
|
||||
TagName = "struct";
|
||||
FixItTagName = "struct ";
|
||||
break;
|
||||
|
||||
case TTK_Union:
|
||||
TagName = "union";
|
||||
FixItTagName = "union ";
|
||||
break;
|
||||
}
|
||||
|
||||
Diag(NameLoc, diag::err_use_of_tag_name_without_tag)
|
||||
<< Name << TagName << getLangOpts().CPlusPlus
|
||||
<< FixItHint::CreateInsertion(NameLoc, FixItTagName);
|
||||
|
||||
LookupResult R(*this, Name, NameLoc, LookupOrdinaryName);
|
||||
if (LookupParsedName(R, S, &SS)) {
|
||||
for (LookupResult::iterator I = R.begin(), IEnd = R.end();
|
||||
I != IEnd; ++I)
|
||||
Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type)
|
||||
<< Name << TagName;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Result.clear(LookupOrdinaryName);
|
||||
if (!getLangOpts().CPlusPlus && !SecondTry &&
|
||||
isTagTypeWithMissingTag(*this, Result, S, SS, Name, NameLoc)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Perform typo correction to determine if there is another name that is
|
||||
|
@ -773,6 +782,23 @@ Corrected:
|
|||
return ParsedType::make(T);
|
||||
}
|
||||
|
||||
// Check for a tag type hidden by a non-type decl in a few cases where it
|
||||
// seems likely a type is wanted instead of the non-type that was found.
|
||||
if (!getLangOpts().ObjC1 && FirstDecl && !isa<ClassTemplateDecl>(FirstDecl) &&
|
||||
!isa<TypeAliasTemplateDecl>(FirstDecl)) {
|
||||
bool NextIsOp = NextToken.is(tok::amp) || NextToken.is(tok::star);
|
||||
if ((NextToken.is(tok::identifier) ||
|
||||
(NextIsOp && FirstDecl->isFunctionOrFunctionTemplate())) &&
|
||||
isTagTypeWithMissingTag(*this, Result, S, SS, Name, NameLoc)) {
|
||||
FirstDecl = (*Result.begin())->getUnderlyingDecl();
|
||||
if (TypeDecl *Type = dyn_cast<TypeDecl>(FirstDecl)) {
|
||||
DiagnoseUseOfDecl(Type, NameLoc);
|
||||
QualType T = Context.getTypeDeclType(Type);
|
||||
return ParsedType::make(T);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!Result.empty() && (*Result.begin())->isCXXClassMember())
|
||||
return BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result, 0);
|
||||
|
||||
|
|
|
@ -70,3 +70,23 @@ void foo() {
|
|||
fn(1); // expected-error {{no matching function}}
|
||||
fn(g); // OK
|
||||
}
|
||||
|
||||
namespace PR11874 {
|
||||
void foo(); // expected-note 3 {{class 'foo' is hidden by a non-type declaration of 'foo' here}}
|
||||
class foo {};
|
||||
class bar {
|
||||
bar() {
|
||||
const foo* f1 = 0; // expected-error {{must use 'class' tag to refer to type 'foo' in this scope}}
|
||||
foo* f2 = 0; // expected-error {{must use 'class' tag to refer to type 'foo' in this scope}}
|
||||
foo f3; // expected-error {{must use 'class' tag to refer to type 'foo' in this scope}}
|
||||
}
|
||||
};
|
||||
|
||||
int baz; // expected-note 2 {{class 'baz' is hidden by a non-type declaration of 'baz' here}}
|
||||
class baz {};
|
||||
void fizbin() {
|
||||
const baz* b1 = 0; // expected-error {{must use 'class' tag to refer to type 'baz' in this scope}}
|
||||
baz* b2; // expected-error {{use of undeclared identifier 'b2'}}
|
||||
baz b3; // expected-error {{must use 'class' tag to refer to type 'baz' in this scope}}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче