From: Fariborz Jahanian Date: Fri, 19 Jun 2009 23:37:08 +0000 (+0000) Subject: Use QualType to represent block's implicit return type as X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7d5c74ecbbd8719436c071f38657bc8e97ee4a24;p=clang Use QualType to represent block's implicit return type as to not lose its 'const/volatile' qualifier. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@73795 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index f1e25ce918..2ed9112475 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -2463,10 +2463,13 @@ public: class BlockDeclRefExpr : public Expr { ValueDecl *D; SourceLocation Loc; - bool IsByRef; + bool IsByRef : 1; + bool ConstQualAdded : 1; public: - BlockDeclRefExpr(ValueDecl *d, QualType t, SourceLocation l, bool ByRef) : - Expr(BlockDeclRefExprClass, t), D(d), Loc(l), IsByRef(ByRef) {} + BlockDeclRefExpr(ValueDecl *d, QualType t, SourceLocation l, bool 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 // block. @@ -2484,6 +2487,9 @@ public: bool isByRef() const { return IsByRef; } void setByRef(bool BR) { IsByRef = BR; } + + bool isConstQualAdded() const { return ConstQualAdded; } + void setConstQualAdded(bool C) { ConstQualAdded = C; } static bool classof(const Stmt *T) { return T->getStmtClass() == BlockDeclRefExprClass; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index bb9fa4b798..23bab23009 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -102,7 +102,7 @@ struct BlockSemaInfo { /// ReturnType - This will get set to block result type, by looking at /// return types, if any, in the block body. - Type *ReturnType; + QualType ReturnType; /// LabelMap - This is a mapping from label identifiers to the LabelStmt for /// it (which acts like the label decl in some ways). Forward referenced diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 7e82783404..de56819311 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1129,10 +1129,13 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, // The BlocksAttr indicates the variable is bound by-reference. if (VD->getAttr(Context)) 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. + 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 // within the block, create a normal DeclRefExpr. @@ -5111,7 +5114,7 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) { BSI->PrevBlockInfo = CurBlock; CurBlock = BSI; - BSI->ReturnType = 0; + BSI->ReturnType = QualType(); BSI->TheScope = BlockScope; BSI->hasBlockDeclRefExprs = false; BSI->SavedFunctionNeedsScopeChecking = CurFunctionNeedsScopeChecking; @@ -5206,7 +5209,7 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { Diag(ParamInfo.getSourceRange().getBegin(), diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy; } else if (!RetTy->isDependentType()) - CurBlock->ReturnType = RetTy.getTypePtr(); + CurBlock->ReturnType = RetTy; } /// ActOnBlockError - If there is an error parsing a block, this callback @@ -5240,8 +5243,8 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, CurBlock = CurBlock->PrevBlockInfo; QualType RetTy = Context.VoidTy; - if (BSI->ReturnType) - RetTy = QualType(BSI->ReturnType, 0); + if (!BSI->ReturnType.isNull()) + RetTy = BSI->ReturnType; llvm::SmallVector ArgTypes; for (unsigned i = 0, e = BSI->Params.size(); i != e; ++i) diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 7797e270f5..914839cbf7 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -748,16 +748,23 @@ Action::OwningStmtResult Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // If this is the first return we've seen in the block, infer the type of // the block from it. - if (CurBlock->ReturnType == 0) { + if (CurBlock->ReturnType.isNull()) { if (RetValExp) { // Don't call UsualUnaryConversions(), since we don't want to do // integer promotions here. DefaultFunctionArrayConversion(RetValExp); - CurBlock->ReturnType = RetValExp->getType().getTypePtr(); + CurBlock->ReturnType = RetValExp->getType(); + if (BlockDeclRefExpr *CDRE = dyn_cast(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 - CurBlock->ReturnType = Context.VoidTy.getTypePtr(); + CurBlock->ReturnType = Context.VoidTy; } - QualType FnRetType = QualType(CurBlock->ReturnType, 0); + QualType FnRetType = CurBlock->ReturnType; if (CurBlock->TheDecl->hasAttr(Context)) { Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr) diff --git a/test/Sema/block-return.c b/test/Sema/block-return.c index e1a3cfd812..87f4040be9 100644 --- a/test/Sema/block-return.c +++ b/test/Sema/block-return.c @@ -102,3 +102,27 @@ void foo6() { b(1); 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)'}} + +} + +