forked from OSchip/llvm-project
				
			Refactor capture in blocks to use new-style capture hooks. Start adding a bit of the code for lambdas. The only visible changes are that we use the C++11 odr-used rules to figure out when a variable is captured, and type-checking in lambdas is slightly more accurate.
llvm-svn: 149663
This commit is contained in:
		
							parent
							
								
									d1956e46dd
								
							
						
					
					
						commit
						9bb33f572f
					
				| 
						 | 
					@ -1191,231 +1191,6 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
 | 
				
			||||||
                                     StringTokLocs.size()));
 | 
					                                     StringTokLocs.size()));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum CaptureResult {
 | 
					 | 
				
			||||||
  /// No capture is required.
 | 
					 | 
				
			||||||
  CR_NoCapture,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /// A capture is required.
 | 
					 | 
				
			||||||
  CR_Capture,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /// A by-ref capture is required.
 | 
					 | 
				
			||||||
  CR_CaptureByRef,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /// An error occurred when trying to capture the given variable.
 | 
					 | 
				
			||||||
  CR_Error
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Diagnose an uncapturable value reference.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// \param var - the variable referenced
 | 
					 | 
				
			||||||
/// \param DC - the context which we couldn't capture through
 | 
					 | 
				
			||||||
static CaptureResult
 | 
					 | 
				
			||||||
diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
 | 
					 | 
				
			||||||
                                   VarDecl *var, DeclContext *DC) {
 | 
					 | 
				
			||||||
  switch (S.ExprEvalContexts.back().Context) {
 | 
					 | 
				
			||||||
  case Sema::Unevaluated:
 | 
					 | 
				
			||||||
  case Sema::ConstantEvaluated:
 | 
					 | 
				
			||||||
    // The argument will never be evaluated at runtime, so don't complain.
 | 
					 | 
				
			||||||
    return CR_NoCapture;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  case Sema::PotentiallyEvaluated:
 | 
					 | 
				
			||||||
  case Sema::PotentiallyEvaluatedIfUsed:
 | 
					 | 
				
			||||||
    break;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Don't diagnose about capture if we're not actually in code right
 | 
					 | 
				
			||||||
  // now; in general, there are more appropriate places that will
 | 
					 | 
				
			||||||
  // diagnose this.
 | 
					 | 
				
			||||||
  if (!S.CurContext->isFunctionOrMethod()) return CR_NoCapture;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Certain madnesses can happen with parameter declarations, which
 | 
					 | 
				
			||||||
  // we want to ignore.
 | 
					 | 
				
			||||||
  if (isa<ParmVarDecl>(var)) {
 | 
					 | 
				
			||||||
    // - If the parameter still belongs to the translation unit, then
 | 
					 | 
				
			||||||
    //   we're actually just using one parameter in the declaration of
 | 
					 | 
				
			||||||
    //   the next.  This is useful in e.g. VLAs.
 | 
					 | 
				
			||||||
    if (isa<TranslationUnitDecl>(var->getDeclContext()))
 | 
					 | 
				
			||||||
      return CR_NoCapture;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // - This particular madness can happen in ill-formed default
 | 
					 | 
				
			||||||
    //   arguments; claim it's okay and let downstream code handle it.
 | 
					 | 
				
			||||||
    if (S.CurContext == var->getDeclContext()->getParent())
 | 
					 | 
				
			||||||
      return CR_NoCapture;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  DeclarationName functionName;
 | 
					 | 
				
			||||||
  if (FunctionDecl *fn = dyn_cast<FunctionDecl>(var->getDeclContext()))
 | 
					 | 
				
			||||||
    functionName = fn->getDeclName();
 | 
					 | 
				
			||||||
  // FIXME: variable from enclosing block that we couldn't capture from!
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  S.Diag(loc, diag::err_reference_to_local_var_in_enclosing_function)
 | 
					 | 
				
			||||||
    << var->getIdentifier() << functionName;
 | 
					 | 
				
			||||||
  S.Diag(var->getLocation(), diag::note_local_variable_declared_here)
 | 
					 | 
				
			||||||
    << var->getIdentifier();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return CR_Error;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// There is a well-formed capture at a particular scope level;
 | 
					 | 
				
			||||||
/// propagate it through all the nested blocks.
 | 
					 | 
				
			||||||
static CaptureResult propagateCapture(Sema &S, unsigned ValidScopeIndex,
 | 
					 | 
				
			||||||
                                      const CapturingScopeInfo::Capture &Cap) {
 | 
					 | 
				
			||||||
  // Update all the inner blocks with the capture information.
 | 
					 | 
				
			||||||
  for (unsigned i = ValidScopeIndex + 1, e = S.FunctionScopes.size();
 | 
					 | 
				
			||||||
         i != e; ++i) {
 | 
					 | 
				
			||||||
    BlockScopeInfo *innerBlock = cast<BlockScopeInfo>(S.FunctionScopes[i]);
 | 
					 | 
				
			||||||
    innerBlock->AddCapture(Cap.getVariable(), Cap.isReferenceCapture(),
 | 
					 | 
				
			||||||
                           /*nested*/ true, Cap.getLocation(),
 | 
					 | 
				
			||||||
                           Cap.getCopyExpr());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return Cap.isReferenceCapture() ? CR_CaptureByRef : CR_Capture;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// shouldCaptureValueReference - Determine if a reference to the
 | 
					 | 
				
			||||||
/// given value in the current context requires a variable capture.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// This also keeps the captures set in the BlockScopeInfo records
 | 
					 | 
				
			||||||
/// up-to-date.
 | 
					 | 
				
			||||||
static CaptureResult shouldCaptureValueReference(Sema &S, SourceLocation loc,
 | 
					 | 
				
			||||||
                                                 ValueDecl *Value) {
 | 
					 | 
				
			||||||
  // Only variables ever require capture.
 | 
					 | 
				
			||||||
  VarDecl *var = dyn_cast<VarDecl>(Value);
 | 
					 | 
				
			||||||
  if (!var) return CR_NoCapture;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Fast path: variables from the current context never require capture.
 | 
					 | 
				
			||||||
  DeclContext *DC = S.CurContext;
 | 
					 | 
				
			||||||
  if (var->getDeclContext() == DC) return CR_NoCapture;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Only variables with local storage require capture.
 | 
					 | 
				
			||||||
  // FIXME: What about 'const' variables in C++?
 | 
					 | 
				
			||||||
  if (!var->hasLocalStorage()) return CR_NoCapture;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Otherwise, we need to capture.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  unsigned functionScopesIndex = S.FunctionScopes.size() - 1;
 | 
					 | 
				
			||||||
  do {
 | 
					 | 
				
			||||||
    // Only blocks (and eventually C++0x closures) can capture; other
 | 
					 | 
				
			||||||
    // scopes don't work.
 | 
					 | 
				
			||||||
    if (!isa<BlockDecl>(DC))
 | 
					 | 
				
			||||||
      return diagnoseUncapturableValueReference(S, loc, var, DC);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    BlockScopeInfo *blockScope =
 | 
					 | 
				
			||||||
      cast<BlockScopeInfo>(S.FunctionScopes[functionScopesIndex]);
 | 
					 | 
				
			||||||
    assert(blockScope->TheDecl == static_cast<BlockDecl*>(DC));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Check whether we've already captured it in this block.  If so,
 | 
					 | 
				
			||||||
    // we're done.
 | 
					 | 
				
			||||||
    if (unsigned indexPlus1 = blockScope->CaptureMap[var])
 | 
					 | 
				
			||||||
      return propagateCapture(S, functionScopesIndex,
 | 
					 | 
				
			||||||
                              blockScope->Captures[indexPlus1 - 1]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    functionScopesIndex--;
 | 
					 | 
				
			||||||
    DC = cast<BlockDecl>(DC)->getDeclContext();
 | 
					 | 
				
			||||||
  } while (var->getDeclContext() != DC);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Okay, we descended all the way to the block that defines the variable.
 | 
					 | 
				
			||||||
  // Actually try to capture it.
 | 
					 | 
				
			||||||
  QualType type = var->getType();
 | 
					 | 
				
			||||||
  
 | 
					 | 
				
			||||||
  // Prohibit variably-modified types.
 | 
					 | 
				
			||||||
  if (type->isVariablyModifiedType()) {
 | 
					 | 
				
			||||||
    S.Diag(loc, diag::err_ref_vm_type);
 | 
					 | 
				
			||||||
    S.Diag(var->getLocation(), diag::note_declared_at);
 | 
					 | 
				
			||||||
    return CR_Error;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Prohibit arrays, even in __block variables, but not references to
 | 
					 | 
				
			||||||
  // them.
 | 
					 | 
				
			||||||
  if (type->isArrayType()) {
 | 
					 | 
				
			||||||
    S.Diag(loc, diag::err_ref_array_type);
 | 
					 | 
				
			||||||
    S.Diag(var->getLocation(), diag::note_declared_at);
 | 
					 | 
				
			||||||
    return CR_Error;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // The BlocksAttr indicates the variable is bound by-reference.
 | 
					 | 
				
			||||||
  bool byRef = var->hasAttr<BlocksAttr>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Build a copy expression.
 | 
					 | 
				
			||||||
  Expr *copyExpr = 0;
 | 
					 | 
				
			||||||
  const RecordType *rtype;
 | 
					 | 
				
			||||||
  if (!byRef && S.getLangOptions().CPlusPlus && !type->isDependentType() &&
 | 
					 | 
				
			||||||
      (rtype = type->getAs<RecordType>())) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // The capture logic needs the destructor, so make sure we mark it.
 | 
					 | 
				
			||||||
    // Usually this is unnecessary because most local variables have
 | 
					 | 
				
			||||||
    // their destructors marked at declaration time, but parameters are
 | 
					 | 
				
			||||||
    // an exception because it's technically only the call site that
 | 
					 | 
				
			||||||
    // actually requires the destructor.
 | 
					 | 
				
			||||||
    if (isa<ParmVarDecl>(var))
 | 
					 | 
				
			||||||
      S.FinalizeVarWithDestructor(var, rtype);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // According to the blocks spec, the capture of a variable from
 | 
					 | 
				
			||||||
    // the stack requires a const copy constructor.  This is not true
 | 
					 | 
				
			||||||
    // of the copy/move done to move a __block variable to the heap.
 | 
					 | 
				
			||||||
    type.addConst();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Expr *declRef = new (S.Context) DeclRefExpr(var, type, VK_LValue, loc);
 | 
					 | 
				
			||||||
    ExprResult result =
 | 
					 | 
				
			||||||
      S.PerformCopyInitialization(
 | 
					 | 
				
			||||||
                      InitializedEntity::InitializeBlock(var->getLocation(),
 | 
					 | 
				
			||||||
                                                         type, false),
 | 
					 | 
				
			||||||
                                  loc, S.Owned(declRef));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Build a full-expression copy expression if initialization
 | 
					 | 
				
			||||||
    // succeeded and used a non-trivial constructor.  Recover from
 | 
					 | 
				
			||||||
    // errors by pretending that the copy isn't necessary.
 | 
					 | 
				
			||||||
    if (!result.isInvalid() &&
 | 
					 | 
				
			||||||
        !cast<CXXConstructExpr>(result.get())->getConstructor()->isTrivial()) {
 | 
					 | 
				
			||||||
      result = S.MaybeCreateExprWithCleanups(result);
 | 
					 | 
				
			||||||
      copyExpr = result.take();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // We're currently at the declarer; go back to the closure.
 | 
					 | 
				
			||||||
  functionScopesIndex++;
 | 
					 | 
				
			||||||
  BlockScopeInfo *blockScope =
 | 
					 | 
				
			||||||
    cast<BlockScopeInfo>(S.FunctionScopes[functionScopesIndex]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Build a valid capture in this scope.
 | 
					 | 
				
			||||||
  blockScope->AddCapture(var, byRef, /*nested*/ false, loc, copyExpr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Propagate that to inner captures if necessary.
 | 
					 | 
				
			||||||
  return propagateCapture(S, functionScopesIndex,
 | 
					 | 
				
			||||||
                          blockScope->Captures.back());
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static ExprResult BuildBlockDeclRefExpr(Sema &S, ValueDecl *VD,
 | 
					 | 
				
			||||||
                                        const DeclarationNameInfo &NameInfo,
 | 
					 | 
				
			||||||
                                        bool ByRef) {
 | 
					 | 
				
			||||||
  assert(isa<VarDecl>(VD) && "capturing non-variable");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  VarDecl *var = cast<VarDecl>(VD);
 | 
					 | 
				
			||||||
  assert(var->hasLocalStorage() && "capturing non-local");
 | 
					 | 
				
			||||||
  assert(ByRef == var->hasAttr<BlocksAttr>() && "byref set wrong");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  QualType exprType = var->getType().getNonReferenceType();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  BlockDeclRefExpr *BDRE;
 | 
					 | 
				
			||||||
  if (!ByRef) {
 | 
					 | 
				
			||||||
    // The variable will be bound by copy; make it const within the
 | 
					 | 
				
			||||||
    // closure, but record that this was done in the expression.
 | 
					 | 
				
			||||||
    bool constAdded = !exprType.isConstQualified();
 | 
					 | 
				
			||||||
    exprType.addConst();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    BDRE = new (S.Context) BlockDeclRefExpr(var, exprType, VK_LValue,
 | 
					 | 
				
			||||||
                                            NameInfo.getLoc(), false,
 | 
					 | 
				
			||||||
                                            constAdded);
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    BDRE = new (S.Context) BlockDeclRefExpr(var, exprType, VK_LValue,
 | 
					 | 
				
			||||||
                                            NameInfo.getLoc(), true);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  S.MarkBlockDeclRefReferenced(BDRE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return S.Owned(BDRE);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ExprResult
 | 
					ExprResult
 | 
				
			||||||
Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
 | 
					Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
 | 
				
			||||||
                       SourceLocation Loc,
 | 
					                       SourceLocation Loc,
 | 
				
			||||||
| 
						 | 
					@ -2323,6 +2098,68 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
 | 
				
			||||||
  return Owned(ULE);
 | 
					  return Owned(ULE);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool shouldBuildBlockDeclRef(ValueDecl *D, Sema &S) {
 | 
				
			||||||
 | 
					  // Check for a variable with local storage not from the current scope;
 | 
				
			||||||
 | 
					  // we need to create BlockDeclRefExprs for these.
 | 
				
			||||||
 | 
					  // FIXME: BlockDeclRefExpr shouldn't exist!
 | 
				
			||||||
 | 
					  VarDecl *var = dyn_cast<VarDecl>(D);
 | 
				
			||||||
 | 
					  if (!var)
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  if (var->getDeclContext() == S.CurContext)
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  if (!var->hasLocalStorage())
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  return S.getCurBlock() != 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool shouldAddConstQualToVarRef(ValueDecl *D, Sema &S) {
 | 
				
			||||||
 | 
					  VarDecl *var = dyn_cast<VarDecl>(D);
 | 
				
			||||||
 | 
					  if (!var)
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  if (var->getDeclContext() == S.CurContext)
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  if (!var->hasLocalStorage())
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  LambdaScopeInfo *LSI = S.getCurLambda();
 | 
				
			||||||
 | 
					  if (!LSI)
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // We don't actually allow capturing a __block variable in a lambda, but
 | 
				
			||||||
 | 
					  // this way gives better diagnostics.
 | 
				
			||||||
 | 
					  if (var->hasAttr<BlocksAttr>())
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // FIXME: Does the addition of const really only apply in
 | 
				
			||||||
 | 
					  // potentially-evaluated contexts?  The text in the lambda spec
 | 
				
			||||||
 | 
					  // about decltype hints that it might apply in unevaluated contexts
 | 
				
			||||||
 | 
					  // as well... and there's precent in our blocks implementation.
 | 
				
			||||||
 | 
					  return !LSI->Mutable &&
 | 
				
			||||||
 | 
					         S.ExprEvalContexts.back().Context != Sema::Unevaluated;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ExprResult BuildBlockDeclRefExpr(Sema &S, ValueDecl *VD,
 | 
				
			||||||
 | 
					                                        const DeclarationNameInfo &NameInfo) {
 | 
				
			||||||
 | 
					  VarDecl *var = cast<VarDecl>(VD);
 | 
				
			||||||
 | 
					  QualType exprType = var->getType().getNonReferenceType();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool HasBlockAttr = var->hasAttr<BlocksAttr>();
 | 
				
			||||||
 | 
					  bool ConstAdded = false;
 | 
				
			||||||
 | 
					  if (!HasBlockAttr) {
 | 
				
			||||||
 | 
					    ConstAdded = !exprType.isConstQualified();
 | 
				
			||||||
 | 
					    exprType.addConst();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  BlockDeclRefExpr *BDRE =
 | 
				
			||||||
 | 
					      new (S.Context) BlockDeclRefExpr(var, exprType, VK_LValue,
 | 
				
			||||||
 | 
					                                       NameInfo.getLoc(), HasBlockAttr,
 | 
				
			||||||
 | 
					                                       ConstAdded);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  S.MarkBlockDeclRefReferenced(BDRE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return S.Owned(BDRE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// \brief Complete semantic analysis for a reference to the given declaration.
 | 
					/// \brief Complete semantic analysis for a reference to the given declaration.
 | 
				
			||||||
ExprResult
 | 
					ExprResult
 | 
				
			||||||
Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
 | 
					Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
 | 
				
			||||||
| 
						 | 
					@ -2373,30 +2210,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
 | 
				
			||||||
      return BuildAnonymousStructUnionMemberReference(SS, NameInfo.getLoc(),
 | 
					      return BuildAnonymousStructUnionMemberReference(SS, NameInfo.getLoc(),
 | 
				
			||||||
                                                      indirectField);
 | 
					                                                      indirectField);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // If the identifier reference is inside a block, and it refers to a value
 | 
					  {
 | 
				
			||||||
  // that is outside the block, create a BlockDeclRefExpr instead of a
 | 
					 | 
				
			||||||
  // DeclRefExpr.  This ensures the value is treated as a copy-in snapshot when
 | 
					 | 
				
			||||||
  // the block is formed.
 | 
					 | 
				
			||||||
  //
 | 
					 | 
				
			||||||
  // We do not do this for things like enum constants, global variables, etc,
 | 
					 | 
				
			||||||
  // as they do not get snapshotted.
 | 
					 | 
				
			||||||
  //
 | 
					 | 
				
			||||||
  switch (shouldCaptureValueReference(*this, NameInfo.getLoc(), VD)) {
 | 
					 | 
				
			||||||
  case CR_Error:
 | 
					 | 
				
			||||||
    return ExprError();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  case CR_Capture:
 | 
					 | 
				
			||||||
    assert(!SS.isSet() && "referenced local variable with scope specifier?");
 | 
					 | 
				
			||||||
    return BuildBlockDeclRefExpr(*this, VD, NameInfo, /*byref*/ false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  case CR_CaptureByRef:
 | 
					 | 
				
			||||||
    assert(!SS.isSet() && "referenced local variable with scope specifier?");
 | 
					 | 
				
			||||||
    return BuildBlockDeclRefExpr(*this, VD, NameInfo, /*byref*/ true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  case CR_NoCapture: {
 | 
					 | 
				
			||||||
    // If this reference is not in a block or if the referenced
 | 
					 | 
				
			||||||
    // variable is within the block, create a normal DeclRefExpr.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    QualType type = VD->getType();
 | 
					    QualType type = VD->getType();
 | 
				
			||||||
    ExprValueKind valueKind = VK_RValue;
 | 
					    ExprValueKind valueKind = VK_RValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2467,6 +2281,13 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
 | 
				
			||||||
      // These are always l-values.
 | 
					      // These are always l-values.
 | 
				
			||||||
      valueKind = VK_LValue;
 | 
					      valueKind = VK_LValue;
 | 
				
			||||||
      type = type.getNonReferenceType();
 | 
					      type = type.getNonReferenceType();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (shouldBuildBlockDeclRef(VD, *this))
 | 
				
			||||||
 | 
					        return BuildBlockDeclRefExpr(*this, VD, NameInfo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (shouldAddConstQualToVarRef(VD, *this))
 | 
				
			||||||
 | 
					        type.addConst();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case Decl::Function: {
 | 
					    case Decl::Function: {
 | 
				
			||||||
| 
						 | 
					@ -2529,10 +2350,6 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS);
 | 
					    return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  llvm_unreachable("unknown capture result");
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
 | 
					ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
 | 
				
			||||||
| 
						 | 
					@ -9613,6 +9430,129 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
 | 
				
			||||||
  Func->setUsed(true);
 | 
					  Func->setUsed(true);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
 | 
				
			||||||
 | 
					                                   VarDecl *var, DeclContext *DC) {
 | 
				
			||||||
 | 
					  //  If the parameter still belongs to the translation unit, then
 | 
				
			||||||
 | 
					  //  we're actually just using one parameter in the declaration of
 | 
				
			||||||
 | 
					  //  the next.
 | 
				
			||||||
 | 
					  if (isa<ParmVarDecl>(var) &&
 | 
				
			||||||
 | 
					      isa<TranslationUnitDecl>(var->getDeclContext()))
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Don't diagnose about capture if we're not actually in code right
 | 
				
			||||||
 | 
					  // now; in general, there are more appropriate places that will
 | 
				
			||||||
 | 
					  // diagnose this.
 | 
				
			||||||
 | 
					  // FIXME: We incorrectly skip diagnosing C++11 member initializers.
 | 
				
			||||||
 | 
					  if (!S.CurContext->isFunctionOrMethod())
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  DeclarationName functionName;
 | 
				
			||||||
 | 
					  if (FunctionDecl *fn = dyn_cast<FunctionDecl>(var->getDeclContext()))
 | 
				
			||||||
 | 
					    functionName = fn->getDeclName();
 | 
				
			||||||
 | 
					  // FIXME: variable from enclosing block that we couldn't capture from!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  S.Diag(loc, diag::err_reference_to_local_var_in_enclosing_function)
 | 
				
			||||||
 | 
					    << var->getIdentifier() << functionName;
 | 
				
			||||||
 | 
					  S.Diag(var->getLocation(), diag::note_local_variable_declared_here)
 | 
				
			||||||
 | 
					    << var->getIdentifier();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void tryCaptureVar(Sema &S, VarDecl *var,
 | 
				
			||||||
 | 
					                          SourceLocation loc) {
 | 
				
			||||||
 | 
					  // Check if the variable needs to be captured.
 | 
				
			||||||
 | 
					  DeclContext *DC = S.CurContext;
 | 
				
			||||||
 | 
					  if (var->getDeclContext() == DC) return;
 | 
				
			||||||
 | 
					  if (!var->hasLocalStorage()) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Actually try to capture it.
 | 
				
			||||||
 | 
					  QualType type = var->getType();
 | 
				
			||||||
 | 
					  bool Nested = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  unsigned functionScopesIndex = S.FunctionScopes.size() - 1;
 | 
				
			||||||
 | 
					  do {
 | 
				
			||||||
 | 
					    // Only blocks (and eventually C++0x closures) can capture; other
 | 
				
			||||||
 | 
					    // scopes don't work.
 | 
				
			||||||
 | 
					    // FIXME: Make this function support lambdas!
 | 
				
			||||||
 | 
					    if (!isa<BlockDecl>(DC))
 | 
				
			||||||
 | 
					      return diagnoseUncapturableValueReference(S, loc, var, DC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    BlockScopeInfo *blockScope =
 | 
				
			||||||
 | 
					      cast<BlockScopeInfo>(S.FunctionScopes[functionScopesIndex]);
 | 
				
			||||||
 | 
					    assert(blockScope->TheDecl == static_cast<BlockDecl*>(DC));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check whether we've already captured it in this block.
 | 
				
			||||||
 | 
					    if (blockScope->CaptureMap.count(var)) {
 | 
				
			||||||
 | 
					      Nested = true;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    functionScopesIndex--;
 | 
				
			||||||
 | 
					    DC = cast<BlockDecl>(DC)->getDeclContext();
 | 
				
			||||||
 | 
					  } while (var->getDeclContext() != DC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool byRef = var->hasAttr<BlocksAttr>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (unsigned i = functionScopesIndex + 1,
 | 
				
			||||||
 | 
					                e = S.FunctionScopes.size(); i != e; ++i) {
 | 
				
			||||||
 | 
					    // Prohibit variably-modified types.
 | 
				
			||||||
 | 
					    if (type->isVariablyModifiedType()) {
 | 
				
			||||||
 | 
					      S.Diag(loc, diag::err_ref_vm_type);
 | 
				
			||||||
 | 
					      S.Diag(var->getLocation(), diag::note_declared_at);
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Prohibit arrays, even in __block variables, but not references to
 | 
				
			||||||
 | 
					    // them.
 | 
				
			||||||
 | 
					    if (type->isArrayType()) {
 | 
				
			||||||
 | 
					      S.Diag(loc, diag::err_ref_array_type);
 | 
				
			||||||
 | 
					      S.Diag(var->getLocation(), diag::note_declared_at);
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Build a copy expression.
 | 
				
			||||||
 | 
					    Expr *copyExpr = 0;
 | 
				
			||||||
 | 
					    const RecordType *rtype;
 | 
				
			||||||
 | 
					    if (!byRef && S.getLangOptions().CPlusPlus && !type->isDependentType() &&
 | 
				
			||||||
 | 
					        (rtype = type->getAs<RecordType>())) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // The capture logic needs the destructor, so make sure we mark it.
 | 
				
			||||||
 | 
					      // Usually this is unnecessary because most local variables have
 | 
				
			||||||
 | 
					      // their destructors marked at declaration time, but parameters are
 | 
				
			||||||
 | 
					      // an exception because it's technically only the call site that
 | 
				
			||||||
 | 
					      // actually requires the destructor.
 | 
				
			||||||
 | 
					      if (isa<ParmVarDecl>(var))
 | 
				
			||||||
 | 
					        S.FinalizeVarWithDestructor(var, rtype);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // According to the blocks spec, the capture of a variable from
 | 
				
			||||||
 | 
					      // the stack requires a const copy constructor.  This is not true
 | 
				
			||||||
 | 
					      // of the copy/move done to move a __block variable to the heap.
 | 
				
			||||||
 | 
					      type.addConst();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Expr *declRef = new (S.Context) DeclRefExpr(var, type, VK_LValue, loc);
 | 
				
			||||||
 | 
					      ExprResult result =
 | 
				
			||||||
 | 
					        S.PerformCopyInitialization(
 | 
				
			||||||
 | 
					                        InitializedEntity::InitializeBlock(var->getLocation(),
 | 
				
			||||||
 | 
					                                                           type, false),
 | 
				
			||||||
 | 
					                                    loc, S.Owned(declRef));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Build a full-expression copy expression if initialization
 | 
				
			||||||
 | 
					      // succeeded and used a non-trivial constructor.  Recover from
 | 
				
			||||||
 | 
					      // errors by pretending that the copy isn't necessary.
 | 
				
			||||||
 | 
					      if (!result.isInvalid() &&
 | 
				
			||||||
 | 
					          !cast<CXXConstructExpr>(result.get())->getConstructor()->isTrivial()) {
 | 
				
			||||||
 | 
					        result = S.MaybeCreateExprWithCleanups(result);
 | 
				
			||||||
 | 
					        copyExpr = result.take();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    BlockScopeInfo *blockScope = cast<BlockScopeInfo>(S.FunctionScopes[i]);
 | 
				
			||||||
 | 
					    blockScope->AddCapture(var, byRef, Nested, loc, copyExpr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Nested = true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void MarkVarDeclODRUsed(Sema &SemaRef, VarDecl *Var,
 | 
					static void MarkVarDeclODRUsed(Sema &SemaRef, VarDecl *Var,
 | 
				
			||||||
                               SourceLocation Loc) {
 | 
					                               SourceLocation Loc) {
 | 
				
			||||||
  // Keep track of used but undefined variables.
 | 
					  // Keep track of used but undefined variables.
 | 
				
			||||||
| 
						 | 
					@ -9622,6 +9562,8 @@ static void MarkVarDeclODRUsed(Sema &SemaRef, VarDecl *Var,
 | 
				
			||||||
    if (old.isInvalid()) old = Loc;
 | 
					    if (old.isInvalid()) old = Loc;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  tryCaptureVar(SemaRef, Var, Loc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Var->setUsed(true);
 | 
					  Var->setUsed(true);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9665,9 +9607,6 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
 | 
				
			||||||
                                    VarDecl *Var, Expr *E) {
 | 
					                                    VarDecl *Var, Expr *E) {
 | 
				
			||||||
  Var->setReferenced();
 | 
					  Var->setReferenced();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (Var->isUsed(false))
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!IsPotentiallyEvaluatedContext(SemaRef))
 | 
					  if (!IsPotentiallyEvaluatedContext(SemaRef))
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue