llvm::FoldingSet<ASQualType> ASQualTypes;
llvm::FoldingSet<ComplexType> ComplexTypes;
llvm::FoldingSet<PointerType> PointerTypes;
+ llvm::FoldingSet<BlockPointerType> BlockPointerTypes;
llvm::FoldingSet<ReferenceType> ReferenceTypes;
llvm::FoldingSet<ConstantArrayType> ConstantArrayTypes;
llvm::FoldingSet<IncompleteArrayType> IncompleteArrayTypes;
/// 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.
class SourceLocation;
class PointerLikeType;
class PointerType;
+ class BlockPointerType;
class ReferenceType;
class VectorType;
class ArrayType;
TypeName, Tagged, ASQual,
ObjCInterface, ObjCQualifiedInterface,
ObjCQualifiedId,
- TypeOfExp, TypeOfTyp // GNU typeof extension.
+ TypeOfExp, TypeOfTyp, // GNU typeof extension.
+ BlockPointer // C extension
};
private:
QualType CanonicalType;
bool isFunctionType() const;
bool isPointerLikeType() const; // Pointer or Reference.
bool isPointerType() const;
+ bool isBlockPointerType() const;
bool isReferenceType() const;
bool isFunctionPointerType() const;
bool isArrayType() const;
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;
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 {
inline bool Type::isPointerType() const {
return isa<PointerType>(CanonicalType.getUnqualifiedType());
}
+inline bool Type::isBlockPointerType() const {
+ return isa<BlockPointerType>(CanonicalType);
+}
inline bool Type::isReferenceType() const {
return isa<ReferenceType>(CanonicalType.getUnqualifiedType());
}
"'%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,
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
// FIXME: The default should be 1.
ThreadsafeStatics = 0;
+ Blocks = 1;
}
GCMode getGCMode() const { return (GCMode) GC; }
/// 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.
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;
};
}
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;
+ }
};
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)
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) {
return getDesugaredType()->getAsPointerType();
}
+const BlockPointerType *Type::getAsBlockPointerType() const {
+ // If this is directly a block pointer type, return it.
+ if (const BlockPointerType *PTy = dyn_cast<BlockPointerType>(this))
+ return PTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<BlockPointerType>(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<ReferenceType>(this))
}
if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType))
return ASQT->getBaseType()->isScalarType();
- return isa<PointerType>(CanonicalType) || isa<ComplexType>(CanonicalType) ||
+ return isa<PointerType>(CanonicalType) ||
+ isa<BlockPointerType>(CanonicalType) ||
+ isa<ComplexType>(CanonicalType) ||
isa<ObjCQualifiedIdType>(CanonicalType);
}
getPointeeType().getAsStringInternal(S);
}
+void BlockPointerType::getAsStringInternal(std::string &S) const {
+ S = '^' + S;
+ PointeeType.getAsStringInternal(S);
+}
+
void ReferenceType::getAsStringInternal(std::string &S) const {
S = '&' + S;
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));
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
//===----------------------------------------------------------------------===//
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;
// 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;
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 ...
--- /dev/null
+// 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;
+}
+