From: Douglas Gregor Date: Thu, 23 Apr 2009 22:29:11 +0000 (+0000) Subject: PCH support for all of the predefined Objective-C types, such as id, X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=319ac896a0fef7365d5589b8021db7e41207fe42;p=clang PCH support for all of the predefined Objective-C types, such as id, SEL, Class, Protocol, CFConstantString, and __objcFastEnumerationState. With this, we can now run the Objective-C methods and properties PCH tests. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69932 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index f49b56c62f..4379854c76 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -370,6 +370,15 @@ public: // constant CFStrings. QualType getCFConstantStringType(); + /// Get the structure type used to representation CFStrings, or NULL + /// if it hasn't yet been built. + QualType getRawCFConstantStringType() { + if (CFConstantStringTypeDecl) + return getTagDeclType(CFConstantStringTypeDecl); + return QualType(); + } + void setCFConstantStringType(QualType T); + // This setter/getter represents the ObjC type for an NSConstantString. void setObjCConstantStringInterface(ObjCInterfaceDecl *Decl); QualType getObjCConstantStringInterface() const { @@ -379,6 +388,16 @@ public: //// This gets the struct used to keep track of fast enumerations. QualType getObjCFastEnumerationStateType(); + /// Get the ObjCFastEnumerationState type, or NULL if it hasn't yet + /// been built. + QualType getRawObjCFastEnumerationStateType() { + if (ObjCFastEnumerationStateTypeDecl) + return getTagDeclType(ObjCFastEnumerationStateTypeDecl); + return QualType(); + } + + void setObjCFastEnumerationStateType(QualType T); + /// getObjCEncodingForType - Emit the ObjC type encoding for the /// given type into \arg S. If \arg NameFields is specified then /// record field names are also encoded. @@ -410,9 +429,9 @@ public: /// This setter/getter represents the ObjC 'id' type. It is setup lazily, by /// Sema. id is always a (typedef for a) pointer type, a pointer to a struct. QualType getObjCIdType() const { return ObjCIdType; } - void setObjCIdType(TypedefDecl *Decl); + void setObjCIdType(QualType T); - void setObjCSelType(TypedefDecl *Decl); + void setObjCSelType(QualType T); QualType getObjCSelType() const { return ObjCSelType; } void setObjCProtoType(QualType QT); @@ -422,7 +441,7 @@ public: /// Sema. 'Class' is always a (typedef for a) pointer type, a pointer to a /// struct. QualType getObjCClassType() const { return ObjCClassType; } - void setObjCClassType(TypedefDecl *Decl); + void setObjCClassType(QualType T); void setBuiltinVaListType(QualType T); QualType getBuiltinVaListType() const { return BuiltinVaListType; } diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h index 998b1109b4..c7c201ddd5 100644 --- a/include/clang/Frontend/PCHBitCodes.h +++ b/include/clang/Frontend/PCHBitCodes.h @@ -342,7 +342,19 @@ namespace clang { /// SPECIAL_TYPES record. enum SpecialTypeIDs { /// \brief __builtin_va_list - SPECIAL_TYPE_BUILTIN_VA_LIST = 0 + SPECIAL_TYPE_BUILTIN_VA_LIST = 0, + /// \brief Objective-C "id" type + SPECIAL_TYPE_OBJC_ID = 1, + /// \brief Objective-C selector type + SPECIAL_TYPE_OBJC_SELECTOR = 2, + /// \brief Objective-C Protocol type + SPECIAL_TYPE_OBJC_PROTOCOL = 3, + /// \brief Objective-C Class type + SPECIAL_TYPE_OBJC_CLASS = 4, + /// \brief CFConstantString type + SPECIAL_TYPE_CF_CONSTANT_STRING = 5, + /// \brief Objective-C fast enumeration state type + SPECIAL_TYPE_OBJC_FAST_ENUMERATION_STATE = 6 }; /// \brief Record codes for each kind of declaration. diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 3895b134f4..3466d7040d 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -2000,6 +2000,12 @@ QualType ASTContext::getCFConstantStringType() { return getTagDeclType(CFConstantStringTypeDecl); } +void ASTContext::setCFConstantStringType(QualType T) { + const RecordType *Rec = T->getAsRecordType(); + assert(Rec && "Invalid CFConstantStringType"); + CFConstantStringTypeDecl = Rec->getDecl(); +} + QualType ASTContext::getObjCFastEnumerationStateType() { if (!ObjCFastEnumerationStateTypeDecl) { @@ -2030,6 +2036,12 @@ QualType ASTContext::getObjCFastEnumerationStateType() return getTagDeclType(ObjCFastEnumerationStateTypeDecl); } +void ASTContext::setObjCFastEnumerationStateType(QualType T) { + const RecordType *Rec = T->getAsRecordType(); + assert(Rec && "Invalid ObjCFAstEnumerationStateType"); + ObjCFastEnumerationStateTypeDecl = Rec->getDecl(); +} + // This returns true if a type has been typedefed to BOOL: // typedef BOOL; static bool isTypeTypedefedAsBOOL(QualType T) { @@ -2520,9 +2532,15 @@ void ASTContext::setBuiltinVaListType(QualType T) BuiltinVaListType = T; } -void ASTContext::setObjCIdType(TypedefDecl *TD) +void ASTContext::setObjCIdType(QualType T) { - ObjCIdType = getTypedefType(TD); + ObjCIdType = T; + + const TypedefType *TT = T->getAsTypedefType(); + if (!TT) + return; + + TypedefDecl *TD = TT->getDecl(); // typedef struct objc_object *id; const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType(); @@ -2536,9 +2554,14 @@ void ASTContext::setObjCIdType(TypedefDecl *TD) IdStructType = rec; } -void ASTContext::setObjCSelType(TypedefDecl *TD) +void ASTContext::setObjCSelType(QualType T) { - ObjCSelType = getTypedefType(TD); + ObjCSelType = T; + + const TypedefType *TT = T->getAsTypedefType(); + if (!TT) + return; + TypedefDecl *TD = TT->getDecl(); // typedef struct objc_selector *SEL; const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType(); @@ -2555,9 +2578,14 @@ void ASTContext::setObjCProtoType(QualType QT) ObjCProtoType = QT; } -void ASTContext::setObjCClassType(TypedefDecl *TD) +void ASTContext::setObjCClassType(QualType T) { - ObjCClassType = getTypedefType(TD); + ObjCClassType = T; + + const TypedefType *TT = T->getAsTypedefType(); + if (!TT) + return; + TypedefDecl *TD = TT->getDecl(); // typedef struct objc_class *Class; const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType(); diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index 5cc0aab5ee..15461bb99b 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -59,6 +59,11 @@ bool operator<(DeclarationName LHS, DeclarationName RHS) { } // end namespace clang DeclarationName::DeclarationName(Selector Sel) { + if (!Sel.getAsOpaquePtr()) { + Ptr = StoredObjCZeroArgSelector; + return; + } + switch (Sel.getNumArgs()) { case 0: Ptr = reinterpret_cast(Sel.getAsIdentifierInfo()); diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index d225c68392..2caab328d9 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -1948,7 +1948,19 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) { // Load the special types. Context.setBuiltinVaListType( GetType(SpecialTypes[pch::SPECIAL_TYPE_BUILTIN_VA_LIST])); - + if (unsigned Id = SpecialTypes[pch::SPECIAL_TYPE_OBJC_ID]) + Context.setObjCIdType(GetType(Id)); + if (unsigned Sel = SpecialTypes[pch::SPECIAL_TYPE_OBJC_SELECTOR]) + Context.setObjCSelType(GetType(Sel)); + if (unsigned Proto = SpecialTypes[pch::SPECIAL_TYPE_OBJC_PROTOCOL]) + Context.setObjCProtoType(GetType(Proto)); + if (unsigned Class = SpecialTypes[pch::SPECIAL_TYPE_OBJC_CLASS]) + Context.setObjCClassType(GetType(Class)); + if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_CF_CONSTANT_STRING]) + Context.setCFConstantStringType(GetType(String)); + if (unsigned FastEnum + = SpecialTypes[pch::SPECIAL_TYPE_OBJC_FAST_ENUMERATION_STATE]) + Context.setObjCFastEnumerationStateType(GetType(FastEnum)); // If we saw the preprocessor block, read it now. if (PreprocessorBlockOffset) { SavedStreamPosition SavedPos(Stream); diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 0c640e7b05..9a60625d1f 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -2105,6 +2105,12 @@ void PCHWriter::WritePCH(Sema &SemaRef) { // Write the record of special types. Record.clear(); AddTypeRef(Context.getBuiltinVaListType(), Record); + AddTypeRef(Context.getObjCIdType(), Record); + AddTypeRef(Context.getObjCSelType(), Record); + AddTypeRef(Context.getObjCProtoType(), Record); + AddTypeRef(Context.getObjCClassType(), Record); + AddTypeRef(Context.getRawCFConstantStringType(), Record); + AddTypeRef(Context.getRawObjCFastEnumerationStateType(), Record); Stream.EmitRecord(pch::SPECIAL_TYPES, Record); // Write the record containing external, unnamed definitions. diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index a5b30cc72a..3702c89cf6 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -110,46 +110,54 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { PushDeclContext(S, Context.getTranslationUnitDecl()); if (!PP.getLangOptions().ObjC1) return; - // Synthesize "typedef struct objc_selector *SEL;" - RecordDecl *SelTag = CreateStructDecl(Context, "objc_selector"); - PushOnScopeChains(SelTag, TUScope); + if (Context.getObjCSelType().isNull()) { + // Synthesize "typedef struct objc_selector *SEL;" + RecordDecl *SelTag = CreateStructDecl(Context, "objc_selector"); + PushOnScopeChains(SelTag, TUScope); - QualType SelT = Context.getPointerType(Context.getTagDeclType(SelTag)); - TypedefDecl *SelTypedef = TypedefDecl::Create(Context, CurContext, - SourceLocation(), - &Context.Idents.get("SEL"), - SelT); - PushOnScopeChains(SelTypedef, TUScope); - Context.setObjCSelType(SelTypedef); + QualType SelT = Context.getPointerType(Context.getTagDeclType(SelTag)); + TypedefDecl *SelTypedef = TypedefDecl::Create(Context, CurContext, + SourceLocation(), + &Context.Idents.get("SEL"), + SelT); + PushOnScopeChains(SelTypedef, TUScope); + Context.setObjCSelType(Context.getTypeDeclType(SelTypedef)); + } + + if (Context.getObjCClassType().isNull()) { + RecordDecl *ClassTag = CreateStructDecl(Context, "objc_class"); + QualType ClassT = Context.getPointerType(Context.getTagDeclType(ClassTag)); + TypedefDecl *ClassTypedef = + TypedefDecl::Create(Context, CurContext, SourceLocation(), + &Context.Idents.get("Class"), ClassT); + PushOnScopeChains(ClassTag, TUScope); + PushOnScopeChains(ClassTypedef, TUScope); + Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef)); + } - // FIXME: Make sure these don't leak! - RecordDecl *ClassTag = CreateStructDecl(Context, "objc_class"); - QualType ClassT = Context.getPointerType(Context.getTagDeclType(ClassTag)); - TypedefDecl *ClassTypedef = - TypedefDecl::Create(Context, CurContext, SourceLocation(), - &Context.Idents.get("Class"), ClassT); - PushOnScopeChains(ClassTag, TUScope); - PushOnScopeChains(ClassTypedef, TUScope); - Context.setObjCClassType(ClassTypedef); // Synthesize "@class Protocol; - ObjCInterfaceDecl *ProtocolDecl = - ObjCInterfaceDecl::Create(Context, CurContext, SourceLocation(), - &Context.Idents.get("Protocol"), - SourceLocation(), true); - Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl)); - PushOnScopeChains(ProtocolDecl, TUScope); - - // Synthesize "typedef struct objc_object { Class isa; } *id;" - RecordDecl *ObjectTag = CreateStructDecl(Context, "objc_object"); + if (Context.getObjCProtoType().isNull()) { + ObjCInterfaceDecl *ProtocolDecl = + ObjCInterfaceDecl::Create(Context, CurContext, SourceLocation(), + &Context.Idents.get("Protocol"), + SourceLocation(), true); + Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl)); + PushOnScopeChains(ProtocolDecl, TUScope); + } - QualType ObjT = Context.getPointerType(Context.getTagDeclType(ObjectTag)); - PushOnScopeChains(ObjectTag, TUScope); - TypedefDecl *IdTypedef = TypedefDecl::Create(Context, CurContext, - SourceLocation(), - &Context.Idents.get("id"), - ObjT); - PushOnScopeChains(IdTypedef, TUScope); - Context.setObjCIdType(IdTypedef); + // Synthesize "typedef struct objc_object { Class isa; } *id;" + if (Context.getObjCIdType().isNull()) { + RecordDecl *ObjectTag = CreateStructDecl(Context, "objc_object"); + + QualType ObjT = Context.getPointerType(Context.getTagDeclType(ObjectTag)); + PushOnScopeChains(ObjectTag, TUScope); + TypedefDecl *IdTypedef = TypedefDecl::Create(Context, CurContext, + SourceLocation(), + &Context.Idents.get("id"), + ObjT); + PushOnScopeChains(IdTypedef, TUScope); + Context.setObjCIdType(Context.getTypeDeclType(IdTypedef)); + } } Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index b3592086dd..e81e883272 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -473,19 +473,19 @@ bool Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { case 2: if (!TypeID->isStr("id")) break; - Context.setObjCIdType(New); + Context.setObjCIdType(Context.getTypeDeclType(New)); objc_types = true; break; case 5: if (!TypeID->isStr("Class")) break; - Context.setObjCClassType(New); + Context.setObjCClassType(Context.getTypeDeclType(New)); objc_types = true; return false; case 3: if (!TypeID->isStr("SEL")) break; - Context.setObjCSelType(New); + Context.setObjCSelType(Context.getTypeDeclType(New)); objc_types = true; return false; case 8: diff --git a/test/PCH/objc_methods.m b/test/PCH/objc_methods.m index 2122ff6061..1a198b18d3 100644 --- a/test/PCH/objc_methods.m +++ b/test/PCH/objc_methods.m @@ -11,8 +11,6 @@ void func() { // FIXME: // AliasForTestPCH *zz; -#if 0 xx = [TestPCH alloc]; [xx instMethod]; -#endif } diff --git a/test/PCH/objc_property.m b/test/PCH/objc_property.m index 83bde783a3..5cf6de7593 100644 --- a/test/PCH/objc_property.m +++ b/test/PCH/objc_property.m @@ -1,9 +1,9 @@ // Test this without pch. -// FIXME: clang-cc -include %S/objc_property.h -fsyntax-only -verify %s && +// RUN: clang-cc -include %S/objc_property.h -fsyntax-only -verify %s && // Test with pch. -// FIXME: clang-cc -x=objective-c -emit-pch -o %t %S/objc_property.h && -// FIXME: clang-cc -include-pch %t -fsyntax-only -verify %s +// RUN: clang-cc -x=objective-c -emit-pch -o %t %S/objc_property.h && +// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s void func() { TestProperties *xx = [TestProperties alloc];