forked from OSchip/llvm-project
First wave of changes to support "blocks" (an extension to C).
This commit adds the declaration syntax (and associated type). llvm-svn: 55417
This commit is contained in:
parent
539f74c87d
commit
ec33ed9ced
|
@ -51,6 +51,7 @@ class ASTContext {
|
|||
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;
|
||||
|
@ -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.
|
||||
|
|
|
@ -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<PointerType>(CanonicalType.getUnqualifiedType());
|
||||
}
|
||||
inline bool Type::isBlockPointerType() const {
|
||||
return isa<BlockPointerType>(CanonicalType);
|
||||
}
|
||||
inline bool Type::isReferenceType() const {
|
||||
return isa<ReferenceType>(CanonicalType.getUnqualifiedType());
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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<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))
|
||||
|
@ -574,7 +588,9 @@ bool Type::isScalarType() const {
|
|||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ...
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue