From: Steve Naroff Date: Wed, 31 Oct 2007 18:42:27 +0000 (+0000) Subject: Implement a more sensible strategy for ObjC built-in types (addressing a long standin... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8ee529b5671295ea38c249df8b9d3766c905cfa7;p=clang Implement a more sensible strategy for ObjC built-in types (addressing a long standing FIXME in Sema::GetObjcIdType()). This removes several gross hacks to work around the previous "lazy" behavior. Two notes: - MinimalActions still needs to be taught about the built-in types (This breaks one of the -noop test cases). I started this, then added a FIXME. - I didn't convert Sema::GetObjcProtoType() yet. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@43567 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Lex/Preprocessor.cpp b/Lex/Preprocessor.cpp index c1f4970f30..0d3ac521d0 100644 --- a/Lex/Preprocessor.cpp +++ b/Lex/Preprocessor.cpp @@ -369,33 +369,7 @@ static void InitializePredefinedMacros(Preprocessor &PP, DefineBuiltinMacro(Buf, "__OBJC__=1"); if (PP.getLangOptions().ObjC2) DefineBuiltinMacro(Buf, "__OBJC2__=1"); - if (PP.getLangOptions().ObjC1) { - const char *ObjcType; - // Predefine all the ObjC goodies (traditionally declared in ). - // We define the following header guard for source compatibility. It has - // the effect of ignoring any explicit inclusion of :-) - DefineBuiltinMacro(Buf, "_OBJC_OBJC_H_=1"); - DefineBuiltinMacro(Buf, "OBJC_EXPORT=extern"); - DefineBuiltinMacro(Buf, "OBJC_IMPORT=extern"); - ObjcType = "typedef struct objc_class *Class;\n"; - Buf.insert(Buf.end(), ObjcType, ObjcType+strlen(ObjcType)); - ObjcType = "typedef struct objc_object { Class isa; } *id;\n"; - Buf.insert(Buf.end(), ObjcType, ObjcType+strlen(ObjcType)); - ObjcType = "typedef struct objc_selector *SEL;\n"; - Buf.insert(Buf.end(), ObjcType, ObjcType+strlen(ObjcType)); - ObjcType = "typedef id (*IMP)(id, SEL, ...);\n"; - Buf.insert(Buf.end(), ObjcType, ObjcType+strlen(ObjcType)); - ObjcType = "typedef signed char BOOL;\n"; - Buf.insert(Buf.end(), ObjcType, ObjcType+strlen(ObjcType)); - DefineBuiltinMacro(Buf, "YES=(BOOL)1"); - DefineBuiltinMacro(Buf, "NO=(BOOL)0"); - DefineBuiltinMacro(Buf, "Nil=0"); - DefineBuiltinMacro(Buf, "nil=0"); - ObjcType = "extern const char *sel_getName(SEL sel);\n"; - Buf.insert(Buf.end(), ObjcType, ObjcType+strlen(ObjcType)); - ObjcType = "extern SEL sel_getUid(const char *str);\n"; - Buf.insert(Buf.end(), ObjcType, ObjcType+strlen(ObjcType)); - } + // Add __builtin_va_list typedef. { const char *VAList = PP.getTargetInfo().getVAListDeclaration(); diff --git a/Parse/MinimalAction.cpp b/Parse/MinimalAction.cpp index d439141322..bc7c41bec3 100644 --- a/Parse/MinimalAction.cpp +++ b/Parse/MinimalAction.cpp @@ -28,6 +28,11 @@ struct TypeNameInfo { } }; +void MinimalAction:: ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { + TUScope = S; + // FIXME: add id/SEL/Class. We need to get our paws on the identifier table. +} + /// isTypeName - This looks at the IdentifierInfo::FETokenInfo field to /// determine whether the name is a type name (objc class name or typedef) or /// not in this scope. diff --git a/Sema/Sema.cpp b/Sema/Sema.cpp index 92d17e1e99..323483586b 100644 --- a/Sema/Sema.cpp +++ b/Sema/Sema.cpp @@ -16,54 +16,35 @@ #include "clang/AST/ASTContext.h" #include "clang/Lex/Preprocessor.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Parse/Scope.h" using namespace clang; -void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { - TUScope = S; +bool Sema::isBuiltinObjcType(TypedefDecl *TD) { + const char *typeName = TD->getIdentifier()->getName(); + return strcmp(typeName, "id") == 0 || strcmp(typeName, "Class") == 0 || + strcmp(typeName, "SEL") == 0; } -/// GetObjcIdType - The following method assumes that "id" is imported -/// via . This is the way GCC worked for almost 20 years. -/// In GCC 4.0, "id" is now a built-in type. Unfortunately, typedefs *cannot* be -/// redefined (even if they are identical). To allow a built-in types to coexist -/// with , GCC has a special hack on decls (DECL_IN_SYSTEM_HEADER). -/// For now, we will *not* install id as a built-in. FIXME: reconsider this. -QualType Sema::GetObjcIdType(SourceLocation Loc) { - assert(TUScope && "GetObjcIdType(): Top-level scope is null"); - if (!Context.getObjcIdType().isNull()) - return Context.getObjcIdType(); +void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { + TUScope = S; + if (PP.getLangOptions().ObjC1) { + TypedefType *t; - IdentifierInfo *IdIdent = &Context.Idents.get("id"); - ScopedDecl *IdDecl = LookupScopedDecl(IdIdent, Decl::IDNS_Ordinary, - SourceLocation(), TUScope); - TypedefDecl *ObjcIdTypedef = dyn_cast_or_null(IdDecl); - if (!ObjcIdTypedef) { - Diag(Loc, diag::err_missing_id_definition); - return QualType(); + // Add the built-in ObjC types. + t = dyn_cast(Context.getObjcIdType().getTypePtr()); + t->getDecl()->getIdentifier()->setFETokenInfo(t->getDecl()); + TUScope->AddDecl(t->getDecl()); + t = dyn_cast(Context.getObjcClassType().getTypePtr()); + t->getDecl()->getIdentifier()->setFETokenInfo(t->getDecl()); + TUScope->AddDecl(t->getDecl()); + t = dyn_cast(Context.getObjcSelType().getTypePtr()); + t->getDecl()->getIdentifier()->setFETokenInfo(t->getDecl()); + TUScope->AddDecl(t->getDecl()); } - Context.setObjcIdType(ObjcIdTypedef); - return Context.getObjcIdType(); -} - -/// GetObjcSelType - See comments for Sema::GetObjcIdType above; replace "id" -/// with "SEL". -QualType Sema::GetObjcSelType(SourceLocation Loc) { - assert(TUScope && "GetObjcSelType(): Top-level scope is null"); - if (Context.getObjcSelType().isNull()) { - IdentifierInfo *SelIdent = &Context.Idents.get("SEL"); - ScopedDecl *SelDecl = LookupScopedDecl(SelIdent, Decl::IDNS_Ordinary, - SourceLocation(), TUScope); - TypedefDecl *ObjcSelTypedef = dyn_cast_or_null(SelDecl); - if (!ObjcSelTypedef) { - Diag(Loc, diag::err_missing_sel_definition); - return QualType(); - } - Context.setObjcSelType(ObjcSelTypedef); - } - return Context.getObjcSelType(); } +/// FIXME: remove this. /// GetObjcProtoType - See comments for Sema::GetObjcIdType above; replace "id" /// with "Protocol". QualType Sema::GetObjcProtoType(SourceLocation Loc) { @@ -82,25 +63,6 @@ QualType Sema::GetObjcProtoType(SourceLocation Loc) { return Context.getObjcProtoType(); } -/// GetObjcClassType - See comments for Sema::GetObjcIdType above; replace "id" -/// with "Protocol". -QualType Sema::GetObjcClassType(SourceLocation Loc) { - assert(TUScope && "GetObjcClassType(): Top-level scope is null"); - if (!Context.getObjcClassType().isNull()) - return Context.getObjcClassType(); - - IdentifierInfo *ClassIdent = &Context.Idents.get("Class"); - ScopedDecl *ClassDecl = LookupScopedDecl(ClassIdent, Decl::IDNS_Ordinary, - SourceLocation(), TUScope); - TypedefDecl *ObjcClassTypedef = dyn_cast_or_null(ClassDecl); - if (!ObjcClassTypedef) { - Diag(Loc, diag::err_missing_class_definition); - return QualType(); - } - Context.setObjcClassType(ObjcClassTypedef); - return Context.getObjcClassType(); -} - Sema::Sema(Preprocessor &pp, ASTContext &ctxt, std::vector &prevInGroup) : PP(pp), Context(ctxt), CurFunctionDecl(0), LastInGroupList(prevInGroup) { @@ -118,7 +80,38 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, std::vector &prevInGroup) KnownFunctionIDs[ id_vfprintf ] = &IT.get("vfprintf"); KnownFunctionIDs[ id_vsprintf ] = &IT.get("vsprintf"); KnownFunctionIDs[ id_vprintf ] = &IT.get("vprintf"); - + + if (PP.getLangOptions().ObjC1) { + // Synthesize "typedef struct objc_class *Class;" + RecordDecl *ClassTag = new RecordDecl(Decl::Struct, SourceLocation(), + &IT.get("objc_class"), 0); + QualType ClassT = Context.getPointerType(Context.getTagDeclType(ClassTag)); + TypedefDecl *ClassTypedef = new TypedefDecl(SourceLocation(), + &Context.Idents.get("Class"), + ClassT, 0); + Context.setObjcClassType(ClassTypedef); + + // Synthesize "typedef struct objc_object { Class isa; } *id;" + RecordDecl *ObjectTag = new RecordDecl(Decl::Struct, SourceLocation(), + &IT.get("objc_object"), 0); + FieldDecl *IsaDecl = new FieldDecl(SourceLocation(), 0, + Context.getObjcClassType()); + ObjectTag->defineBody(&IsaDecl, 1); + QualType ObjT = Context.getPointerType(Context.getTagDeclType(ObjectTag)); + TypedefDecl *IdTypedef = new TypedefDecl(SourceLocation(), + &Context.Idents.get("id"), + ObjT, 0); + Context.setObjcIdType(IdTypedef); + + // Synthesize "typedef struct objc_selector *SEL;" + RecordDecl *SelTag = new RecordDecl(Decl::Struct, SourceLocation(), + &IT.get("objc_selector"), 0); + QualType SelT = Context.getPointerType(Context.getTagDeclType(SelTag)); + TypedefDecl *SelTypedef = new TypedefDecl(SourceLocation(), + &Context.Idents.get("SEL"), + SelT, 0); + Context.setObjcSelType(SelTypedef); + } TUScope = 0; } diff --git a/Sema/Sema.h b/Sema/Sema.h index 13ba636d52..3b8b5e98b3 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -275,17 +275,11 @@ private: bool MatchTwoMethodDeclarations(const ObjcMethodDecl *Method, const ObjcMethodDecl *PrevMethod); - /// GetObjcIdType - Getter for the build-in "id" type. - QualType GetObjcIdType(SourceLocation Loc = SourceLocation()); - - /// GetObjcSelType - Getter for the build-in "SEL" type. - QualType GetObjcSelType(SourceLocation Loc = SourceLocation()); - /// GetObjcSelType - Getter for the build-in "Protocol *" type. QualType GetObjcProtoType(SourceLocation Loc = SourceLocation()); - // GetObjcClassType - Getter for the built-in "Class" type. - QualType GetObjcClassType(SourceLocation Loc = SourceLocation()); + /// isBuiltinObjcType - Returns true of the type is "id", "SEL", "Class". + bool isBuiltinObjcType(TypedefDecl *TD); /// AddInstanceMethodToGlobalPool - All instance methods in a translation /// unit are added to a global pool. This allows us to efficiently associate diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index 32e5d12b3f..ea73db5088 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -25,6 +25,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/DenseSet.h" +#include "clang/Lex/Preprocessor.h" using namespace clang; Sema::DeclTy *Sema::isTypeName(const IdentifierInfo &II, Scope *S) const { @@ -210,6 +211,11 @@ TypedefDecl *Sema::MergeTypeDefDecl(TypedefDecl *New, ScopedDecl *OldD) { return New; } + // Allow multiple definitions for ObjC built-in typedefs. + // FIXME: Verify the underlying types are equivalent! + if (PP.getLangOptions().ObjC1 && isBuiltinObjcType(New)) + return Old; + // TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope. // TODO: This is totally simplistic. It should handle merging functions // together etc, merging extern int X; int X; ... @@ -1193,17 +1199,7 @@ Sema::DeclTy *Sema::ActOnStartCategoryImplementation( /// Check that class of this category is already completely declared. if (!IDecl || IDecl->isForwardDecl()) Diag(ClassLoc, diag::err_undef_interface, ClassName->getName()); - - // We cannot build type 'id' lazily. It is needed when checking if a - // type is an 'id' (via call to isObjcIdType) even if there is no - // need for the default 'id' type. - // FIXME: Depending on the need to compare to 'id', this may have to go - // somewhere else. At this time, this is a good enough place to do type - // encoding of methods and ivars for the rewrite client. - GetObjcIdType(AtCatImplLoc); - GetObjcClassType(AtCatImplLoc); - GetObjcSelType(AtCatImplLoc); - + /// TODO: Check that CatName, category name, is not used in another // implementation. return CDecl; @@ -1273,16 +1269,6 @@ Sema::DeclTy *Sema::ActOnStartClassImplementation( if (!ObjcImplementations.insert(ClassName)) Diag(ClassLoc, diag::err_dup_implementation_class, ClassName->getName()); - // We cannot build type 'id' laziliy. It is needed when checking if a - // type is an 'id' (via call to isObjcIdType) even if there is no - // need for the dafult 'id' type. - // FIXME: Depending on the need to compare to 'id', this may have to go - // somewhere else. At this time, this is a good enough place to do type - // encoding of methods and ivars for the rewrite client. - GetObjcIdType(AtClassImplLoc); - GetObjcClassType(AtClassImplLoc); - GetObjcSelType(AtClassImplLoc); - return IMPDecl; } @@ -1992,7 +1978,7 @@ Sema::DeclTy *Sema::ActOnMethodDeclaration( if (ArgTypes[i]) argType = QualType::getFromOpaquePtr(ArgTypes[i]); else - argType = GetObjcIdType(MethodLoc); + argType = Context.getObjcIdType(); ParmVarDecl* Param = new ParmVarDecl(SourceLocation(/*FIXME*/), ArgNames[i], argType, VarDecl::None, 0); Params.push_back(Param); @@ -2002,7 +1988,7 @@ Sema::DeclTy *Sema::ActOnMethodDeclaration( if (ReturnType) resultDeclType = QualType::getFromOpaquePtr(ReturnType); else // get the type for "id". - resultDeclType = GetObjcIdType(MethodLoc); + resultDeclType = Context.getObjcIdType(); ObjcMethodDecl* ObjcMethod = new ObjcMethodDecl(MethodLoc, EndLoc, Sel, resultDeclType, 0, -1, AttrList, diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index aac6ca3218..1eacd48f3d 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -1959,17 +1959,6 @@ Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc, SourceLocation RParenLoc) { QualType EncodedType = QualType::getFromOpaquePtr(Ty); - // We cannot build type 'id' lazily. It is needed when checking if a - // type is an 'id' (via call to isObjcIdType) even if there is no - // need for the default 'id' type. - // FIXME: Depending on the need to compare to 'id', this may have to go - // somewhere else. At this time, this is a good enough place to do type - // encoding of methods and ivars for the rewrite client. - // The same is true for the 'Class' and 'SEL' types. - GetObjcIdType(EncodeLoc); - GetObjcClassType(EncodeLoc); - GetObjcSelType(EncodeLoc); - QualType t = Context.getPointerType(Context.CharTy); return new ObjCEncodeExpr(t, EncodedType, AtLoc, RParenLoc); } @@ -1979,7 +1968,7 @@ Sema::ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, SourceLocation SelLoc, SourceLocation LParenLoc, SourceLocation RParenLoc) { - QualType t = GetObjcSelType(AtLoc); + QualType t = Context.getObjcSelType(); return new ObjCSelectorExpr(t, Sel, AtLoc, RParenLoc); } @@ -2076,7 +2065,7 @@ Sema::ExprResult Sema::ActOnClassMessage( if (!Method) { Diag(lbrac, diag::warn_method_not_found, std::string("+"), Sel.getName(), SourceRange(lbrac, rbrac)); - returnType = GetObjcIdType(); + returnType = Context.getObjcIdType(); } else { returnType = Method->getResultType(); if (Sel.getNumArgs()) { @@ -2084,7 +2073,6 @@ Sema::ExprResult Sema::ActOnClassMessage( return true; } } - GetObjcSelType(lbrac); // FIXME: a hack to install the sel type. return new ObjCMessageExpr(receiverName, Sel, returnType, lbrac, rbrac, ArgExprs); } @@ -2103,12 +2091,12 @@ Sema::ExprResult Sema::ActOnInstanceMessage( QualType receiverType = RExpr->getType(); QualType returnType; - if (receiverType == GetObjcIdType()) { + if (receiverType == Context.getObjcIdType()) { ObjcMethodDecl *Method = InstanceMethodPool[Sel].Method; if (!Method) { Diag(lbrac, diag::warn_method_not_found, std::string("-"), Sel.getName(), SourceRange(lbrac, rbrac)); - returnType = GetObjcIdType(); + returnType = Context.getObjcIdType(); } else { returnType = Method->getResultType(); if (Sel.getNumArgs()) @@ -2134,7 +2122,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage( if (!Method) { Diag(lbrac, diag::warn_method_not_found, std::string("-"), Sel.getName(), SourceRange(lbrac, rbrac)); - returnType = GetObjcIdType(); + returnType = Context.getObjcIdType(); } else { returnType = Method->getResultType(); if (Sel.getNumArgs()) @@ -2142,6 +2130,5 @@ Sema::ExprResult Sema::ActOnInstanceMessage( return true; } } - GetObjcSelType(lbrac); // FIXME: a hack to install the sel type. return new ObjCMessageExpr(RExpr, Sel, returnType, lbrac, rbrac, ArgExprs); } diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index fe4cf8d85b..de41b4628d 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -756,7 +756,6 @@ 08FB7793FE84155DC02AAC07 /* Project object */ = { isa = PBXProject; buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */; - compatibilityVersion = "Xcode 2.4"; hasScannedForEncodings = 1; mainGroup = 08FB7794FE84155DC02AAC07 /* clang */; projectDirPath = ""; diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 2097601c6b..43290f2add 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -645,9 +645,7 @@ public: /// ActOnPopScope - When a scope is popped, if any typedefs are now /// out-of-scope, they are removed from the IdentifierInfo::FETokenInfo field. virtual void ActOnPopScope(SourceLocation Loc, Scope *S); - virtual void ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { - TUScope = S; - } + virtual void ActOnTranslationUnitScope(SourceLocation Loc, Scope *S); virtual DeclTy *ActOnForwardClassDeclaration(SourceLocation AtClassLoc, IdentifierInfo **IdentList,