forked from OSchip/llvm-project
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. llvm-svn: 147436
This commit is contained in:
parent
7610e45910
commit
5dbf4eb66b
|
@ -1324,7 +1324,11 @@ public:
|
||||||
/// A type that can describe objects, but which lacks information needed to
|
/// 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
|
/// 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.
|
/// 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
|
/// isIncompleteOrObjectType - Return true if this is an incomplete or object
|
||||||
/// type, in other words, not a function type.
|
/// type, in other words, not a function type.
|
||||||
|
|
|
@ -5167,6 +5167,8 @@ def err_module_private_local : Error<
|
||||||
def err_module_private_local_class : Error<
|
def err_module_private_local_class : Error<
|
||||||
"local %select{struct|union|class|enum}0 cannot be declared "
|
"local %select{struct|union|class|enum}0 cannot be declared "
|
||||||
"__module_private__">;
|
"__module_private__">;
|
||||||
|
def err_module_private_definition : Error<
|
||||||
|
"definition of %0 must be imported before it is required">;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end of sema component.
|
} // end of sema component.
|
||||||
|
|
|
@ -247,6 +247,12 @@ public:
|
||||||
/// This is only necessary for issuing pretty diagnostics.
|
/// This is only necessary for issuing pretty diagnostics.
|
||||||
ExtVectorDeclsType ExtVectorDecls;
|
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.
|
/// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes.
|
||||||
llvm::OwningPtr<CXXFieldCollector> FieldCollector;
|
llvm::OwningPtr<CXXFieldCollector> FieldCollector;
|
||||||
|
|
||||||
|
|
|
@ -897,37 +897,56 @@ bool Type::isConstantSizeType() const {
|
||||||
/// isIncompleteType - Return true if this is an incomplete type (C99 6.2.5p1)
|
/// 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
|
/// - a type that can describe objects, but which lacks information needed to
|
||||||
/// determine its size.
|
/// determine its size.
|
||||||
bool Type::isIncompleteType() const {
|
bool Type::isIncompleteType(NamedDecl **Def) const {
|
||||||
|
if (Def)
|
||||||
|
*Def = 0;
|
||||||
|
|
||||||
switch (CanonicalType->getTypeClass()) {
|
switch (CanonicalType->getTypeClass()) {
|
||||||
default: return false;
|
default: return false;
|
||||||
case Builtin:
|
case Builtin:
|
||||||
// Void is the only incomplete builtin type. Per C99 6.2.5p19, it can never
|
// Void is the only incomplete builtin type. Per C99 6.2.5p19, it can never
|
||||||
// be completed.
|
// be completed.
|
||||||
return isVoidType();
|
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).
|
// An enumeration with fixed underlying type is complete (C++0x 7.2p3).
|
||||||
if (cast<EnumType>(CanonicalType)->getDecl()->isFixed())
|
if (EnumD->isFixed())
|
||||||
return false;
|
return false;
|
||||||
// Fall through.
|
|
||||||
case Record:
|
return !EnumD->isCompleteDefinition();
|
||||||
|
}
|
||||||
|
case Record: {
|
||||||
// A tagged type (struct/union/enum/class) is incomplete if the decl is a
|
// 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).
|
// 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:
|
case ConstantArray:
|
||||||
// An array is incomplete if its element type is incomplete
|
// An array is incomplete if its element type is incomplete
|
||||||
// (C++ [dcl.array]p1).
|
// (C++ [dcl.array]p1).
|
||||||
// We don't handle variable arrays (they're not allowed in C++) or
|
// We don't handle variable arrays (they're not allowed in C++) or
|
||||||
// dependent-sized arrays (dependent types are never treated as incomplete).
|
// 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:
|
case IncompleteArray:
|
||||||
// An array of unknown size is an incomplete type (C99 6.2.5p22).
|
// An array of unknown size is an incomplete type (C99 6.2.5p22).
|
||||||
return true;
|
return true;
|
||||||
case ObjCObject:
|
case ObjCObject:
|
||||||
return cast<ObjCObjectType>(CanonicalType)->getBaseType()
|
return cast<ObjCObjectType>(CanonicalType)->getBaseType()
|
||||||
->isIncompleteType();
|
->isIncompleteType(Def);
|
||||||
case ObjCInterface:
|
case ObjCInterface: {
|
||||||
// ObjC interfaces are incomplete if they are @class, not @interface.
|
// 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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1084,6 +1084,11 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (RequireCompleteType(OpLoc, BaseType,
|
||||||
|
PDiag(diag::err_typecheck_incomplete_tag)
|
||||||
|
<< BaseExpr.get()->getSourceRange()))
|
||||||
|
return ExprError();
|
||||||
|
|
||||||
ObjCInterfaceDecl *ClassDeclared;
|
ObjCInterfaceDecl *ClassDeclared;
|
||||||
ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
|
ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "clang/Lex/Preprocessor.h"
|
#include "clang/Lex/Preprocessor.h"
|
||||||
#include "clang/Sema/DeclSpec.h"
|
#include "clang/Sema/DeclSpec.h"
|
||||||
#include "clang/Sema/DelayedDiagnostic.h"
|
#include "clang/Sema/DelayedDiagnostic.h"
|
||||||
|
#include "clang/Sema/Lookup.h"
|
||||||
#include "llvm/ADT/SmallPtrSet.h"
|
#include "llvm/ADT/SmallPtrSet.h"
|
||||||
#include "llvm/Support/ErrorHandling.h"
|
#include "llvm/Support/ErrorHandling.h"
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
|
@ -4059,8 +4060,23 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
|
||||||
// "Can't ask whether a dependent type is complete");
|
// "Can't ask whether a dependent type is complete");
|
||||||
|
|
||||||
// If we have a complete type, we're done.
|
// 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;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const TagType *Tag = T->getAs<TagType>();
|
const TagType *Tag = T->getAs<TagType>();
|
||||||
const ObjCInterfaceType *IFace = 0;
|
const ObjCInterfaceType *IFace = 0;
|
||||||
|
|
|
@ -1,4 +1,11 @@
|
||||||
@interface A
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@interface A {
|
||||||
|
@public
|
||||||
|
int ivar;
|
||||||
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
struct B {
|
struct B {
|
||||||
|
|
|
@ -1,15 +1,28 @@
|
||||||
// RUN: rm -rf %t
|
// RUN: rm -rf %t
|
||||||
// RUN: %clang_cc1 -I %S/Inputs -fmodule-cache-path %t %s -verify
|
// 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;
|
__import_module__ decldef;
|
||||||
A *a1; // expected-error{{unknown type name 'A'}}
|
A *a1; // expected-error{{unknown type name 'A'}}
|
||||||
B *b1; // expected-error{{unknown type name 'B'}}
|
B *b1; // expected-error{{unknown type name 'B'}}
|
||||||
|
|
||||||
__import_module__ decldef.Decl;
|
__import_module__ decldef.Decl;
|
||||||
|
|
||||||
A *a2;
|
A *a2;
|
||||||
B *b;
|
B *b;
|
||||||
|
|
||||||
void testB() {
|
void testA(A *a) {
|
||||||
B b; // FIXME: Should error, because we can't see the definition.
|
a->ivar = 17; // expected-error{{definition of 'A' must be imported before it is required}}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testB() {
|
||||||
|
B b; // expected-error{{definition of 'B' must be imported before it is required}}
|
||||||
|
B b2; // Note: the reundant error was silenced.
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue