modern objective-c translator. named aggregate types
defined inside the objc class belong to class's
decl. scope. This is to conform to objective-c
rules. // rdar://11351299
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@155855 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Rewrite/RewriteModernObjC.cpp b/lib/Rewrite/RewriteModernObjC.cpp
index 5cd6836..6d79263 100644
--- a/lib/Rewrite/RewriteModernObjC.cpp
+++ b/lib/Rewrite/RewriteModernObjC.cpp
@@ -109,7 +109,7 @@
llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCSynthesizedStructs;
llvm::SmallPtrSet<ObjCProtocolDecl*, 8> ObjCSynthesizedProtocols;
llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCWrittenInterfaces;
- llvm::SmallPtrSet<TagDecl*, 8> TagsDefinedInIvarDecls;
+ llvm::SmallPtrSet<TagDecl*, 32> GlobalDefinedTags;
SmallVector<ObjCInterfaceDecl*, 32> ObjCInterfacesSeen;
/// DefinedNonLazyClasses - List of defined "non-lazy" classes.
SmallVector<ObjCInterfaceDecl*, 8> DefinedNonLazyClasses;
@@ -346,6 +346,10 @@
std::string &Result);
void RewriteObjCFieldDecl(FieldDecl *fieldDecl, std::string &Result);
+ bool IsTagDefinedInsideClass(ObjCInterfaceDecl *IDecl, TagDecl *Tag,
+ bool &IsNamedDefinition);
+ void RewriteLocallyDefinedNamedAggregates(FieldDecl *fieldDecl,
+ std::string &Result);
bool RewriteObjCFieldDeclType(QualType &Type, std::string &Result);
@@ -3494,18 +3498,31 @@
return false;
}
-static bool IsTagDefinedInsideClass(ASTContext *Context,
- ObjCInterfaceDecl *IDecl, TagDecl *Tag) {
+/// IsTagDefinedInsideClass - This routine checks that a named tagged type
+/// is defined inside an objective-c class. If so, it returns true.
+bool RewriteModernObjC::IsTagDefinedInsideClass(ObjCInterfaceDecl *IDecl,
+ TagDecl *Tag,
+ bool &IsNamedDefinition) {
if (!IDecl)
return false;
SourceLocation TagLocation;
if (RecordDecl *RD = dyn_cast<RecordDecl>(Tag)) {
RD = RD->getDefinition();
- if (!RD)
+ if (!RD || !RD->getDeclName().getAsIdentifierInfo())
return false;
+ IsNamedDefinition = true;
TagLocation = RD->getLocation();
return Context->getSourceManager().isBeforeInTranslationUnit(
- IDecl->getLocation(), TagLocation);
+ IDecl->getLocation(), TagLocation);
+ }
+ if (EnumDecl *ED = dyn_cast<EnumDecl>(Tag)) {
+ if (!ED || !ED->getDeclName().getAsIdentifierInfo())
+ return false;
+ IsNamedDefinition = true;
+ TagLocation = ED->getLocation();
+ return Context->getSourceManager().isBeforeInTranslationUnit(
+ IDecl->getLocation(), TagLocation);
+
}
return false;
}
@@ -3529,12 +3546,11 @@
assert(false && "class not allowed as an ivar type");
Result += RD->getName();
- if (TagsDefinedInIvarDecls.count(RD)) {
- // This struct is already defined. Do not write its definition again.
+ if (GlobalDefinedTags.count(RD)) {
+ // struct/union is defined globally, use it.
Result += " ";
return true;
}
- TagsDefinedInIvarDecls.insert(RD);
Result += " {\n";
for (RecordDecl::field_iterator i = RD->field_begin(),
e = RD->field_end(); i != e; ++i) {
@@ -3550,12 +3566,11 @@
if (ED->isCompleteDefinition()) {
Result += "\n\tenum ";
Result += ED->getName();
- if (TagsDefinedInIvarDecls.count(ED)) {
- // This enum is already defined. Do not write its definition again.
+ if (GlobalDefinedTags.count(ED)) {
+ // Enum is globall defined, use it.
Result += " ";
return true;
}
- TagsDefinedInIvarDecls.insert(ED);
Result += " {\n";
for (EnumDecl::enumerator_iterator EC = ED->enumerator_begin(),
@@ -3606,6 +3621,39 @@
Result += ";\n";
}
+/// RewriteLocallyDefinedNamedAggregates - This routine rewrites locally defined
+/// named aggregate types into the input buffer.
+void RewriteModernObjC::RewriteLocallyDefinedNamedAggregates(FieldDecl *fieldDecl,
+ std::string &Result) {
+ QualType Type = fieldDecl->getType();
+ if (Type->isArrayType())
+ Type = Context->getBaseElementType(Type);
+ ObjCInterfaceDecl *IDecl =
+ dyn_cast<ObjCInterfaceDecl>(fieldDecl->getDeclContext());
+
+ TagDecl *TD = 0;
+ if (Type->isRecordType()) {
+ TD = Type->getAs<RecordType>()->getDecl();
+ }
+ else if (Type->isEnumeralType()) {
+ TD = Type->getAs<EnumType>()->getDecl();
+ }
+
+ if (TD) {
+ if (GlobalDefinedTags.count(TD))
+ return;
+
+ bool IsNamedDefinition = false;
+ if (IsTagDefinedInsideClass(IDecl, TD, IsNamedDefinition)) {
+ RewriteObjCFieldDeclType(Type, Result);
+ Result += ";";
+ }
+ if (IsNamedDefinition)
+ GlobalDefinedTags.insert(TD);
+ }
+
+}
+
/// RewriteObjCInternalStruct - Rewrite one internal struct corresponding to
/// an objective-c class with ivars.
void RewriteModernObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl,
@@ -3634,6 +3682,12 @@
return;
}
+ // Insert named struct/union definitions inside class to
+ // outer scope. This follows semantics of locally defined
+ // struct/unions in objective-c classes.
+ for (unsigned i = 0, e = IVars.size(); i < e; i++)
+ RewriteLocallyDefinedNamedAggregates(IVars[i], Result);
+
Result += "\nstruct ";
Result += CDecl->getNameAsString();
Result += "_IMPL {\n";
@@ -3643,7 +3697,7 @@
Result += "_IMPL "; Result += RCDecl->getNameAsString();
Result += "_IVARS;\n";
}
- TagsDefinedInIvarDecls.clear();
+
for (unsigned i = 0, e = IVars.size(); i < e; i++)
RewriteObjCFieldDecl(IVars[i], Result);
@@ -7264,7 +7318,8 @@
if (IvarT->isRecordType()) {
RecordDecl *RD = IvarT->getAs<RecordType>()->getDecl();
- if (IsTagDefinedInsideClass(Context, iFaceDecl->getDecl(), RD)) {
+ RD = RD->getDefinition();
+ if (RD && !RD->getDeclName().getAsIdentifierInfo()) {
// decltype(((Foo_IMPL*)0)->bar) *
std::string RecName = iFaceDecl->getDecl()->getName();
RecName += "_IMPL";
diff --git a/test/Rewriter/rewrite-modern-ivar-access.mm b/test/Rewriter/rewrite-modern-ivar-access.mm
new file mode 100644
index 0000000..6599236
--- /dev/null
+++ b/test/Rewriter/rewrite-modern-ivar-access.mm
@@ -0,0 +1,101 @@
+// RUN: %clang_cc1 -fblocks -rewrite-objc -fms-extensions %s -o %t-rw.cpp
+// RUN: %clang_cc1 -Werror -fsyntax-only -Wno-address-of-temporary -Wno-c++11-narrowing -std=c++11 -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+
+// FIXME: It is incompatible to mingw due to __declspec.
+// XFAIL: mingw32
+
+struct OUTSIDE {
+ int i_OUTSIDE;
+ double d_OUTSIDE;
+};
+
+
+@interface I1 {
+@protected
+ struct OUTSIDE ivar_I1;
+
+ struct INNER_I1 {
+ int i_INNER_I1;
+ double d_INNER_I1;
+ };
+
+ struct INNER_I1 ivar_I2;
+
+ struct OUTSIDE ivar_I3;
+
+ struct {
+ int i_noname;
+ double d_noname;
+ } NONAME_I4;
+
+ struct {
+ int i_noname;
+ double d_noname;
+ } NONAME_I5;
+}
+@end
+
+@implementation I1
+- (void) I1_Meth {
+ ivar_I1.i_OUTSIDE = 0;
+
+ ivar_I2.i_INNER_I1 = 1;
+
+ ivar_I3.i_OUTSIDE = 2;
+
+ NONAME_I4.i_noname = 3;
+
+ NONAME_I5.i_noname = 4;
+}
+@end
+
+@interface INTF2 {
+@protected
+ struct OUTSIDE ivar_INTF2;
+
+ struct {
+ int i_noname;
+ double d_noname;
+ } NONAME_INTF4;
+
+
+ struct OUTSIDE ivar_INTF3;
+
+ struct INNER_I1 ivar_INTF4;
+
+ struct {
+ int i_noname;
+ double d_noname;
+ } NONAME_INTF5;
+
+ struct INNER_INTF2 {
+ int i_INNER_INTF2;
+ double d_INNER_INTF2;
+ };
+
+ struct INNER_INTF2 ivar_INTF6, ivar_INTF7;
+
+ struct INNER_INTF3 {
+ int i;
+ } X1,X2,X3;
+
+}
+@end
+
+@implementation INTF2
+- (void) I2_Meth {
+ ivar_INTF2.i_OUTSIDE = 0;
+
+ ivar_INTF4.i_INNER_I1 = 1;
+
+ ivar_INTF3.i_OUTSIDE = 2;
+
+ NONAME_INTF4.i_noname = 3;
+
+ NONAME_INTF5.i_noname = 4;
+ ivar_INTF6.i_INNER_INTF2 = 5;
+ ivar_INTF7.i_INNER_INTF2 = 5;
+ X1.i = X2.i = X3.i = 1;
+}
+@end
+
diff --git a/test/Rewriter/rewrite-modern-ivars-1.mm b/test/Rewriter/rewrite-modern-ivars-1.mm
index 376d300..f05d809 100644
--- a/test/Rewriter/rewrite-modern-ivars-1.mm
+++ b/test/Rewriter/rewrite-modern-ivars-1.mm
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
-// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -Werror -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
@interface NSCheapMutableString {
@private
@@ -87,3 +87,38 @@
}
@end
+enum OUTSIDE {
+ yes
+};
+
+@interface MoreEnumTests {
+@private
+ enum INSIDE {
+ no
+ } others;
+
+ enum OUTSIDE meetoo;
+
+ enum {
+ one,
+ two
+ } eu;
+}
+@end
+
+@interface I {
+ enum INSIDE I1;
+ enum OUTSIDE I2;
+ enum ALSO_INSIDE {
+ maybe
+ } I3;
+
+ enum ALSO_INSIDE I4;
+
+ enum {
+ three,
+ four
+ } I5;
+}
+@end
+
diff --git a/test/Rewriter/rewrite-modern-struct-ivar.mm b/test/Rewriter/rewrite-modern-struct-ivar.mm
index 4a137ae..bb6098c 100644
--- a/test/Rewriter/rewrite-modern-struct-ivar.mm
+++ b/test/Rewriter/rewrite-modern-struct-ivar.mm
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -E %s -o %t.mm
// RUN: %clang_cc1 -fblocks -rewrite-objc -fms-extensions %t.mm -o %t-rw.cpp
// RUN: FileCheck --input-file=%t-rw.cpp %s
-// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -Wno-c++11-narrowing -std=c++11 -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -Werror -Wno-address-of-temporary -Wno-c++11-narrowing -std=c++11 -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
struct S {
int i1;
@@ -49,4 +49,4 @@
@end
// CHECK: (*(decltype(((Foo_IMPL *)0U)->bar) *)((char *)self + OBJC_IVAR_$_Foo$bar)).x = 0;
-// CHECK: (*(decltype(((Foo_IMPL *)0U)->s) *)((char *)self + OBJC_IVAR_$_Foo$s)).x = 0;
+// CHECK: (*(struct _S *)((char *)self + OBJC_IVAR_$_Foo$s)).x = 0;