]> granicus.if.org Git - clang/commitdiff
Diagnose cases where the definition of a particular type is required,
authorDouglas Gregor <dgregor@apple.com>
Mon, 2 Jan 2012 17:18:37 +0000 (17:18 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 2 Jan 2012 17:18:37 +0000 (17:18 +0000)
is known (to Clang), but is not visible because the module has not yet
been imported.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147436 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Type.h
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/AST/Type.cpp
lib/Sema/SemaExprMember.cpp
lib/Sema/SemaType.cpp
test/Modules/Inputs/def.h
test/Modules/decldef.mm

index 58a112cadf1c92acf8fc4fe6e071d00abfa62a30..c6ac71b104aae3fbd78a4fe3f558a6383fbc2bae 100644 (file)
@@ -1324,7 +1324,11 @@ public:
   /// A type that can describe objects, but which lacks information needed to
   /// determine its size (e.g. void, or a fwd declared struct). Clients of this
   /// routine will need to determine if the size is actually required.
-  bool isIncompleteType() const;
+  ///
+  /// \brief Def If non-NULL, and the type refers to some kind of declaration
+  /// that can be completed (such as a C struct, C++ class, or Objective-C
+  /// class), will be set to the declaration.
+  bool isIncompleteType(NamedDecl **Def = 0) const;
 
   /// isIncompleteOrObjectType - Return true if this is an incomplete or object
   /// type, in other words, not a function type.
index ff60e1bb61b62cc63bf48d8dfcc64fa8417c9d59..d97dff633bf321ce3ce048bae449d55d8a2fa125 100644 (file)
@@ -5167,6 +5167,8 @@ def err_module_private_local : Error<
 def err_module_private_local_class : Error<
   "local %select{struct|union|class|enum}0 cannot be declared "
   "__module_private__">;
+def err_module_private_definition : Error<
+  "definition of %0 must be imported before it is required">;
 }
 
 } // end of sema component.
index cd401792b6f725a08560c6c88545bc3e5bb5cc3e..947e3fb37431ead597f55ff13767659f916bcdfc 100644 (file)
@@ -247,6 +247,12 @@ public:
   /// This is only necessary for issuing pretty diagnostics.
   ExtVectorDeclsType ExtVectorDecls;
 
+  /// \brief The set of types for which we have already complained about the
+  /// definitions being hidden.
+  ///
+  /// This set is used to suppress redundant diagnostics.
+  llvm::SmallPtrSet<NamedDecl *, 4> HiddenDefinitions;
+  
   /// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes.
   llvm::OwningPtr<CXXFieldCollector> FieldCollector;
 
index ddeeacd551e0a6948dcae415a019ec1b64b4d0b5..3c4845d85a3539f08a120d70b7b9248a412031ae 100644 (file)
@@ -897,37 +897,56 @@ bool Type::isConstantSizeType() const {
 /// isIncompleteType - Return true if this is an incomplete type (C99 6.2.5p1)
 /// - a type that can describe objects, but which lacks information needed to
 /// determine its size.
-bool Type::isIncompleteType() const {
+bool Type::isIncompleteType(NamedDecl **Def) const {
+  if (Def)
+    *Def = 0;
+  
   switch (CanonicalType->getTypeClass()) {
   default: return false;
   case Builtin:
     // Void is the only incomplete builtin type.  Per C99 6.2.5p19, it can never
     // be completed.
     return isVoidType();
-  case Enum:
+  case Enum: {
+    EnumDecl *EnumD = cast<EnumType>(CanonicalType)->getDecl();
+    if (Def)
+      *Def = EnumD;
+    
     // An enumeration with fixed underlying type is complete (C++0x 7.2p3).
-    if (cast<EnumType>(CanonicalType)->getDecl()->isFixed())
-        return false;
-    // Fall through.
-  case Record:
+    if (EnumD->isFixed())
+      return false;
+    
+    return !EnumD->isCompleteDefinition();
+  }
+  case Record: {
     // A tagged type (struct/union/enum/class) is incomplete if the decl is a
     // forward declaration, but not a full definition (C99 6.2.5p22).
-    return !cast<TagType>(CanonicalType)->getDecl()->isCompleteDefinition();
+    RecordDecl *Rec = cast<RecordType>(CanonicalType)->getDecl();
+    if (Def)
+      *Def = Rec;
+    return !Rec->isCompleteDefinition();
+  }
   case ConstantArray:
     // An array is incomplete if its element type is incomplete
     // (C++ [dcl.array]p1).
     // We don't handle variable arrays (they're not allowed in C++) or
     // dependent-sized arrays (dependent types are never treated as incomplete).
-    return cast<ArrayType>(CanonicalType)->getElementType()->isIncompleteType();
+    return cast<ArrayType>(CanonicalType)->getElementType()
+             ->isIncompleteType(Def);
   case IncompleteArray:
     // An array of unknown size is an incomplete type (C99 6.2.5p22).
     return true;
   case ObjCObject:
     return cast<ObjCObjectType>(CanonicalType)->getBaseType()
-                                                         ->isIncompleteType();
-  case ObjCInterface:
+             ->isIncompleteType(Def);
+  case ObjCInterface: {
     // ObjC interfaces are incomplete if they are @class, not @interface.
-    return !cast<ObjCInterfaceType>(CanonicalType)->getDecl()->hasDefinition();
+    ObjCInterfaceDecl *Interface
+      = cast<ObjCInterfaceType>(CanonicalType)->getDecl();
+    if (Def)
+      *Def = Interface;
+    return !Interface->hasDefinition();
+  }
   }
 }
 
index 65e444915c3a550604303953741be5183d3568b6..3e7f8314d5d09c4c3e5d5e62afc213085bee2f3a 100644 (file)
@@ -1084,6 +1084,11 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
       goto fail;
     }
 
+    if (RequireCompleteType(OpLoc, BaseType, 
+                            PDiag(diag::err_typecheck_incomplete_tag)
+                              << BaseExpr.get()->getSourceRange()))
+      return ExprError();
+    
     ObjCInterfaceDecl *ClassDeclared;
     ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
 
index 3cececb8c42f018e53cbe5e84cb8ab4be7b96c7d..f4b82fc1cb48230253671f4933396895233550b0 100644 (file)
@@ -27,6 +27,7 @@
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Sema/DeclSpec.h"
 #include "clang/Sema/DelayedDiagnostic.h"
+#include "clang/Sema/Lookup.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/Support/ErrorHandling.h"
 using namespace clang;
@@ -4059,8 +4060,23 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
   //         "Can't ask whether a dependent type is complete");
 
   // If we have a complete type, we're done.
-  if (!T->isIncompleteType())
+  NamedDecl *Def = 0;
+  if (!T->isIncompleteType(&Def)) {
+    // If we know about the definition but it is not visible, complain.
+    if (diag != 0 && Def && !LookupResult::isVisible(Def)) {
+      // Suppress this error outside of a SFINAE context if we've already
+      // emitted the error once for this type. There's no usefulness in 
+      // repeating the diagnostic.
+      // FIXME: Add a Fix-It that imports the corresponding module or includes
+      // the header.
+      if (isSFINAEContext() || HiddenDefinitions.insert(Def)) {
+        Diag(Loc, diag::err_module_private_definition) << T;
+        Diag(Def->getLocation(), diag::note_previous_definition);
+      }
+    }
+    
     return false;
+  }
 
   const TagType *Tag = T->getAs<TagType>();
   const ObjCInterfaceType *IFace = 0;
index c9bc36d61da79127824a904910b42a2d676a60c4..7c1a99ef7e62dcef1e31bf0a94cda275331b52a9 100644 (file)
@@ -1,4 +1,11 @@
-@interface A
+
+
+
+
+@interface A {
+@public
+  int ivar;
+}
 @end
 
 struct B {
index 3d24a0ef533f063a9ec2044d07e5372e484d2439..07499b31f7e13adea31b31b5d11dd5fc7a9aeaa2 100644 (file)
@@ -1,15 +1,28 @@
 // RUN: rm -rf %t
 // RUN: %clang_cc1 -I %S/Inputs -fmodule-cache-path %t %s -verify
 
+
+// in other file: expected-note{{previous definition is here}}
+
+
+
+
+
+// in other file: expected-note{{previous definition is here}}
+
 __import_module__ decldef;
 A *a1; // expected-error{{unknown type name 'A'}}
 B *b1; // expected-error{{unknown type name 'B'}}
-
 __import_module__ decldef.Decl;
 
 A *a2;
 B *b;
 
+void testA(A *a) {
+  a->ivar = 17; // expected-error{{definition of 'A' must be imported before it is required}}
+}
+
 void testB() {
-  B b; // FIXME: Should error, because we can't see the definition.
+  B b; // expected-error{{definition of 'B' must be imported before it is required}}
+  B b2; // Note: the reundant error was silenced.
 }