]> granicus.if.org Git - clang/commitdiff
Restructure how we interpret block-literal declarators. Correctly handle
authorJohn McCall <rjmccall@apple.com>
Fri, 4 Jun 2010 11:21:44 +0000 (11:21 +0000)
committerJohn McCall <rjmccall@apple.com>
Fri, 4 Jun 2010 11:21:44 +0000 (11:21 +0000)
the case where we pick up block arguments from a typedef.  Save the block
signature as it was written, and preserve same through PCH.

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

include/clang/AST/Decl.h
lib/Frontend/PCHReaderDecl.cpp
lib/Frontend/PCHWriterDecl.cpp
lib/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaExpr.cpp

index 61447295ceecd4f2385339571845328aaad944a6..1e507a5d25e5b47db34a2f9333facc489d5fd8c4 100644 (file)
@@ -2127,11 +2127,13 @@ class BlockDecl : public Decl, public DeclContext {
   unsigned NumParams;
 
   Stmt *Body;
+  TypeSourceInfo *SignatureAsWritten;
 
 protected:
   BlockDecl(DeclContext *DC, SourceLocation CaretLoc)
     : Decl(Block, DC, CaretLoc), DeclContext(Block),
-      IsVariadic(false), ParamInfo(0), NumParams(0), Body(0) {}
+      IsVariadic(false), ParamInfo(0), NumParams(0), Body(0),
+      SignatureAsWritten(0) {}
 
   virtual ~BlockDecl();
   virtual void Destroy(ASTContext& C);
@@ -2148,6 +2150,9 @@ public:
   Stmt *getBody() const { return (Stmt*) Body; }
   void setBody(CompoundStmt *B) { Body = (Stmt*) B; }
 
+  void setSignatureAsWritten(TypeSourceInfo *Sig) { SignatureAsWritten = Sig; }
+  TypeSourceInfo *getSignatureAsWritten() const { return SignatureAsWritten; }
+
   // Iterator access to formal parameters.
   unsigned param_size() const { return getNumParams(); }
   typedef ParmVarDecl **param_iterator;
index 606e852385d4eb3bb62c0155c94fc5896c91ecd5..8b7b66c2b85d2f9b615ce78e23a33d2885d9c878 100644 (file)
@@ -462,6 +462,7 @@ void PCHDeclReader::VisitFileScopeAsmDecl(FileScopeAsmDecl *AD) {
 void PCHDeclReader::VisitBlockDecl(BlockDecl *BD) {
   VisitDecl(BD);
   BD->setBody(cast_or_null<CompoundStmt>(Reader.ReadDeclStmt()));
+  BD->setSignatureAsWritten(Reader.GetTypeSourceInfo(Record, Idx));
   unsigned NumParams = Record[Idx++];
   llvm::SmallVector<ParmVarDecl *, 16> Params;
   Params.reserve(NumParams);
index d0a01f083f9fa933fbfd4644e5a23e4f68842df3..8eeef7c741e9451cad89a2426da4ec651c1a037f 100644 (file)
@@ -471,6 +471,7 @@ void PCHDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
 void PCHDeclWriter::VisitBlockDecl(BlockDecl *D) {
   VisitDecl(D);
   Writer.AddStmt(D->getBody());
+  Writer.AddTypeSourceInfo(D->getSignatureAsWritten(), Record);
   Record.push_back(D->param_size());
   for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end();
        P != PEnd; ++P)
index e4e63c330b21e40737e74deeccbf4fcd0631b686..32cd6dcc5cb025a71476982863ee75cd64bb6bcd 100644 (file)
@@ -841,6 +841,9 @@ public:
                                 bool &OverloadableAttrRequired);
   void CheckMain(FunctionDecl *FD);
   virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D);
+  ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC,
+                                          SourceLocation Loc,
+                                          QualType T);
   ParmVarDecl *CheckParameter(DeclContext *DC,
                               TypeSourceInfo *TSInfo, QualType T,
                               IdentifierInfo *Name,
index 02a157f1d8547dd17fee12083a541648472e1ec3..52e4bb9aca3f0cc51c706e5de705223511cb0a6e 100644 (file)
@@ -3272,14 +3272,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
     // Synthesize a parameter for each argument type.
     for (FunctionProtoType::arg_type_iterator AI = FT->arg_type_begin(),
          AE = FT->arg_type_end(); AI != AE; ++AI) {
-      ParmVarDecl *Param = ParmVarDecl::Create(Context, NewFD,
-                                               D.getIdentifierLoc(), 0,
-                                               *AI, 
-                                         Context.getTrivialTypeSourceInfo(*AI, 
-                                                          D.getIdentifierLoc()),
-                                               VarDecl::None,
-                                               VarDecl::None, 0);
-      Param->setImplicit();
+      ParmVarDecl *Param =
+        BuildParmVarDeclForTypedef(NewFD, D.getIdentifierLoc(), *AI);
       Params.push_back(Param);
     }
   } else {
@@ -4331,6 +4325,18 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
   return DeclPtrTy::make(New);
 }
 
+/// \brief Synthesizes a variable for a parameter arising from a
+/// typedef.
+ParmVarDecl *Sema::BuildParmVarDeclForTypedef(DeclContext *DC,
+                                              SourceLocation Loc,
+                                              QualType T) {
+  ParmVarDecl *Param = ParmVarDecl::Create(Context, DC, Loc, 0,
+                                T, Context.getTrivialTypeSourceInfo(T, Loc),
+                                           VarDecl::None, VarDecl::None, 0);
+  Param->setImplicit();
+  return Param;
+}
+
 ParmVarDecl *Sema::CheckParameter(DeclContext *DC, 
                                   TypeSourceInfo *TSInfo, QualType T,
                                   IdentifierInfo *Name,
index 906fd08828d9a3a00109712eb332c61674c55023..1640a61a22d13856810106967e50fe4f1cc7763a 100644 (file)
@@ -6976,62 +6976,47 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
   assert(ParamInfo.getIdentifier()==0 && "block-id should have no identifier!");
   BlockScopeInfo *CurBlock = getCurBlock();
 
-  if (ParamInfo.getNumTypeObjects() == 0
-      || ParamInfo.getTypeObject(0).Kind != DeclaratorChunk::Function) {
-    ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
-    QualType T = GetTypeForDeclarator(ParamInfo, CurScope);
-
-    if (T->isArrayType()) {
-      Diag(ParamInfo.getSourceRange().getBegin(),
-           diag::err_block_returns_array);
-      return;
-    }
-
-    // The parameter list is optional, if there was none, assume ().
-    if (!T->isFunctionType())
-      T = Context.getFunctionType(T, 0, 0, false, 0, false, false, 0, 0,
-                                  FunctionType::ExtInfo());
-
+  TypeSourceInfo *Sig = 0;
+  QualType T = GetTypeForDeclarator(ParamInfo, CurScope, &Sig);
+  CurBlock->TheDecl->setSignatureAsWritten(Sig);
+
+  QualType RetTy;
+  if (const FunctionType *Fn = T->getAs<FunctionType>()) {
+    RetTy = Fn->getResultType();
+    CurBlock->hasPrototype = isa<FunctionProtoType>(Fn);
+    CurBlock->isVariadic =
+      !isa<FunctionProtoType>(Fn) || cast<FunctionProtoType>(Fn)->isVariadic();
+  } else {
+    RetTy = T;
     CurBlock->hasPrototype = true;
     CurBlock->isVariadic = false;
-    // Check for a valid sentinel attribute on this block.
-    if (CurBlock->TheDecl->getAttr<SentinelAttr>()) {
-      Diag(ParamInfo.getAttributes()->getLoc(),
-           diag::warn_attribute_sentinel_not_variadic) << 1;
-      // FIXME: remove the attribute.
-    }
-    QualType RetTy = T.getTypePtr()->getAs<FunctionType>()->getResultType();
-
-    // Do not allow returning a objc interface by-value.
-    if (RetTy->isObjCObjectType()) {
-      Diag(ParamInfo.getSourceRange().getBegin(),
-           diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy;
-      return;
-    }
+  }
 
-    CurBlock->ReturnType = RetTy;
+  CurBlock->TheDecl->setIsVariadic(CurBlock->isVariadic);
+
+  // Don't allow returning an array by value.
+  if (RetTy->isArrayType()) {
+    Diag(ParamInfo.getSourceRange().getBegin(), diag::err_block_returns_array);
     return;
   }
 
-  // Analyze arguments to block.
-  assert(ParamInfo.getTypeObject(0).Kind == DeclaratorChunk::Function &&
-         "Not a function declarator!");
-  DeclaratorChunk::FunctionTypeInfo &FTI = ParamInfo.getTypeObject(0).Fun;
+  // Don't allow returning a objc interface by value.
+  if (RetTy->isObjCObjectType()) {
+    Diag(ParamInfo.getSourceRange().getBegin(),
+         diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy;
+    return;
+  }
 
-  CurBlock->hasPrototype = FTI.hasPrototype;
-  CurBlock->isVariadic = true;
+  // Context.DependentTy is used as a placeholder for a missing block
+  // return type.
+  if (RetTy != Context.DependentTy)
+    CurBlock->ReturnType = RetTy;
 
-  // Check for C99 6.7.5.3p10 - foo(void) is a non-varargs function that takes
-  // no arguments, not a function that takes a single void argument.
-  if (FTI.hasPrototype &&
-      FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
-     (!FTI.ArgInfo[0].Param.getAs<ParmVarDecl>()->getType().getCVRQualifiers()&&
-        FTI.ArgInfo[0].Param.getAs<ParmVarDecl>()->getType()->isVoidType())) {
-    // empty arg list, don't push any params.
-    CurBlock->isVariadic = false;
-  } else if (FTI.hasPrototype) {
-    for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
-      ParmVarDecl *Param = FTI.ArgInfo[i].Param.getAs<ParmVarDecl>();
+  // Push block parameters from the declarator if we had them.
+  if (isa<FunctionProtoType>(T)) {
+    FunctionProtoTypeLoc TL = cast<FunctionProtoTypeLoc>(Sig->getTypeLoc());
+    for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {
+      ParmVarDecl *Param = TL.getArg(I);
       if (Param->getIdentifier() == 0 &&
           !Param->isImplicit() &&
           !Param->isInvalidDecl() &&
@@ -7039,13 +7024,39 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
         Diag(Param->getLocation(), diag::err_parameter_name_omitted);
       CurBlock->Params.push_back(Param);
     }
-    CurBlock->isVariadic = FTI.isVariadic;
+
+  // Fake up parameter variables if we have a typedef, like
+  //   ^ fntype { ... }
+  } else if (const FunctionProtoType *Fn = T->getAs<FunctionProtoType>()) {
+    for (FunctionProtoType::arg_type_iterator
+           I = Fn->arg_type_begin(), E = Fn->arg_type_end(); I != E; ++I) {
+      ParmVarDecl *Param =
+        BuildParmVarDeclForTypedef(CurBlock->TheDecl,
+                                   ParamInfo.getSourceRange().getBegin(),
+                                   *I);
+      CurBlock->Params.push_back(Param);
+    }
   }
-  CurBlock->TheDecl->setParams(CurBlock->Params.data(),
-                               CurBlock->Params.size());
-  CurBlock->TheDecl->setIsVariadic(CurBlock->isVariadic);
+
+  // Set the parmaeters on the block decl.
+  if (!CurBlock->Params.empty())
+    CurBlock->TheDecl->setParams(CurBlock->Params.data(),
+                                 CurBlock->Params.size());
+
+  // Finally we can process decl attributes.
   ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
 
+  if (!CurBlock->isVariadic && CurBlock->TheDecl->getAttr<SentinelAttr>()) {
+    Diag(ParamInfo.getAttributes()->getLoc(),
+         diag::warn_attribute_sentinel_not_variadic) << 1;
+    // FIXME: remove the attribute.
+  }
+
+  // Put the parameter variables in scope.  We can bail out immediately
+  // if we don't have any.
+  if (CurBlock->Params.empty())
+    return;
+
   bool ShouldCheckShadow =
     Diags.getDiagnosticLevel(diag::warn_decl_shadow) != Diagnostic::Ignored;
 
@@ -7061,25 +7072,6 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
       PushOnScopeChains(*AI, CurBlock->TheScope);
     }
   }
-
-  // Check for a valid sentinel attribute on this block.
-  if (!CurBlock->isVariadic &&
-      CurBlock->TheDecl->getAttr<SentinelAttr>()) {
-    Diag(ParamInfo.getAttributes()->getLoc(),
-         diag::warn_attribute_sentinel_not_variadic) << 1;
-    // FIXME: remove the attribute.
-  }
-
-  // Analyze the return type.
-  QualType T = GetTypeForDeclarator(ParamInfo, CurScope);
-  QualType RetTy = T->getAs<FunctionType>()->getResultType();
-
-  // Do not allow returning a objc interface by-value.
-  if (RetTy->isObjCObjectType()) {
-    Diag(ParamInfo.getSourceRange().getBegin(),
-         diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy;
-  } else if (!RetTy->isDependentType())
-    CurBlock->ReturnType = RetTy;
 }
 
 /// ActOnBlockError - If there is an error parsing a block, this callback