mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-07 08:34:59 +00:00
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:
parent
f1b9209a34
commit
0ac012835f
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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?
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -441,6 +441,11 @@ private:
|
||||
ExprResult ParseInitializer();
|
||||
ExprResult ParseInitializerWithPotentialDesignator();
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// clang Expressions
|
||||
|
||||
ExprResult ParseBlockLiteralExpression(); // ^{...}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Objective-C Expressions
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user