From: Fariborz Jahanian Date: Mon, 30 Apr 2012 23:20:30 +0000 (+0000) Subject: modern objective-c translator. named aggregate types X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8fba894335b979e6d213c685bca959168c1f2182;p=clang 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 5cd6836cc3..6d79263d45 100644 --- a/lib/Rewrite/RewriteModernObjC.cpp +++ b/lib/Rewrite/RewriteModernObjC.cpp @@ -109,7 +109,7 @@ namespace { llvm::SmallPtrSet ObjCSynthesizedStructs; llvm::SmallPtrSet ObjCSynthesizedProtocols; llvm::SmallPtrSet ObjCWrittenInterfaces; - llvm::SmallPtrSet TagsDefinedInIvarDecls; + llvm::SmallPtrSet GlobalDefinedTags; SmallVector ObjCInterfacesSeen; /// DefinedNonLazyClasses - List of defined "non-lazy" classes. SmallVector DefinedNonLazyClasses; @@ -346,6 +346,10 @@ namespace { 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 @@ bool RewriteModernObjC::BufferContainsPPDirectives(const char *startBuf, 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(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(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 @@ bool RewriteModernObjC::RewriteObjCFieldDeclType(QualType &Type, 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 @@ bool RewriteModernObjC::RewriteObjCFieldDeclType(QualType &Type, 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 @@ void RewriteModernObjC::RewriteObjCFieldDecl(FieldDecl *fieldDecl, 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(fieldDecl->getDeclContext()); + + TagDecl *TD = 0; + if (Type->isRecordType()) { + TD = Type->getAs()->getDecl(); + } + else if (Type->isEnumeralType()) { + TD = Type->getAs()->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 @@ void RewriteModernObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl, 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 @@ void RewriteModernObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl, 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 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) { if (IvarT->isRecordType()) { RecordDecl *RD = IvarT->getAs()->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 0000000000..6599236e71 --- /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 376d300c7e..f05d8091d0 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 4a137aeff6..bb6098c268 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 @@ struct S { @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;