Add parser/action support for block literal expressions.

Parser support for blocks is almost complete...just need to add support for the __block() storage class qualifier.

llvm-svn: 55495
This commit is contained in:
Steve Naroff 2008-08-28 19:20:44 +00:00
parent f1b9209a34
commit 0ac012835f
8 changed files with 129 additions and 6 deletions

View File

@ -1116,6 +1116,10 @@ DIAG(warn_selfcomparison,WARNING,
// CHECK: use of uninitialized values
DIAG(warn_uninit_val, WARNING, "use of uninitialized variable")
// Blocks
DIAG(err_expected_block_lbrace, ERROR,
"expected '{' in block literal")
// CFString checking
DIAG(err_cfstring_literal_not_string_constant, ERROR,
"CFString literal is not a string constant")

View File

@ -533,6 +533,27 @@ public:
return 0;
}
//===------------------------- "Block" Extension ------------------------===//
/// ActOnBlockStart - This callback is invoked when a block literal is
/// started. The result pointer is passed into the block finalizers.
virtual void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope,
Declarator &ParamInfo) {}
/// ActOnBlockError - If there is an error parsing a block, this callback
/// is invoked to pop the information about the block from the action impl.
virtual void ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) {}
/// ActOnBlockStmtExpr - This is called when the body of a block statement
/// literal was successfully completed. ^(int x){...}
virtual ExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc, StmtTy *Body,
Scope *CurScope) { return 0; }
/// ActOnBlockExprExpr - This is called when the body of a block
/// expression literal was successfully completed. ^(int x)[foo bar: x]
virtual ExprResult ActOnBlockExprExpr(SourceLocation CaretLoc, ExprTy *Body,
Scope *CurScope) { return 0; }
//===------------------------- C++ Declarations -------------------------===//
/// ActOnStartNamespaceDef - This is called at the start of a namespace

View File

@ -481,6 +481,7 @@ struct DeclaratorChunk {
case Reference: return Ref.AttrList;
case Array: return 0;
case Function: return 0;
case BlockPointer: return 0; // FIXME: Do blocks have attr list?
}
}

View File

@ -441,6 +441,11 @@ private:
ExprResult ParseInitializer();
ExprResult ParseInitializerWithPotentialDesignator();
//===--------------------------------------------------------------------===//
// clang Expressions
ExprResult ParseBlockLiteralExpression(); // ^{...}
//===--------------------------------------------------------------------===//
// Objective-C Expressions

View File

@ -45,7 +45,13 @@ public:
DeclScope = 0x08,
/// CXXClassScope - The scope of a C++ struct/union/class definition.
CXXClassScope = 0x10
CXXClassScope = 0x10,
/// BlockScope - This is a scope that corresponds to a block object.
/// Blocks serve as top-level scopes for some objects like labels, they
/// also prevent things like break and continue. BlockScopes have the
/// other flags set as well.
BlockScope = 0x20
};
private:
/// The parent scope for this scope. This is null for the translation-unit

View File

@ -613,8 +613,8 @@ QualType ASTContext::getPointerType(QualType T) {
/// 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
assert(T->isFunctionType() && "block of function types only");
// Unique pointers, to guarantee there is only one block of a particular
// structure.
llvm::FoldingSetNodeID ID;
BlockPointerType::Profile(ID, T);
@ -624,7 +624,7 @@ QualType ASTContext::getBlockPointerType(QualType T) {
BlockPointerTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(PT, 0);
// If the closure pointee type isn't canonical, this won't be a canonical
// If the block 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()) {

View File

@ -21,6 +21,7 @@
#include "clang/Parse/Parser.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Scope.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SmallString.h"
@ -380,6 +381,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, unsigned MinPrec) {
/// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
/// [C++] 'static_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
/// [C++] 'this' [C++ 9.3.2]
/// [clang] '^' block-literal
///
/// constant: [C99 6.4.4]
/// integer-constant
@ -595,6 +597,11 @@ Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) {
if (getLang().ObjC1)
return ParsePostfixExpressionSuffix(ParseObjCMessageExpression());
// FALL THROUGH.
case tok::caret:
if (getLang().Blocks)
return ParsePostfixExpressionSuffix(ParseBlockLiteralExpression());
Diag(Tok, diag::err_expected_expression);
return ExprResult(true);
default:
UnhandledToken:
Diag(Tok, diag::err_expected_expression);
@ -1068,3 +1075,74 @@ bool Parser::ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs) {
CommaLocs.push_back(ConsumeToken());
}
}
/// ParseBlockLiteralExpression - Parse a block literal, which roughly looks
/// like ^(int x){ return x+1; } or ^(int y)foo(4, y, z)
///
/// block-literal:
/// [clang] '^' block-args[opt] compound-statement
/// [clang] '^' block-args cast-expression
/// [clang] block-args:
/// [clang] '(' parameter-list ')'
///
Parser::ExprResult Parser::ParseBlockLiteralExpression() {
assert(Tok.is(tok::caret) && "block literal starts with ^");
SourceLocation CaretLoc = ConsumeToken();
// Enter a scope to hold everything within the block. This includes the
// argument decls, decls within the compound expression, etc. This also
// allows determining whether a variable reference inside the block is
// within or outside of the block.
EnterScope(Scope::BlockScope|Scope::FnScope|Scope::BreakScope|
Scope::ContinueScope|Scope::DeclScope);
// Parse the return type if present.
DeclSpec DS;
Declarator ParamInfo(DS, Declarator::PrototypeContext);
// If this block has arguments, parse them. There is no ambiguity here with
// the expression case, because the expression case requires a parameter list.
if (Tok.is(tok::l_paren)) {
ParseParenDeclarator(ParamInfo);
// Parse the pieces after the identifier as if we had "int(...)".
ParamInfo.SetIdentifier(0, CaretLoc);
if (ParamInfo.getInvalidType()) {
// If there was an error parsing the arguments, they may have tried to use
// ^(x+y) which requires an argument list. Just skip the whole block
// literal.
ExitScope();
return true;
}
} else {
// Otherwise, pretend we saw (void).
ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false,
0, 0, CaretLoc));
}
// Inform sema that we are starting a block.
Actions.ActOnBlockStart(CaretLoc, CurScope, ParamInfo);
ExprResult Result;
if (Tok.is(tok::l_brace)) {
StmtResult Stmt = ParseCompoundStatementBody();
if (!Stmt.isInvalid) {
Result = Actions.ActOnBlockStmtExpr(CaretLoc, Stmt.Val, CurScope);
} else {
Actions.ActOnBlockError(CaretLoc, CurScope);
Result = true;
}
} else {
ExprResult Expr = ParseCastExpression(false);
if (!Expr.isInvalid) {
Result = Actions.ActOnBlockExprExpr(CaretLoc, Expr.Val, CurScope);
} else {
Actions.ActOnBlockError(CaretLoc, CurScope);
Diag(Tok, diag::err_expected_block_lbrace);
Result = true;
}
}
ExitScope();
return Result;
}

View File

@ -7,12 +7,20 @@ struct blockStruct {
int blockTaker (int (^myBlock)(int), int other_input)
{
return 0;
return 5 * myBlock (other_input);
}
int main (int argc, char **argv)
{
int (^blockptr) (int);
int (^blockptr) (int) = ^(int inval) {
printf ("Inputs: %d, %d.\n", argc, inval);
return argc * inval;
};
argc = 10;
printf ("I got: %d.\n",
blockTaker (blockptr, 6));
return 0;
}