diff options
author | Kaelyn Uhrain <rikka@google.com> | 2012-05-02 00:11:40 +0000 |
---|---|---|
committer | Kaelyn Uhrain <rikka@google.com> | 2012-05-02 00:11:40 +0000 |
commit | 12f3297fbef1673b32c8987da9933687996c65b3 (patch) | |
tree | fca9fc0a5706ff1644ed0dd388c4f39d289f8ef8 | |
parent | 2a6e30d9ec947e26df55b4ea4eb5b583bb85ee96 (diff) |
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
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 114 | ||||
-rw-r--r-- | test/SemaCXX/decl-expr-ambiguity.cpp | 20 |
2 files changed, 90 insertions, 44 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index ac28221e94..184f166325 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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 @@ -748,7 +757,7 @@ Corrected: if (TypeDecl *Type = dyn_cast<TypeDecl>(FirstDecl)) { DiagnoseUseOfDecl(Type, NameLoc); QualType T = Context.getTypeDeclType(Type); - return ParsedType::make(T); + return ParsedType::make(T); } ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(FirstDecl); @@ -772,6 +781,23 @@ Corrected: QualType T = Context.getObjCInterfaceType(Class); 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); diff --git a/test/SemaCXX/decl-expr-ambiguity.cpp b/test/SemaCXX/decl-expr-ambiguity.cpp index 6f4d08cc68..ab1a2b5b95 100644 --- a/test/SemaCXX/decl-expr-ambiguity.cpp +++ b/test/SemaCXX/decl-expr-ambiguity.cpp @@ -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}} +} +} |