]> granicus.if.org Git - clang/commitdiff
Try harder to recognize hidden tag type names in potential declarations instead
authorKaelyn Uhrain <rikka@google.com>
Wed, 2 May 2012 00:11:40 +0000 (00:11 +0000)
committerKaelyn Uhrain <rikka@google.com>
Wed, 2 May 2012 00:11:40 +0000 (00:11 +0000)
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

lib/Sema/SemaDecl.cpp
test/SemaCXX/decl-expr-ambiguity.cpp

index ac28221e940fc5f6235564913a0e916622827eca..184f166325e79ac555b389e00fce6f4863d63976 100644 (file)
@@ -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);
index 6f4d08cc686cbf4be9ccfc12bfae0736b95850c9..ab1a2b5b9583fb6c5919cb6ad1b3cc6ebde6f79d 100644 (file)
@@ -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}}
+}
+}