From: Steve Naroff Date: Wed, 27 Aug 2008 16:04:49 +0000 (+0000) Subject: First wave of changes to support "blocks" (an extension to C). X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5618bd4a52c45fbbb605e3ba885663b2164db8a3;p=clang First wave of changes to support "blocks" (an extension to C). This commit adds the declaration syntax (and associated type). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55417 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index c5976be1b4..1f9fec3c02 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -51,6 +51,7 @@ class ASTContext { llvm::FoldingSet ASQualTypes; llvm::FoldingSet ComplexTypes; llvm::FoldingSet PointerTypes; + llvm::FoldingSet BlockPointerTypes; llvm::FoldingSet ReferenceTypes; llvm::FoldingSet ConstantArrayTypes; llvm::FoldingSet IncompleteArrayTypes; @@ -162,6 +163,10 @@ public: /// getPointerType - Return the uniqued reference to the type for a pointer to /// the specified type. QualType getPointerType(QualType T); + + /// getBlockPointerType - Return the uniqued reference to the type for a block + /// of the specified type. + QualType getBlockPointerType(QualType T); /// getReferenceType - Return the uniqued reference to the type for a /// reference to the specified type. diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index f8c518acb9..2921132bec 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -42,6 +42,7 @@ namespace clang { class SourceLocation; class PointerLikeType; class PointerType; + class BlockPointerType; class ReferenceType; class VectorType; class ArrayType; @@ -239,7 +240,8 @@ public: TypeName, Tagged, ASQual, ObjCInterface, ObjCQualifiedInterface, ObjCQualifiedId, - TypeOfExp, TypeOfTyp // GNU typeof extension. + TypeOfExp, TypeOfTyp, // GNU typeof extension. + BlockPointer // C extension }; private: QualType CanonicalType; @@ -319,6 +321,7 @@ public: bool isFunctionType() const; bool isPointerLikeType() const; // Pointer or Reference. bool isPointerType() const; + bool isBlockPointerType() const; bool isReferenceType() const; bool isFunctionPointerType() const; bool isArrayType() const; @@ -344,6 +347,7 @@ public: const FunctionTypeProto *getAsFunctionTypeProto() const; const PointerLikeType *getAsPointerLikeType() const; // Pointer or Reference. const PointerType *getAsPointerType() const; + const BlockPointerType *getAsBlockPointerType() const; const ReferenceType *getAsReferenceType() const; const RecordType *getAsRecordType() const; const RecordType *getAsStructureType() const; @@ -568,6 +572,41 @@ protected: friend class Type; }; +/// BlockPointerType - pointer to a block type. +/// This type is to represent types syntactically represented as +/// "void (^)(int)", etc. Pointee is required to always be a function type. +/// +class BlockPointerType : public Type, public llvm::FoldingSetNode { + QualType PointeeType; // Block is some kind of pointer type + BlockPointerType(QualType Pointee, QualType CanonicalCls) : + Type(BlockPointer, CanonicalCls), PointeeType(Pointee) { + } + friend class ASTContext; // ASTContext creates these. +public: + + // Get the pointee type. Pointee is required to always be a function type. + QualType getPointeeType() const { return PointeeType; } + + virtual void getAsStringInternal(std::string &InnerString) const; + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getPointeeType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) { + ID.AddPointer(Pointee.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == BlockPointer; + } + static bool classof(const BlockPointerType *) { return true; } + + protected: + virtual void EmitImpl(llvm::Serializer& S) const; + static Type* CreateImpl(ASTContext& Context,llvm::Deserializer& D); + friend class Type; +}; + /// ReferenceType - C++ 8.3.2 - Reference Declarators. /// class ReferenceType : public PointerLikeType, public llvm::FoldingSetNode { @@ -1303,6 +1342,9 @@ inline bool Type::isFunctionType() const { inline bool Type::isPointerType() const { return isa(CanonicalType.getUnqualifiedType()); } +inline bool Type::isBlockPointerType() const { + return isa(CanonicalType); +} inline bool Type::isReferenceType() const { return isa(CanonicalType.getUnqualifiedType()); } diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 914434a7ef..f075a44143 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -859,6 +859,10 @@ DIAG(err_illegal_decl_pointer_to_reference, ERROR, "'%0' declared as a pointer to a reference") DIAG(err_illegal_decl_reference_to_reference, ERROR, "'%0' declared as a reference to a reference") +DIAG(err_qualified_block_pointer_type, ERROR, + "qualifier specification on block pointer type not allowed") +DIAG(err_nonfunction_block_type, ERROR, + "block pointer to non-function type is invalid") // Expressions. DIAG(ext_sizeof_function_type, EXTENSION, diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h index def23e6550..b1bdebabc4 100644 --- a/include/clang/Basic/LangOptions.h +++ b/include/clang/Basic/LangOptions.h @@ -48,6 +48,7 @@ struct LangOptions { unsigned ThreadsafeStatics : 1; // Whether static initializers are protected // by lockis. + unsigned Blocks : 1; // block extension to C private: unsigned GC : 2; // Objective-C Garbage Collection modes. We declare // this enum as unsigned because MSVC insists on making enums @@ -66,6 +67,7 @@ public: // FIXME: The default should be 1. ThreadsafeStatics = 0; + Blocks = 1; } GCMode getGCMode() const { return (GCMode) GC; } diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index f4690f8012..9edc649384 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -376,7 +376,7 @@ private: /// This is intended to be a small value object. struct DeclaratorChunk { enum { - Pointer, Reference, Array, Function + Pointer, Reference, Array, Function, BlockPointer } Kind; /// Loc - The place where this type was defined. @@ -455,12 +455,20 @@ struct DeclaratorChunk { delete[] ArgInfo; } }; - + + struct BlockPointerTypeInfo { + /// For now, sema will catch these as invalid. + /// The type qualifiers: const/volatile/restrict. + unsigned TypeQuals : 3; + void destroy() {} + }; + union { - PointerTypeInfo Ptr; - ReferenceTypeInfo Ref; - ArrayTypeInfo Arr; - FunctionTypeInfo Fun; + PointerTypeInfo Ptr; + ReferenceTypeInfo Ref; + ArrayTypeInfo Arr; + FunctionTypeInfo Fun; + BlockPointerTypeInfo Cls; }; @@ -535,6 +543,16 @@ struct DeclaratorChunk { } return I; } + /// getBlockPointer - Return a DeclaratorChunk for a block. + /// + static DeclaratorChunk getBlockPointer(unsigned TypeQuals, + SourceLocation Loc) { + DeclaratorChunk I; + I.Kind = BlockPointer; + I.Loc = Loc; + I.Cls.TypeQuals = TypeQuals; + return I; + } }; @@ -619,6 +637,8 @@ public: DeclTypeInfo[i].Fun.destroy(); else if (DeclTypeInfo[i].Kind == DeclaratorChunk::Pointer) DeclTypeInfo[i].Ptr.destroy(); + else if (DeclTypeInfo[i].Kind == DeclaratorChunk::BlockPointer) + DeclTypeInfo[i].Cls.destroy(); else if (DeclTypeInfo[i].Kind == DeclaratorChunk::Reference) DeclTypeInfo[i].Ref.destroy(); else if (DeclTypeInfo[i].Kind == DeclaratorChunk::Array) diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index bb8743babd..d17be725f5 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -610,6 +610,37 @@ QualType ASTContext::getPointerType(QualType T) { return QualType(New, 0); } +/// getBlockPointerType - Return the uniqued reference to the type for +/// a pointer to the specified block. +QualType ASTContext::getBlockPointerType(QualType T) { + assert(T->isFunctionType() && "closure of function types only"); + // Unique pointers, to guarantee there is only one closure of a particular + // structure. + llvm::FoldingSetNodeID ID; + BlockPointerType::Profile(ID, T); + + void *InsertPos = 0; + if (BlockPointerType *PT = + BlockPointerTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(PT, 0); + + // If the closure pointee type isn't canonical, this won't be a canonical + // type either so fill in the canonical type field. + QualType Canonical; + if (!T->isCanonical()) { + Canonical = getBlockPointerType(getCanonicalType(T)); + + // Get the new insert position for the node we care about. + BlockPointerType *NewIP = + BlockPointerTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); + } + BlockPointerType *New = new BlockPointerType(T, Canonical); + Types.push_back(New); + BlockPointerTypes.InsertNode(New, InsertPos); + return QualType(New, 0); +} + /// getReferenceType - Return the uniqued reference to the type for a reference /// to the specified type. QualType ASTContext::getReferenceType(QualType T) { diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 84b369ca30..2c5a3f41bf 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -231,6 +231,20 @@ const PointerType *Type::getAsPointerType() const { return getDesugaredType()->getAsPointerType(); } +const BlockPointerType *Type::getAsBlockPointerType() const { + // If this is directly a block pointer type, return it. + if (const BlockPointerType *PTy = dyn_cast(this)) + return PTy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa(CanonicalType)) + return 0; + + // If this is a typedef for a block pointer type, strip the typedef off + // without losing all typedef information. + return getDesugaredType()->getAsBlockPointerType(); +} + const ReferenceType *Type::getAsReferenceType() const { // If this is directly a reference type, return it. if (const ReferenceType *RTy = dyn_cast(this)) @@ -574,7 +588,9 @@ bool Type::isScalarType() const { } if (const ASQualType *ASQT = dyn_cast(CanonicalType)) return ASQT->getBaseType()->isScalarType(); - return isa(CanonicalType) || isa(CanonicalType) || + return isa(CanonicalType) || + isa(CanonicalType) || + isa(CanonicalType) || isa(CanonicalType); } @@ -831,6 +847,11 @@ void PointerType::getAsStringInternal(std::string &S) const { getPointeeType().getAsStringInternal(S); } +void BlockPointerType::getAsStringInternal(std::string &S) const { + S = '^' + S; + PointeeType.getAsStringInternal(S); +} + void ReferenceType::getAsStringInternal(std::string &S) const { S = '&' + S; diff --git a/lib/AST/TypeSerialization.cpp b/lib/AST/TypeSerialization.cpp index 68ef1114a7..9674726855 100644 --- a/lib/AST/TypeSerialization.cpp +++ b/lib/AST/TypeSerialization.cpp @@ -99,6 +99,10 @@ void Type::Create(ASTContext& Context, unsigned i, Deserializer& D) { case Type::Pointer: D.RegisterPtr(PtrID,PointerType::CreateImpl(Context,D)); break; + + case Type::BlockPointer: + D.RegisterPtr(PtrID,BlockPointerType::CreateImpl(Context,D)); + break; case Type::Tagged: D.RegisterPtr(PtrID,TagType::CreateImpl(Context,D)); @@ -129,6 +133,18 @@ Type* ASQualType::CreateImpl(ASTContext& Context, Deserializer& D) { return Context.getASQualType(BaseTy, AddressSpace).getTypePtr(); } +//===----------------------------------------------------------------------===// +// BlockPointerType +//===----------------------------------------------------------------------===// + +void BlockPointerType::EmitImpl(Serializer& S) const { + S.Emit(getPointeeType()); +} + +Type* BlockPointerType::CreateImpl(ASTContext& Context, Deserializer& D) { + return Context.getBlockPointerType(QualType::ReadVal(D)).getTypePtr(); +} + //===----------------------------------------------------------------------===// // ComplexType //===----------------------------------------------------------------------===// diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index def039b98d..76fca9e885 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1111,14 +1111,15 @@ void Parser::ParseDeclarator(Declarator &D) { void Parser::ParseDeclaratorInternal(Declarator &D) { tok::TokenKind Kind = Tok.getKind(); - // Not a pointer or C++ reference. - if (Kind != tok::star && (Kind != tok::amp || !getLang().CPlusPlus)) + // Not a pointer, C++ reference, or block. + if (Kind != tok::star && (Kind != tok::amp || !getLang().CPlusPlus) && + (Kind != tok::caret || !getLang().Blocks)) return ParseDirectDeclarator(D); // Otherwise, '*' -> pointer or '&' -> reference. SourceLocation Loc = ConsumeToken(); // Eat the * or &. - if (Kind == tok::star) { + if (Kind == tok::star || Kind == tok::caret) { // Is a pointer. DeclSpec DS; @@ -1126,10 +1127,14 @@ void Parser::ParseDeclaratorInternal(Declarator &D) { // Recursively parse the declarator. ParseDeclaratorInternal(D); - - // Remember that we parsed a pointer type, and remember the type-quals. - D.AddTypeInfo(DeclaratorChunk::getPointer(DS.getTypeQualifiers(), Loc, - DS.TakeAttributes())); + if (Kind == tok::star) + // Remember that we parsed a pointer type, and remember the type-quals. + D.AddTypeInfo(DeclaratorChunk::getPointer(DS.getTypeQualifiers(), Loc, + DS.TakeAttributes())); + else + // Remember that we parsed a Block type, and remember the type-quals. + D.AddTypeInfo(DeclaratorChunk::getBlockPointer(DS.getTypeQualifiers(), + Loc)); } else { // Is a reference DeclSpec DS; diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index c7876b1151..209a003988 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -253,6 +253,14 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) { DeclaratorChunk &DeclType = D.getTypeObject(e-i-1); switch (DeclType.Kind) { default: assert(0 && "Unknown decltype!"); + case DeclaratorChunk::BlockPointer: + if (DeclType.Cls.TypeQuals) + Diag(D.getIdentifierLoc(), diag::err_qualified_block_pointer_type); + if (!T.getTypePtr()->isFunctionType()) + Diag(D.getIdentifierLoc(), diag::err_nonfunction_block_type); + else + T = Context.getBlockPointerType(T); + break; case DeclaratorChunk::Pointer: if (T->isReferenceType()) { // C++ 8.3.2p4: There shall be no ... pointers to references ... diff --git a/test/Parser/block-pointer-decl.c b/test/Parser/block-pointer-decl.c new file mode 100644 index 0000000000..eb7ebcb402 --- /dev/null +++ b/test/Parser/block-pointer-decl.c @@ -0,0 +1,18 @@ +// RUN: clang -fsyntax-only -verify -parse-noop %s + +struct blockStruct { + int (^a)(float, int); + int b; +}; + +int blockTaker (int (^myBlock)(int), int other_input) +{ + return 0; +} + +int main (int argc, char **argv) +{ + int (^blockptr) (int); + return 0; +} +