diff options
author | Douglas Gregor <dgregor@apple.com> | 2013-02-09 01:35:03 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2013-02-09 01:35:03 +0000 |
commit | 6bd992946bda92193fadce7e4890d4465d2702f4 (patch) | |
tree | 3f4481d4238755cbddf2d8c767971a13e90458c7 /test | |
parent | f07e815823e03c046bbc186ec2b41d656e9cac7f (diff) |
Ensure that type definitions present in just-loaded modules are
visible.
The basic problem here is that a given translation unit can use
forward declarations to form pointers to a given type, say,
class X;
X *x;
and then import a module that includes a definition of X:
import XDef;
We will then fail when attempting to access a member of X, e.g.,
x->method()
because the AST reader did not know to look for a default of a class
named X within the new module.
This implementation is a bit of a C-centric hack, because the only
definitions that can have this property are enums, structs, unions,
Objective-C classes, and Objective-C protocols, and all of those are
either visible at the top-level or can't be defined later. Hence, we
can use the out-of-date-ness of the name and the identifier-update
mechanism to force the update.
In C++, we will not be so lucky, and will need a more advanced
solution, because the definitions could be in namespaces defined in
two different modules, e.g.,
// module 1
namespace N { struct X; }
// module 2
namespace N { struct X { /* ... */ }; }
One possible implementation here is for C++ to extend the information
associated with each identifier table to include the declaration IDs
of any definitions associated with that name, regardless of
context. We would have to eagerly load those definitions.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@174794 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test')
-rw-r--r-- | test/Modules/Inputs/def.h | 9 | ||||
-rw-r--r-- | test/Modules/decldef.m | 28 | ||||
-rw-r--r-- | test/Modules/decldef.mm | 19 |
3 files changed, 55 insertions, 1 deletions
diff --git a/test/Modules/Inputs/def.h b/test/Modules/Inputs/def.h index 6d06b08125..eb7eb7e59d 100644 --- a/test/Modules/Inputs/def.h +++ b/test/Modules/Inputs/def.h @@ -8,4 +8,13 @@ } @end +@interface Def +- defMethod; +@end +#ifdef __cplusplus +class Def2 { +public: + void func(); +}; +#endif diff --git a/test/Modules/decldef.m b/test/Modules/decldef.m new file mode 100644 index 0000000000..7fb8a61386 --- /dev/null +++ b/test/Modules/decldef.m @@ -0,0 +1,28 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodules -fobjc-arc -I %S/Inputs -fmodules-cache-path=%t %s -verify + + +// In other file: expected-note {{previous definition is here}} + +@class Def; +Def *def; + +@import decldef; +A *a1; // expected-error{{unknown type name 'A'}} +B *b1; // expected-error{{must use 'struct' tag to refer to type 'B'}} +@import decldef.Decl; + +A *a2; +struct B *b; + +void testA(A *a) { + a->ivar = 17; // expected-error{{definition of 'A' must be imported from module 'decldef.Def' before it is required}} +} + +void testB() { + B b; // Note: redundant error silenced +} + +void testDef() { + [def defMethod]; +} diff --git a/test/Modules/decldef.mm b/test/Modules/decldef.mm index 97ce72dd35..732c2a27e2 100644 --- a/test/Modules/decldef.mm +++ b/test/Modules/decldef.mm @@ -1,9 +1,18 @@ // RUN: rm -rf %t -// RUN: %clang_cc1 -fmodules -I %S/Inputs -fmodules-cache-path=%t %s -verify +// RUN: %clang_cc1 -fmodules -fobjc-arc -I %S/Inputs -fmodules-cache-path=%t %s -verify // In other file: expected-note {{previous definition is here}} +@class Def; +Def *def; +class Def2; +Def2 *def2; + +@interface Unrelated +- defMethod; +@end + @import decldef; A *a1; // expected-error{{unknown type name 'A'}} B *b1; // expected-error{{unknown type name 'B'}} @@ -19,3 +28,11 @@ void testA(A *a) { void testB() { B b; // Note: redundant error silenced } + +void testDef() { + [def defMethod]; +} + +void testDef2() { + def2->func(); +} |