]> granicus.if.org Git - clang/commitdiff
Preserve more information from a block's original function declarator, if one
authorJohn McCall <rjmccall@apple.com>
Fri, 4 Jun 2010 19:02:56 +0000 (19:02 +0000)
committerJohn McCall <rjmccall@apple.com>
Fri, 4 Jun 2010 19:02:56 +0000 (19:02 +0000)
was given.  Remove some unnecessary accounting from BlockScopeInfo.  Handle
typedef'ed function types until such time as we decide not.

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

lib/AST/ASTContext.cpp
lib/Sema/Sema.h
lib/Sema/SemaChecking.cpp
lib/Sema/SemaExpr.cpp
test/CodeGen/blocks.c

index a3f1b4455e98aaa16ae2f0fce1465ed8ae6c0473..43bf21313f6c5cdec39161af4f02d233954b3e1b 100644 (file)
@@ -3147,7 +3147,7 @@ void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr,
   QualType BlockTy =
       Expr->getType()->getAs<BlockPointerType>()->getPointeeType();
   // Encode result type.
-  getObjCEncodingForType(cast<FunctionType>(BlockTy)->getResultType(), S);
+  getObjCEncodingForType(BlockTy->getAs<FunctionType>()->getResultType(), S);
   // Compute size of all parameters.
   // Start with computing size of a pointer in number of bytes.
   // FIXME: There might(should) be a better way of doing this computation!
index 32cd6dcc5cb025a71476982863ee75cd64bb6bcd..09d813c7dbee1a2fd717d078d1b626f37a04580b 100644 (file)
@@ -155,9 +155,6 @@ struct FunctionScopeInfo {
 
 /// \brief Retains information about a block that is currently being parsed.
 struct BlockScopeInfo : FunctionScopeInfo {
-  llvm::SmallVector<ParmVarDecl*, 8> Params;
-  bool hasPrototype;
-  bool isVariadic;
   bool hasBlockDeclRefExprs;
 
   BlockDecl *TheDecl;
@@ -166,13 +163,17 @@ struct BlockScopeInfo : FunctionScopeInfo {
   /// arguments etc.
   Scope *TheScope;
 
-  /// ReturnType - This will get set to block result type, by looking at
-  /// return types, if any, in the block body.
+  /// ReturnType - The return type of the block, or null if the block
+  /// signature didn't provide an explicit return type.
   QualType ReturnType;
 
+  /// BlockType - The function type of the block, if one was given.
+  /// Its return type may be BuiltinType::Dependent.
+  QualType FunctionType;
+
   BlockScopeInfo(unsigned NumErrors, Scope *BlockScope, BlockDecl *Block)
-    : FunctionScopeInfo(NumErrors), hasPrototype(false), isVariadic(false),
-      hasBlockDeclRefExprs(false), TheDecl(Block), TheScope(BlockScope)
+    : FunctionScopeInfo(NumErrors), hasBlockDeclRefExprs(false),
+      TheDecl(Block), TheScope(BlockScope)
   {
     IsBlockInfo = true;
   }
index 4f3f41b715f94b3693b1ef2832ab5f278269e049..d47f2ce8edc0fe69c871d20a65efd623d05240e8 100644 (file)
@@ -511,7 +511,7 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
   BlockScopeInfo *CurBlock = getCurBlock();
   bool isVariadic;
   if (CurBlock)
-    isVariadic = CurBlock->isVariadic;
+    isVariadic = CurBlock->TheDecl->isVariadic();
   else if (FunctionDecl *FD = getCurFunctionDecl())
     isVariadic = FD->isVariadic();
   else
index 1640a61a22d13856810106967e50fe4f1cc7763a..e1a6a04bfd41494f144bf0a5b7d1c8106b2f3e6f 100644 (file)
@@ -6980,19 +6980,19 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
   QualType T = GetTypeForDeclarator(ParamInfo, CurScope, &Sig);
   CurBlock->TheDecl->setSignatureAsWritten(Sig);
 
+  bool isVariadic;
   QualType RetTy;
   if (const FunctionType *Fn = T->getAs<FunctionType>()) {
+    CurBlock->FunctionType = T;
     RetTy = Fn->getResultType();
-    CurBlock->hasPrototype = isa<FunctionProtoType>(Fn);
-    CurBlock->isVariadic =
+    isVariadic =
       !isa<FunctionProtoType>(Fn) || cast<FunctionProtoType>(Fn)->isVariadic();
   } else {
     RetTy = T;
-    CurBlock->hasPrototype = true;
-    CurBlock->isVariadic = false;
+    isVariadic = false;
   }
 
-  CurBlock->TheDecl->setIsVariadic(CurBlock->isVariadic);
+  CurBlock->TheDecl->setIsVariadic(isVariadic);
 
   // Don't allow returning an array by value.
   if (RetTy->isArrayType()) {
@@ -7008,11 +7008,14 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
   }
 
   // Context.DependentTy is used as a placeholder for a missing block
-  // return type.
+  // return type.  TODO:  what should we do with declarators like:
+  //   ^ * { ... }
+  // If the answer is "apply template argument deduction"....
   if (RetTy != Context.DependentTy)
     CurBlock->ReturnType = RetTy;
 
   // Push block parameters from the declarator if we had them.
+  llvm::SmallVector<ParmVarDecl*, 8> Params;
   if (isa<FunctionProtoType>(T)) {
     FunctionProtoTypeLoc TL = cast<FunctionProtoTypeLoc>(Sig->getTypeLoc());
     for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {
@@ -7022,7 +7025,7 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
           !Param->isInvalidDecl() &&
           !getLangOptions().CPlusPlus)
         Diag(Param->getLocation(), diag::err_parameter_name_omitted);
-      CurBlock->Params.push_back(Param);
+      Params.push_back(Param);
     }
 
   // Fake up parameter variables if we have a typedef, like
@@ -7034,19 +7037,18 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
         BuildParmVarDeclForTypedef(CurBlock->TheDecl,
                                    ParamInfo.getSourceRange().getBegin(),
                                    *I);
-      CurBlock->Params.push_back(Param);
+      Params.push_back(Param);
     }
   }
 
-  // Set the parmaeters on the block decl.
-  if (!CurBlock->Params.empty())
-    CurBlock->TheDecl->setParams(CurBlock->Params.data(),
-                                 CurBlock->Params.size());
+  // Set the parameters on the block decl.
+  if (!Params.empty())
+    CurBlock->TheDecl->setParams(Params.data(), Params.size());
 
   // Finally we can process decl attributes.
   ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
 
-  if (!CurBlock->isVariadic && CurBlock->TheDecl->getAttr<SentinelAttr>()) {
+  if (!isVariadic && CurBlock->TheDecl->getAttr<SentinelAttr>()) {
     Diag(ParamInfo.getAttributes()->getLoc(),
          diag::warn_attribute_sentinel_not_variadic) << 1;
     // FIXME: remove the attribute.
@@ -7054,7 +7056,7 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
 
   // Put the parameter variables in scope.  We can bail out immediately
   // if we don't have any.
-  if (CurBlock->Params.empty())
+  if (Params.empty())
     return;
 
   bool ShouldCheckShadow =
@@ -7099,22 +7101,52 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
   if (!BSI->ReturnType.isNull())
     RetTy = BSI->ReturnType;
 
-  llvm::SmallVector<QualType, 8> ArgTypes;
-  for (unsigned i = 0, e = BSI->Params.size(); i != e; ++i)
-    ArgTypes.push_back(BSI->Params[i]->getType());
-
   bool NoReturn = BSI->TheDecl->getAttr<NoReturnAttr>();
   QualType BlockTy;
-  if (!BSI->hasPrototype)
-    BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0, false, false, 0, 0,
-                                FunctionType::ExtInfo(NoReturn, 0, CC_Default));
-  else
-    BlockTy = Context.getFunctionType(RetTy, ArgTypes.data(), ArgTypes.size(),
-                                      BSI->isVariadic, 0, false, false, 0, 0,
-                                FunctionType::ExtInfo(NoReturn, 0, CC_Default));
+
+  // If the user wrote a function type in some form, try to use that.
+  if (!BSI->FunctionType.isNull()) {
+    const FunctionType *FTy = BSI->FunctionType->getAs<FunctionType>();
+
+    FunctionType::ExtInfo Ext = FTy->getExtInfo();
+    if (NoReturn && !Ext.getNoReturn()) Ext = Ext.withNoReturn(true);
+    
+    // Turn protoless block types into nullary block types.
+    if (isa<FunctionNoProtoType>(FTy)) {
+      BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0,
+                                        false, false, 0, 0, Ext);
+
+    // Otherwise, if we don't need to change anything about the function type,
+    // preserve its sugar structure.
+    } else if (FTy->getResultType() == RetTy &&
+               (!NoReturn || FTy->getNoReturnAttr())) {
+      BlockTy = BSI->FunctionType;
+
+    // Otherwise, make the minimal modifications to the function type.
+    } else {
+      const FunctionProtoType *FPT = cast<FunctionProtoType>(FTy);
+      BlockTy = Context.getFunctionType(RetTy,
+                                        FPT->arg_type_begin(),
+                                        FPT->getNumArgs(),
+                                        FPT->isVariadic(),
+                                        /*quals*/ 0,
+                                        FPT->hasExceptionSpec(),
+                                        FPT->hasAnyExceptionSpec(),
+                                        FPT->getNumExceptions(),
+                                        FPT->exception_begin(),
+                                        Ext);
+    }
+
+  // If we don't have a function type, just build one from nothing.
+  } else {
+    BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0,
+                                      false, false, 0, 0,
+                             FunctionType::ExtInfo(NoReturn, 0, CC_Default));
+  }
 
   // FIXME: Check that return/parameter types are complete/non-abstract
-  DiagnoseUnusedParameters(BSI->Params.begin(), BSI->Params.end());
+  DiagnoseUnusedParameters(BSI->TheDecl->param_begin(),
+                           BSI->TheDecl->param_end());
   BlockTy = Context.getBlockPointerType(BlockTy);
 
   // If needed, diagnose invalid gotos and switches in the block.
index a0f5dae6f44d4ce1226b6bac5b6ee3ec74dc7849..6888356a5a1d6e251eaaaf6f8e3770b66b692981 100644 (file)
@@ -27,3 +27,9 @@ void (^test1)(void) = ^(void) {
   ^ { i = 1; }();
 };
 
+typedef double ftype(double);
+// It's not clear that we *should* support this syntax, but until that decision
+// is made, we should support it properly and not crash.
+ftype ^test2 = ^ftype {
+  return 0;
+};