]> granicus.if.org Git - clang/commitdiff
Use QualType to represent block's implicit return type as
authorFariborz Jahanian <fjahanian@apple.com>
Fri, 19 Jun 2009 23:37:08 +0000 (23:37 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Fri, 19 Jun 2009 23:37:08 +0000 (23:37 +0000)
to not lose its 'const/volatile' qualifier.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@73795 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Expr.h
lib/Sema/Sema.h
lib/Sema/SemaExpr.cpp
lib/Sema/SemaStmt.cpp
test/Sema/block-return.c

index f1e25ce918427d1a1ddb9917239f5523077850f9..2ed91124758d5218a93059cdc5ba7615764ab177 100644 (file)
@@ -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; 
index bb9fa4b798895e9a9e8b9d2b0d7130ab27a6eb9e..23bab2300971268f88d21a4461707cab47628c0e 100644 (file)
@@ -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
index 7e827834047fba8d3e8c88a0560234ea47dab69e..de5681931196a224c651e3ed2ed756f7a738e992 100644 (file)
@@ -1129,10 +1129,13 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
     // The BlocksAttr indicates the variable is bound by-reference.
     if (VD->getAttr<BlocksAttr>(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<QualType, 8> ArgTypes;
   for (unsigned i = 0, e = BSI->Params.size(); i != e; ++i)
index 7797e270f5f16e4d434cfdbd9eeae107aec86f63..914839cbf790b93047e5ebecc0edeafb60861954 100644 (file)
@@ -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<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
-      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)) {
     Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr)
index e1a3cfd8123d0a2ce5d505e00034bfa8eaa7d39a..87f4040be9d07016f767bb997c5fc0019df8279b 100644 (file)
@@ -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)'}}
+
+}
+
+