Use QualType to represent block's implicit return type as
to not lose its 'const/volatile' qualifier. llvm-svn: 73795
This commit is contained in:
parent
c702fc0e64
commit
3fd7310d70
|
@ -2463,10 +2463,13 @@ public:
|
||||||
class BlockDeclRefExpr : public Expr {
|
class BlockDeclRefExpr : public Expr {
|
||||||
ValueDecl *D;
|
ValueDecl *D;
|
||||||
SourceLocation Loc;
|
SourceLocation Loc;
|
||||||
bool IsByRef;
|
bool IsByRef : 1;
|
||||||
|
bool ConstQualAdded : 1;
|
||||||
public:
|
public:
|
||||||
BlockDeclRefExpr(ValueDecl *d, QualType t, SourceLocation l, bool ByRef) :
|
BlockDeclRefExpr(ValueDecl *d, QualType t, SourceLocation l, bool ByRef,
|
||||||
Expr(BlockDeclRefExprClass, t), D(d), Loc(l), IsByRef(ByRef) {}
|
bool constAdded = false) :
|
||||||
|
Expr(BlockDeclRefExprClass, t), D(d), Loc(l), IsByRef(ByRef),
|
||||||
|
ConstQualAdded(constAdded) {}
|
||||||
|
|
||||||
// \brief Build an empty reference to a declared variable in a
|
// \brief Build an empty reference to a declared variable in a
|
||||||
// block.
|
// block.
|
||||||
|
@ -2485,6 +2488,9 @@ public:
|
||||||
bool isByRef() const { return IsByRef; }
|
bool isByRef() const { return IsByRef; }
|
||||||
void setByRef(bool BR) { IsByRef = BR; }
|
void setByRef(bool BR) { IsByRef = BR; }
|
||||||
|
|
||||||
|
bool isConstQualAdded() const { return ConstQualAdded; }
|
||||||
|
void setConstQualAdded(bool C) { ConstQualAdded = C; }
|
||||||
|
|
||||||
static bool classof(const Stmt *T) {
|
static bool classof(const Stmt *T) {
|
||||||
return T->getStmtClass() == BlockDeclRefExprClass;
|
return T->getStmtClass() == BlockDeclRefExprClass;
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,7 @@ struct BlockSemaInfo {
|
||||||
|
|
||||||
/// ReturnType - This will get set to block result type, by looking at
|
/// ReturnType - This will get set to block result type, by looking at
|
||||||
/// return types, if any, in the block body.
|
/// return types, if any, in the block body.
|
||||||
Type *ReturnType;
|
QualType ReturnType;
|
||||||
|
|
||||||
/// LabelMap - This is a mapping from label identifiers to the LabelStmt for
|
/// LabelMap - This is a mapping from label identifiers to the LabelStmt for
|
||||||
/// it (which acts like the label decl in some ways). Forward referenced
|
/// it (which acts like the label decl in some ways). Forward referenced
|
||||||
|
|
|
@ -1129,10 +1129,13 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
|
||||||
// The BlocksAttr indicates the variable is bound by-reference.
|
// The BlocksAttr indicates the variable is bound by-reference.
|
||||||
if (VD->getAttr<BlocksAttr>(Context))
|
if (VD->getAttr<BlocksAttr>(Context))
|
||||||
return Owned(new (Context) BlockDeclRefExpr(VD, ExprTy, Loc, true));
|
return Owned(new (Context) BlockDeclRefExpr(VD, ExprTy, Loc, true));
|
||||||
|
// This is to record that a 'const' was actually synthesize and added.
|
||||||
|
bool constAdded = !ExprTy.isConstQualified();
|
||||||
// Variable will be bound by-copy, make it const within the closure.
|
// Variable will be bound by-copy, make it const within the closure.
|
||||||
|
|
||||||
ExprTy.addConst();
|
ExprTy.addConst();
|
||||||
return Owned(new (Context) BlockDeclRefExpr(VD, ExprTy, Loc, false));
|
return Owned(new (Context) BlockDeclRefExpr(VD, ExprTy, Loc, false,
|
||||||
|
constAdded));
|
||||||
}
|
}
|
||||||
// If this reference is not in a block or if the referenced variable is
|
// If this reference is not in a block or if the referenced variable is
|
||||||
// within the block, create a normal DeclRefExpr.
|
// within the block, create a normal DeclRefExpr.
|
||||||
|
@ -5111,7 +5114,7 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) {
|
||||||
BSI->PrevBlockInfo = CurBlock;
|
BSI->PrevBlockInfo = CurBlock;
|
||||||
CurBlock = BSI;
|
CurBlock = BSI;
|
||||||
|
|
||||||
BSI->ReturnType = 0;
|
BSI->ReturnType = QualType();
|
||||||
BSI->TheScope = BlockScope;
|
BSI->TheScope = BlockScope;
|
||||||
BSI->hasBlockDeclRefExprs = false;
|
BSI->hasBlockDeclRefExprs = false;
|
||||||
BSI->SavedFunctionNeedsScopeChecking = CurFunctionNeedsScopeChecking;
|
BSI->SavedFunctionNeedsScopeChecking = CurFunctionNeedsScopeChecking;
|
||||||
|
@ -5206,7 +5209,7 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
|
||||||
Diag(ParamInfo.getSourceRange().getBegin(),
|
Diag(ParamInfo.getSourceRange().getBegin(),
|
||||||
diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy;
|
diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy;
|
||||||
} else if (!RetTy->isDependentType())
|
} else if (!RetTy->isDependentType())
|
||||||
CurBlock->ReturnType = RetTy.getTypePtr();
|
CurBlock->ReturnType = RetTy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ActOnBlockError - If there is an error parsing a block, this callback
|
/// ActOnBlockError - If there is an error parsing a block, this callback
|
||||||
|
@ -5240,8 +5243,8 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
|
||||||
CurBlock = CurBlock->PrevBlockInfo;
|
CurBlock = CurBlock->PrevBlockInfo;
|
||||||
|
|
||||||
QualType RetTy = Context.VoidTy;
|
QualType RetTy = Context.VoidTy;
|
||||||
if (BSI->ReturnType)
|
if (!BSI->ReturnType.isNull())
|
||||||
RetTy = QualType(BSI->ReturnType, 0);
|
RetTy = BSI->ReturnType;
|
||||||
|
|
||||||
llvm::SmallVector<QualType, 8> ArgTypes;
|
llvm::SmallVector<QualType, 8> ArgTypes;
|
||||||
for (unsigned i = 0, e = BSI->Params.size(); i != e; ++i)
|
for (unsigned i = 0, e = BSI->Params.size(); i != e; ++i)
|
||||||
|
|
|
@ -748,16 +748,23 @@ Action::OwningStmtResult
|
||||||
Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
|
Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
|
||||||
// If this is the first return we've seen in the block, infer the type of
|
// If this is the first return we've seen in the block, infer the type of
|
||||||
// the block from it.
|
// the block from it.
|
||||||
if (CurBlock->ReturnType == 0) {
|
if (CurBlock->ReturnType.isNull()) {
|
||||||
if (RetValExp) {
|
if (RetValExp) {
|
||||||
// Don't call UsualUnaryConversions(), since we don't want to do
|
// Don't call UsualUnaryConversions(), since we don't want to do
|
||||||
// integer promotions here.
|
// integer promotions here.
|
||||||
DefaultFunctionArrayConversion(RetValExp);
|
DefaultFunctionArrayConversion(RetValExp);
|
||||||
CurBlock->ReturnType = RetValExp->getType().getTypePtr();
|
CurBlock->ReturnType = RetValExp->getType();
|
||||||
|
if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(RetValExp)) {
|
||||||
|
// We have to remove a 'const' added to copied-in variable which was
|
||||||
|
// part of the implementation spec. and not the actual qualifier for
|
||||||
|
// the variable.
|
||||||
|
if (CDRE->isConstQualAdded())
|
||||||
|
CurBlock->ReturnType.removeConst();
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
CurBlock->ReturnType = Context.VoidTy.getTypePtr();
|
CurBlock->ReturnType = Context.VoidTy;
|
||||||
}
|
}
|
||||||
QualType FnRetType = QualType(CurBlock->ReturnType, 0);
|
QualType FnRetType = CurBlock->ReturnType;
|
||||||
|
|
||||||
if (CurBlock->TheDecl->hasAttr<NoReturnAttr>(Context)) {
|
if (CurBlock->TheDecl->hasAttr<NoReturnAttr>(Context)) {
|
||||||
Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr)
|
Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr)
|
||||||
|
|
|
@ -102,3 +102,27 @@ void foo6() {
|
||||||
b(1);
|
b(1);
|
||||||
int (^c)(void) __attribute__((noreturn)) = ^ __attribute__((noreturn)) { return 100; }; // expected-error {{block declared 'noreturn' should not return}}
|
int (^c)(void) __attribute__((noreturn)) = ^ __attribute__((noreturn)) { return 100; }; // expected-error {{block declared 'noreturn' should not return}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void foo7()
|
||||||
|
{
|
||||||
|
const int (^BB) (void) = ^{ const int i = 1; return i; }; // OK
|
||||||
|
const int (^CC) (void) = ^const int{ const int i = 1; return i; }; // OK
|
||||||
|
|
||||||
|
int i;
|
||||||
|
int (^FF) (void) = ^{ return i; }; // OK
|
||||||
|
int (^EE) (void) = ^{ return i+1; }; // OK
|
||||||
|
|
||||||
|
__block int j;
|
||||||
|
int (^JJ) (void) = ^{ return j; }; // OK
|
||||||
|
int (^KK) (void) = ^{ return j+1; }; // OK
|
||||||
|
|
||||||
|
__block const int k;
|
||||||
|
const int cint = 100;
|
||||||
|
|
||||||
|
int (^MM) (void) = ^{ return k; }; // expected-error {{incompatible block pointer types initializing 'int const (^)(void)', expected 'int (^)(void)'}}
|
||||||
|
int (^NN) (void) = ^{ return cint; }; // expected-error {{incompatible block pointer types initializing 'int const (^)(void)', expected 'int (^)(void)'}}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue