aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2012-01-02 17:18:37 +0000
committerDouglas Gregor <dgregor@apple.com>2012-01-02 17:18:37 +0000
commitd07cc36c71558b62889691184dd04655a33fd12a (patch)
tree07e5864c73d5bf9fff8ff618ef6045e7be2c81e8
parentabf07a7fb669dcb74040eef948d61dfe3c59ff17 (diff)
Diagnose cases where the definition of a particular type is required,
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
-rw-r--r--include/clang/AST/Type.h6
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--include/clang/Sema/Sema.h6
-rw-r--r--lib/AST/Type.cpp41
-rw-r--r--lib/Sema/SemaExprMember.cpp5
-rw-r--r--lib/Sema/SemaType.cpp18
-rw-r--r--test/Modules/Inputs/def.h9
-rw-r--r--test/Modules/decldef.mm17
8 files changed, 88 insertions, 16 deletions
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 58a112cadf..c6ac71b104 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -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.
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index ff60e1bb61..d97dff633b 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -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.
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index cd401792b6..947e3fb374 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -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;
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index ddeeacd551..3c4845d85a 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -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();
+ }
}
}
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index 65e444915c..3e7f8314d5 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -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);
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 3cececb8c4..f4b82fc1cb 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -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;
diff --git a/test/Modules/Inputs/def.h b/test/Modules/Inputs/def.h
index c9bc36d61d..7c1a99ef7e 100644
--- a/test/Modules/Inputs/def.h
+++ b/test/Modules/Inputs/def.h
@@ -1,4 +1,11 @@
-@interface A
+
+
+
+
+@interface A {
+@public
+ int ivar;
+}
@end
struct B {
diff --git a/test/Modules/decldef.mm b/test/Modules/decldef.mm
index 3d24a0ef53..07499b31f7 100644
--- a/test/Modules/decldef.mm
+++ b/test/Modules/decldef.mm
@@ -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.
}