diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index ef4fc47567a7c..422149896fb36 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -694,7 +694,6 @@ class Sema final : public SemaBase { Scope *getScopeForContext(DeclContext *Ctx); void PushFunctionScope(); - void PushBlockScope(Scope *BlockScope, BlockDecl *Block); sema::LambdaScopeInfo *PushLambdaScope(); /// This is used to inform Sema what the current TemplateParameterDepth @@ -736,9 +735,6 @@ class Sema final : public SemaBase { bool hasAnyUnrecoverableErrorsInThisFunction() const; - /// Retrieve the current block, if any. - sema::BlockScopeInfo *getCurBlock(); - /// Get the innermost lambda enclosing the current location, if any. This /// looks through intervening non-lambda scopes such as local functions and /// blocks. @@ -2182,14 +2178,6 @@ class Sema final : public SemaBase { void CheckCastAlign(Expr *Op, QualType T, SourceRange TRange); - /// checkUnsafeAssigns - Check whether +1 expr is being assigned - /// to weak/__unsafe_unretained type. - bool checkUnsafeAssigns(SourceLocation Loc, QualType LHS, Expr *RHS); - - /// checkUnsafeExprAssigns - Check whether +1 expr is being assigned - /// to weak/__unsafe_unretained expression. - void checkUnsafeExprAssigns(SourceLocation Loc, Expr *LHS, Expr *RHS); - /// Emit \p DiagID if statement located on \p StmtLoc has a suspicious null /// statement as a \p Body, and it is located on the same line. /// @@ -3853,8 +3841,6 @@ class Sema final : public SemaBase { void AddLaunchBoundsAttr(Decl *D, const AttributeCommonInfo &CI, Expr *MaxThreads, Expr *MinBlocks, Expr *MaxBlocks); - enum class RetainOwnershipKind { NS, CF, OS }; - UuidAttr *mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI, StringRef UuidAsWritten, MSGuidDecl *GuidDecl); @@ -5833,26 +5819,6 @@ class Sema final : public SemaBase { bool CheckCaseExpression(Expr *E); - //===------------------------- "Block" Extension ------------------------===// - - /// ActOnBlockStart - This callback is invoked when a block literal is - /// started. - void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope); - - /// ActOnBlockArguments - This callback allows processing of block arguments. - /// If there are no arguments, this is still invoked. - void ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, - Scope *CurScope); - - /// ActOnBlockError - If there is an error parsing a block, this callback - /// is invoked to pop the information about the block from the action impl. - void ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope); - - /// ActOnBlockStmtExpr - This is called when the body of a block statement - /// literal was successfully completed. ^(int x){...} - ExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc, Stmt *Body, - Scope *CurScope); - //===---------------------------- Clang Extensions ----------------------===// /// __builtin_convertvector(...) @@ -6571,13 +6537,6 @@ class Sema final : public SemaBase { // Set of failed immediate invocations to avoid double diagnosing. llvm::SmallPtrSet FailedImmediateInvocations; - /// List of SourceLocations where 'self' is implicitly retained inside a - /// block. - llvm::SmallVector, 1> - ImplicitlyRetainedSelfLocs; - - void maybeExtendBlockObject(ExprResult &E); - private: static BinaryOperatorKind ConvertTokenKindToBinaryOpcode(tok::TokenKind Kind); diff --git a/clang/include/clang/Sema/SemaObjC.h b/clang/include/clang/Sema/SemaObjC.h index 07c3c1a06be16..c962d48799ec5 100644 --- a/clang/include/clang/Sema/SemaObjC.h +++ b/clang/include/clang/Sema/SemaObjC.h @@ -179,6 +179,13 @@ class SemaObjC : public SemaBase { /// target type. void checkArrayLiteral(QualType TargetType, ObjCArrayLiteral *ArrayLiteral); + /// Retrieve the current block, if any. + sema::BlockScopeInfo *getCurBlock(); + + void PushBlockScope(Scope *BlockScope, BlockDecl *Block); + + void diagnoseImplicitlyRetainedSelf(); + private: IdentifierInfo *Ident_NSError = nullptr; @@ -571,6 +578,21 @@ class SemaObjC : public SemaBase { ObjCContainerDecl *getObjCDeclContext() const; + /// List of SourceLocations where 'self' is implicitly retained inside a + /// block. + llvm::SmallVector, 1> + ImplicitlyRetainedSelfLocs; + + /// checkUnsafeAssigns - Check whether +1 expr is being assigned + /// to weak/__unsafe_unretained type. + bool checkUnsafeAssigns(SourceLocation Loc, QualType LHS, Expr *RHS); + + /// checkUnsafeExprAssigns - Check whether +1 expr is being assigned + /// to weak/__unsafe_unretained expression. + void checkUnsafeExprAssigns(SourceLocation Loc, Expr *LHS, Expr *RHS); + + enum class RetainOwnershipKind { NS, CF, OS }; + private: /// AddMethodToGlobalPool - Add an instance or factory method to the global /// pool. See descriptoin of AddInstanceMethodToGlobalPool. @@ -925,6 +947,27 @@ class SemaObjC : public SemaBase { }; ObjCLiteralKind CheckLiteralKind(Expr *FromE); + /// Do an explicit extend of the given block pointer if we're in ARC. + void maybeExtendBlockObject(ExprResult &E); + + /// ActOnBlockStart - This callback is invoked when a block literal is + /// started. + void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope); + + /// ActOnBlockArguments - This callback allows processing of block arguments. + /// If there are no arguments, this is still invoked. + void ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, + Scope *CurScope); + + /// ActOnBlockError - If there is an error parsing a block, this callback + /// is invoked to pop the information about the block from the action impl. + void ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope); + + /// ActOnBlockStmtExpr - This is called when the body of a block statement + /// literal was successfully completed. ^(int x){...} + ExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc, Stmt *Body, + Scope *CurScope); + ///@} // @@ -1067,15 +1110,13 @@ class SemaObjC : public SemaBase { void handleExternallyRetainedAttr(Decl *D, const ParsedAttr &AL); void AddXConsumedAttr(Decl *D, const AttributeCommonInfo &CI, - Sema::RetainOwnershipKind K, - bool IsTemplateInstantiation); + RetainOwnershipKind K, bool IsTemplateInstantiation); /// \return whether the parameter is a pointer to OSObject pointer. bool isValidOSObjectOutParameter(const Decl *D); bool checkNSReturnsRetainedReturnType(SourceLocation loc, QualType type); - Sema::RetainOwnershipKind - parsedAttrToRetainOwnershipKind(const ParsedAttr &AL); + RetainOwnershipKind parsedAttrToRetainOwnershipKind(const ParsedAttr &AL); ///@} }; diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 9fc3cd73f73a0..ab744c68872d3 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -3733,7 +3733,7 @@ void Parser::ParseBlockId(SourceLocation CaretLoc) { MaybeParseGNUAttributes(DeclaratorInfo); // Inform sema that we are starting a block. - Actions.ActOnBlockArguments(CaretLoc, DeclaratorInfo, getCurScope()); + Actions.ObjC().ActOnBlockArguments(CaretLoc, DeclaratorInfo, getCurScope()); } /// ParseBlockLiteralExpression - Parse a block literal, which roughly looks @@ -3761,7 +3761,7 @@ ExprResult Parser::ParseBlockLiteralExpression() { Scope::CompoundStmtScope | Scope::DeclScope); // Inform sema that we are starting a block. - Actions.ActOnBlockStart(CaretLoc, getCurScope()); + Actions.ObjC().ActOnBlockStart(CaretLoc, getCurScope()); // Parse the return type if present. DeclSpec DS(AttrFactory); @@ -3786,14 +3786,14 @@ ExprResult Parser::ParseBlockLiteralExpression() { // If there was an error parsing the arguments, they may have // tried to use ^(x+y) which requires an argument list. Just // skip the whole block literal. - Actions.ActOnBlockError(CaretLoc, getCurScope()); + Actions.ObjC().ActOnBlockError(CaretLoc, getCurScope()); return ExprError(); } MaybeParseGNUAttributes(ParamInfo); // Inform sema that we are starting a block. - Actions.ActOnBlockArguments(CaretLoc, ParamInfo, getCurScope()); + Actions.ObjC().ActOnBlockArguments(CaretLoc, ParamInfo, getCurScope()); } else if (!Tok.is(tok::l_brace)) { ParseBlockId(CaretLoc); } else { @@ -3823,7 +3823,7 @@ ExprResult Parser::ParseBlockLiteralExpression() { MaybeParseGNUAttributes(ParamInfo); // Inform sema that we are starting a block. - Actions.ActOnBlockArguments(CaretLoc, ParamInfo, getCurScope()); + Actions.ObjC().ActOnBlockArguments(CaretLoc, ParamInfo, getCurScope()); } @@ -3831,16 +3831,17 @@ ExprResult Parser::ParseBlockLiteralExpression() { if (!Tok.is(tok::l_brace)) { // Saw something like: ^expr Diag(Tok, diag::err_expected_expression); - Actions.ActOnBlockError(CaretLoc, getCurScope()); + Actions.ObjC().ActOnBlockError(CaretLoc, getCurScope()); return ExprError(); } StmtResult Stmt(ParseCompoundStatementBody()); BlockScope.Exit(); if (!Stmt.isInvalid()) - Result = Actions.ActOnBlockStmtExpr(CaretLoc, Stmt.get(), getCurScope()); + Result = + Actions.ObjC().ActOnBlockStmtExpr(CaretLoc, Stmt.get(), getCurScope()); else - Actions.ActOnBlockError(CaretLoc, getCurScope()); + Actions.ObjC().ActOnBlockError(CaretLoc, getCurScope()); return Result; } diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 3f8f2f027172d..e32192af436cf 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -2204,12 +2204,6 @@ void Sema::PushFunctionScope() { OpenMP().pushOpenMPFunctionRegion(); } -void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) { - FunctionScopes.push_back(new BlockScopeInfo(getDiagnostics(), - BlockScope, Block)); - CapturingFunctionScopes++; -} - LambdaScopeInfo *Sema::PushLambdaScope() { LambdaScopeInfo *const LSI = new LambdaScopeInfo(getDiagnostics()); FunctionScopes.push_back(LSI); @@ -2382,21 +2376,6 @@ void Sema::setFunctionHasMustTail() { FunctionScopes.back()->setHasMustTail(); } -BlockScopeInfo *Sema::getCurBlock() { - if (FunctionScopes.empty()) - return nullptr; - - auto CurBSI = dyn_cast(FunctionScopes.back()); - if (CurBSI && CurBSI->TheDecl && - !CurBSI->TheDecl->Encloses(CurContext)) { - // We have switched contexts due to template instantiation. - assert(!CodeSynthesisContexts.empty()); - return nullptr; - } - - return CurBSI; -} - FunctionScopeInfo *Sema::getEnclosingFunction() const { if (FunctionScopes.empty()) return nullptr; diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 005fbfd42a8ab..784606368b3ae 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -13457,124 +13457,6 @@ void Sema::CheckArrayAccess(const Expr *expr) { } } -static bool checkUnsafeAssignLiteral(Sema &S, SourceLocation Loc, - Expr *RHS, bool isProperty) { - // Check if RHS is an Objective-C object literal, which also can get - // immediately zapped in a weak reference. Note that we explicitly - // allow ObjCStringLiterals, since those are designed to never really die. - RHS = RHS->IgnoreParenImpCasts(); - - // This enum needs to match with the 'select' in - // warn_objc_arc_literal_assign (off-by-1). - SemaObjC::ObjCLiteralKind Kind = S.ObjC().CheckLiteralKind(RHS); - if (Kind == SemaObjC::LK_String || Kind == SemaObjC::LK_None) - return false; - - S.Diag(Loc, diag::warn_arc_literal_assign) - << (unsigned) Kind - << (isProperty ? 0 : 1) - << RHS->getSourceRange(); - - return true; -} - -static bool checkUnsafeAssignObject(Sema &S, SourceLocation Loc, - Qualifiers::ObjCLifetime LT, - Expr *RHS, bool isProperty) { - // Strip off any implicit cast added to get to the one ARC-specific. - while (ImplicitCastExpr *cast = dyn_cast(RHS)) { - if (cast->getCastKind() == CK_ARCConsumeObject) { - S.Diag(Loc, diag::warn_arc_retained_assign) - << (LT == Qualifiers::OCL_ExplicitNone) - << (isProperty ? 0 : 1) - << RHS->getSourceRange(); - return true; - } - RHS = cast->getSubExpr(); - } - - if (LT == Qualifiers::OCL_Weak && - checkUnsafeAssignLiteral(S, Loc, RHS, isProperty)) - return true; - - return false; -} - -bool Sema::checkUnsafeAssigns(SourceLocation Loc, - QualType LHS, Expr *RHS) { - Qualifiers::ObjCLifetime LT = LHS.getObjCLifetime(); - - if (LT != Qualifiers::OCL_Weak && LT != Qualifiers::OCL_ExplicitNone) - return false; - - if (checkUnsafeAssignObject(*this, Loc, LT, RHS, false)) - return true; - - return false; -} - -void Sema::checkUnsafeExprAssigns(SourceLocation Loc, - Expr *LHS, Expr *RHS) { - QualType LHSType; - // PropertyRef on LHS type need be directly obtained from - // its declaration as it has a PseudoType. - ObjCPropertyRefExpr *PRE - = dyn_cast(LHS->IgnoreParens()); - if (PRE && !PRE->isImplicitProperty()) { - const ObjCPropertyDecl *PD = PRE->getExplicitProperty(); - if (PD) - LHSType = PD->getType(); - } - - if (LHSType.isNull()) - LHSType = LHS->getType(); - - Qualifiers::ObjCLifetime LT = LHSType.getObjCLifetime(); - - if (LT == Qualifiers::OCL_Weak) { - if (!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc)) - getCurFunction()->markSafeWeakUse(LHS); - } - - if (checkUnsafeAssigns(Loc, LHSType, RHS)) - return; - - // FIXME. Check for other life times. - if (LT != Qualifiers::OCL_None) - return; - - if (PRE) { - if (PRE->isImplicitProperty()) - return; - const ObjCPropertyDecl *PD = PRE->getExplicitProperty(); - if (!PD) - return; - - unsigned Attributes = PD->getPropertyAttributes(); - if (Attributes & ObjCPropertyAttribute::kind_assign) { - // when 'assign' attribute was not explicitly specified - // by user, ignore it and rely on property type itself - // for lifetime info. - unsigned AsWrittenAttr = PD->getPropertyAttributesAsWritten(); - if (!(AsWrittenAttr & ObjCPropertyAttribute::kind_assign) && - LHSType->isObjCRetainableType()) - return; - - while (ImplicitCastExpr *cast = dyn_cast(RHS)) { - if (cast->getCastKind() == CK_ARCConsumeObject) { - Diag(Loc, diag::warn_arc_retained_property_assign) - << RHS->getSourceRange(); - return; - } - RHS = cast->getSubExpr(); - } - } else if (Attributes & ObjCPropertyAttribute::kind_weak) { - if (checkUnsafeAssignObject(*this, Loc, Qualifiers::OCL_Weak, RHS, true)) - return; - } - } -} - //===--- CHECK: Empty statement body (-Wempty-body) ---------------------===// static bool ShouldDiagnoseEmptyStmtBody(const SourceManager &SourceMgr, diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index cd1c5f9391ccd..0801cedf675fe 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -413,7 +413,7 @@ void PreferredTypeBuilder::enterReturn(Sema &S, SourceLocation Tok) { if (!Enabled) return; if (isa(S.CurContext)) { - if (sema::BlockScopeInfo *BSI = S.getCurBlock()) { + if (sema::BlockScopeInfo *BSI = S.ObjC().getCurBlock()) { ComputeType = nullptr; Type = BSI->ReturnType; ExpectedLoc = Tok; @@ -2473,9 +2473,10 @@ AddOrdinaryNameResults(SemaCodeCompletion::ParserCompletionContext CCC, ReturnType = Function->getReturnType(); else if (const auto *Method = dyn_cast(SemaRef.CurContext)) ReturnType = Method->getReturnType(); - else if (SemaRef.getCurBlock() && - !SemaRef.getCurBlock()->ReturnType.isNull()) - ReturnType = SemaRef.getCurBlock()->ReturnType;; + else if (SemaRef.ObjC().getCurBlock() && + !SemaRef.ObjC().getCurBlock()->ReturnType.isNull()) + ReturnType = SemaRef.ObjC().getCurBlock()->ReturnType; + ; if (ReturnType.isNull() || ReturnType->isVoidType()) { Builder.AddTypedTextChunk("return"); Builder.AddChunk(CodeCompletionString::CK_SemiColon); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 029ccf944c513..deb161ee352be 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -13782,7 +13782,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { VDecl->setType(DclT); if (!VDecl->isInvalidDecl()) { - checkUnsafeAssigns(VDecl->getLocation(), VDecl->getType(), Init); + ObjC().checkUnsafeAssigns(VDecl->getLocation(), VDecl->getType(), Init); if (VDecl->hasAttr()) ObjC().checkRetainCycles(VDecl, Init); @@ -16016,35 +16016,6 @@ class ExitFunctionBodyRAII { bool IsLambda = false; }; -static void diagnoseImplicitlyRetainedSelf(Sema &S) { - llvm::DenseMap EscapeInfo; - - auto IsOrNestedInEscapingBlock = [&](const BlockDecl *BD) { - if (EscapeInfo.count(BD)) - return EscapeInfo[BD]; - - bool R = false; - const BlockDecl *CurBD = BD; - - do { - R = !CurBD->doesNotEscape(); - if (R) - break; - CurBD = CurBD->getParent()->getInnermostBlockDecl(); - } while (CurBD); - - return EscapeInfo[BD] = R; - }; - - // If the location where 'self' is implicitly retained is inside a escaping - // block, emit a diagnostic. - for (const std::pair &P : - S.ImplicitlyRetainedSelfLocs) - if (IsOrNestedInEscapingBlock(P.second)) - S.Diag(P.first, diag::warn_implicitly_retains_self) - << FixItHint::CreateInsertion(P.first, "self->"); -} - static bool methodHasName(const FunctionDecl *FD, StringRef Name) { return isa(FD) && FD->param_empty() && FD->getDeclName().isIdentifier() && FD->getName() == Name; @@ -16392,7 +16363,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, FSI->ObjCWarnForNoInitDelegation = false; } - diagnoseImplicitlyRetainedSelf(*this); + ObjC().diagnoseImplicitlyRetainedSelf(); } else { // Parsing the function declaration failed in some way. Pop the fake scope // we pushed on. diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 807453400abdd..d60d9968b7957 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -368,7 +368,7 @@ HasExplicitOwnershipAttr(Sema &S, ParmVarDecl *Param) { /// and user declared, in the method definition's AST. void SemaObjC::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { ASTContext &Context = getASTContext(); - SemaRef.ImplicitlyRetainedSelfLocs.clear(); + ImplicitlyRetainedSelfLocs.clear(); assert((SemaRef.getCurMethodDecl() == nullptr) && "Methodparsing confused"); ObjCMethodDecl *MDecl = dyn_cast_or_null(D); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index db44cfe1288b6..9bc771a34073a 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -1070,7 +1070,7 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, // Copy blocks to the heap. if (ExprRes.get()->getType()->isBlockPointerType()) - maybeExtendBlockObject(ExprRes); + ObjC().maybeExtendBlockObject(ExprRes); E = ExprRes.get(); @@ -7306,20 +7306,6 @@ Sema::BuildInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, return E; } -/// Do an explicit extend of the given block pointer if we're in ARC. -void Sema::maybeExtendBlockObject(ExprResult &E) { - assert(E.get()->getType()->isBlockPointerType()); - assert(E.get()->isPRValue()); - - // Only do this in an r-value context. - if (!getLangOpts().ObjCAutoRefCount) return; - - E = ImplicitCastExpr::Create( - Context, E.get()->getType(), CK_ARCExtendBlockObject, E.get(), - /*base path*/ nullptr, VK_PRValue, FPOptionsOverride()); - Cleanup.setExprNeedsCleanups(true); -} - /// Prepares for a scalar cast, performing all the necessary stages /// except the final cast and returning the kind required. CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) { @@ -7356,7 +7342,7 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) { return CK_BitCast; if (SrcKind == Type::STK_CPointer) return CK_CPointerToObjCPointerCast; - maybeExtendBlockObject(Src); + ObjC().maybeExtendBlockObject(Src); return CK_BlockPointerToObjCPointerCast; case Type::STK_Bool: return CK_PointerToBoolean; @@ -9545,7 +9531,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, if (RHSType->isBlockPointerType() && LHSType->isBlockCompatibleObjCPointerType(Context)) { if (ConvertRHS) - maybeExtendBlockObject(RHS); + ObjC().maybeExtendBlockObject(RHS); Kind = CK_BlockPointerToObjCPointerCast; return Compatible; } @@ -13764,7 +13750,7 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, getCurFunction()->markSafeWeakUse(RHS.get()); } else if (getLangOpts().ObjCAutoRefCount || getLangOpts().ObjCWeak) { - checkUnsafeExprAssigns(Loc, LHSExpr, RHS.get()); + ObjC().checkUnsafeExprAssigns(Loc, LHSExpr, RHS.get()); } } } else { @@ -16081,358 +16067,6 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, // Clang Extensions. //===----------------------------------------------------------------------===// -/// ActOnBlockStart - This callback is invoked when a block literal is started. -void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) { - BlockDecl *Block = BlockDecl::Create(Context, CurContext, CaretLoc); - - if (LangOpts.CPlusPlus) { - MangleNumberingContext *MCtx; - Decl *ManglingContextDecl; - std::tie(MCtx, ManglingContextDecl) = - getCurrentMangleNumberContext(Block->getDeclContext()); - if (MCtx) { - unsigned ManglingNumber = MCtx->getManglingNumber(Block); - Block->setBlockMangling(ManglingNumber, ManglingContextDecl); - } - } - - PushBlockScope(CurScope, Block); - CurContext->addDecl(Block); - if (CurScope) - PushDeclContext(CurScope, Block); - else - CurContext = Block; - - getCurBlock()->HasImplicitReturnType = true; - - // Enter a new evaluation context to insulate the block from any - // cleanups from the enclosing full-expression. - PushExpressionEvaluationContext( - ExpressionEvaluationContext::PotentiallyEvaluated); -} - -void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, - Scope *CurScope) { - assert(ParamInfo.getIdentifier() == nullptr && - "block-id should have no identifier!"); - assert(ParamInfo.getContext() == DeclaratorContext::BlockLiteral); - BlockScopeInfo *CurBlock = getCurBlock(); - - TypeSourceInfo *Sig = GetTypeForDeclarator(ParamInfo); - QualType T = Sig->getType(); - - // FIXME: We should allow unexpanded parameter packs here, but that would, - // in turn, make the block expression contain unexpanded parameter packs. - if (DiagnoseUnexpandedParameterPack(CaretLoc, Sig, UPPC_Block)) { - // Drop the parameters. - FunctionProtoType::ExtProtoInfo EPI; - EPI.HasTrailingReturn = false; - EPI.TypeQuals.addConst(); - T = Context.getFunctionType(Context.DependentTy, std::nullopt, EPI); - Sig = Context.getTrivialTypeSourceInfo(T); - } - - // GetTypeForDeclarator always produces a function type for a block - // literal signature. Furthermore, it is always a FunctionProtoType - // unless the function was written with a typedef. - assert(T->isFunctionType() && - "GetTypeForDeclarator made a non-function block signature"); - - // Look for an explicit signature in that function type. - FunctionProtoTypeLoc ExplicitSignature; - - if ((ExplicitSignature = Sig->getTypeLoc() - .getAsAdjusted())) { - - // Check whether that explicit signature was synthesized by - // GetTypeForDeclarator. If so, don't save that as part of the - // written signature. - if (ExplicitSignature.getLocalRangeBegin() == - ExplicitSignature.getLocalRangeEnd()) { - // This would be much cheaper if we stored TypeLocs instead of - // TypeSourceInfos. - TypeLoc Result = ExplicitSignature.getReturnLoc(); - unsigned Size = Result.getFullDataSize(); - Sig = Context.CreateTypeSourceInfo(Result.getType(), Size); - Sig->getTypeLoc().initializeFullCopy(Result, Size); - - ExplicitSignature = FunctionProtoTypeLoc(); - } - } - - CurBlock->TheDecl->setSignatureAsWritten(Sig); - CurBlock->FunctionType = T; - - const auto *Fn = T->castAs(); - QualType RetTy = Fn->getReturnType(); - bool isVariadic = - (isa(Fn) && cast(Fn)->isVariadic()); - - CurBlock->TheDecl->setIsVariadic(isVariadic); - - // Context.DependentTy is used as a placeholder for a missing block - // 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; - CurBlock->TheDecl->setBlockMissingReturnType(false); - CurBlock->HasImplicitReturnType = false; - } - - // Push block parameters from the declarator if we had them. - SmallVector Params; - if (ExplicitSignature) { - for (unsigned I = 0, E = ExplicitSignature.getNumParams(); I != E; ++I) { - ParmVarDecl *Param = ExplicitSignature.getParam(I); - if (Param->getIdentifier() == nullptr && !Param->isImplicit() && - !Param->isInvalidDecl() && !getLangOpts().CPlusPlus) { - // Diagnose this as an extension in C17 and earlier. - if (!getLangOpts().C23) - Diag(Param->getLocation(), diag::ext_parameter_name_omitted_c23); - } - Params.push_back(Param); - } - - // Fake up parameter variables if we have a typedef, like - // ^ fntype { ... } - } else if (const FunctionProtoType *Fn = T->getAs()) { - for (const auto &I : Fn->param_types()) { - ParmVarDecl *Param = BuildParmVarDeclForTypedef( - CurBlock->TheDecl, ParamInfo.getBeginLoc(), I); - Params.push_back(Param); - } - } - - // Set the parameters on the block decl. - if (!Params.empty()) { - CurBlock->TheDecl->setParams(Params); - CheckParmsForFunctionDef(CurBlock->TheDecl->parameters(), - /*CheckParameterNames=*/false); - } - - // Finally we can process decl attributes. - ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo); - - // Put the parameter variables in scope. - for (auto *AI : CurBlock->TheDecl->parameters()) { - AI->setOwningFunction(CurBlock->TheDecl); - - // If this has an identifier, add it to the scope stack. - if (AI->getIdentifier()) { - CheckShadow(CurBlock->TheScope, AI); - - PushOnScopeChains(AI, CurBlock->TheScope); - } - - if (AI->isInvalidDecl()) - CurBlock->TheDecl->setInvalidDecl(); - } -} - -/// ActOnBlockError - If there is an error parsing a block, this callback -/// is invoked to pop the information about the block from the action impl. -void Sema::ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) { - // Leave the expression-evaluation context. - DiscardCleanupsInEvaluationContext(); - PopExpressionEvaluationContext(); - - // Pop off CurBlock, handle nested blocks. - PopDeclContext(); - PopFunctionScopeInfo(); -} - -/// ActOnBlockStmtExpr - This is called when the body of a block statement -/// literal was successfully completed. ^(int x){...} -ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, - Stmt *Body, Scope *CurScope) { - // If blocks are disabled, emit an error. - if (!LangOpts.Blocks) - Diag(CaretLoc, diag::err_blocks_disable) << LangOpts.OpenCL; - - // Leave the expression-evaluation context. - if (hasAnyUnrecoverableErrorsInThisFunction()) - DiscardCleanupsInEvaluationContext(); - assert(!Cleanup.exprNeedsCleanups() && - "cleanups within block not correctly bound!"); - PopExpressionEvaluationContext(); - - BlockScopeInfo *BSI = cast(FunctionScopes.back()); - BlockDecl *BD = BSI->TheDecl; - - if (BSI->HasImplicitReturnType) - deduceClosureReturnType(*BSI); - - QualType RetTy = Context.VoidTy; - if (!BSI->ReturnType.isNull()) - RetTy = BSI->ReturnType; - - bool NoReturn = BD->hasAttr(); - QualType BlockTy; - - // If the user wrote a function type in some form, try to use that. - if (!BSI->FunctionType.isNull()) { - const FunctionType *FTy = BSI->FunctionType->castAs(); - - FunctionType::ExtInfo Ext = FTy->getExtInfo(); - if (NoReturn && !Ext.getNoReturn()) Ext = Ext.withNoReturn(true); - - // Turn protoless block types into nullary block types. - if (isa(FTy)) { - FunctionProtoType::ExtProtoInfo EPI; - EPI.ExtInfo = Ext; - BlockTy = Context.getFunctionType(RetTy, std::nullopt, EPI); - - // Otherwise, if we don't need to change anything about the function type, - // preserve its sugar structure. - } else if (FTy->getReturnType() == RetTy && - (!NoReturn || FTy->getNoReturnAttr())) { - BlockTy = BSI->FunctionType; - - // Otherwise, make the minimal modifications to the function type. - } else { - const FunctionProtoType *FPT = cast(FTy); - FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); - EPI.TypeQuals = Qualifiers(); - EPI.ExtInfo = Ext; - BlockTy = Context.getFunctionType(RetTy, FPT->getParamTypes(), EPI); - } - - // If we don't have a function type, just build one from nothing. - } else { - FunctionProtoType::ExtProtoInfo EPI; - EPI.ExtInfo = FunctionType::ExtInfo().withNoReturn(NoReturn); - BlockTy = Context.getFunctionType(RetTy, std::nullopt, EPI); - } - - DiagnoseUnusedParameters(BD->parameters()); - BlockTy = Context.getBlockPointerType(BlockTy); - - // If needed, diagnose invalid gotos and switches in the block. - if (getCurFunction()->NeedsScopeChecking() && - !PP.isCodeCompletionEnabled()) - DiagnoseInvalidJumps(cast(Body)); - - BD->setBody(cast(Body)); - - if (Body && getCurFunction()->HasPotentialAvailabilityViolations) - DiagnoseUnguardedAvailabilityViolations(BD); - - // Try to apply the named return value optimization. We have to check again - // if we can do this, though, because blocks keep return statements around - // to deduce an implicit return type. - if (getLangOpts().CPlusPlus && RetTy->isRecordType() && - !BD->isDependentContext()) - computeNRVO(Body, BSI); - - if (RetTy.hasNonTrivialToPrimitiveDestructCUnion() || - RetTy.hasNonTrivialToPrimitiveCopyCUnion()) - checkNonTrivialCUnion(RetTy, BD->getCaretLocation(), NTCUC_FunctionReturn, - NTCUK_Destruct|NTCUK_Copy); - - PopDeclContext(); - - // Set the captured variables on the block. - SmallVector Captures; - for (Capture &Cap : BSI->Captures) { - if (Cap.isInvalid() || Cap.isThisCapture()) - continue; - // Cap.getVariable() is always a VarDecl because - // blocks cannot capture structured bindings or other ValueDecl kinds. - auto *Var = cast(Cap.getVariable()); - Expr *CopyExpr = nullptr; - if (getLangOpts().CPlusPlus && Cap.isCopyCapture()) { - if (const RecordType *Record = - Cap.getCaptureType()->getAs()) { - // 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(Var)) - FinalizeVarWithDestructor(Var, Record); - - // Enter a separate potentially-evaluated context while building block - // initializers to isolate their cleanups from those of the block - // itself. - // FIXME: Is this appropriate even when the block itself occurs in an - // unevaluated operand? - EnterExpressionEvaluationContext EvalContext( - *this, ExpressionEvaluationContext::PotentiallyEvaluated); - - SourceLocation Loc = Cap.getLocation(); - - ExprResult Result = BuildDeclarationNameExpr( - CXXScopeSpec(), DeclarationNameInfo(Var->getDeclName(), Loc), Var); - - // 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. - if (!Result.isInvalid() && - !Result.get()->getType().isConstQualified()) { - Result = ImpCastExprToType(Result.get(), - Result.get()->getType().withConst(), - CK_NoOp, VK_LValue); - } - - if (!Result.isInvalid()) { - Result = PerformCopyInitialization( - InitializedEntity::InitializeBlock(Var->getLocation(), - Cap.getCaptureType()), - Loc, Result.get()); - } - - // 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(Result.get())->getConstructor() - ->isTrivial()) { - Result = MaybeCreateExprWithCleanups(Result); - CopyExpr = Result.get(); - } - } - } - - BlockDecl::Capture NewCap(Var, Cap.isBlockCapture(), Cap.isNested(), - CopyExpr); - Captures.push_back(NewCap); - } - BD->setCaptures(Context, Captures, BSI->CXXThisCaptureIndex != 0); - - // Pop the block scope now but keep it alive to the end of this function. - AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy(); - PoppedFunctionScopePtr ScopeRAII = PopFunctionScopeInfo(&WP, BD, BlockTy); - - BlockExpr *Result = new (Context) BlockExpr(BD, BlockTy); - - // If the block isn't obviously global, i.e. it captures anything at - // all, then we need to do a few things in the surrounding context: - if (Result->getBlockDecl()->hasCaptures()) { - // First, this expression has a new cleanup object. - ExprCleanupObjects.push_back(Result->getBlockDecl()); - Cleanup.setExprNeedsCleanups(true); - - // It also gets a branch-protected scope if any of the captured - // variables needs destruction. - for (const auto &CI : Result->getBlockDecl()->captures()) { - const VarDecl *var = CI.getVariable(); - if (var->getType().isDestructedType() != QualType::DK_none) { - setFunctionHasBranchProtectedScope(); - break; - } - } - } - - if (getCurFunction()) - getCurFunction()->addBlock(BD); - - if (BD->isInvalidDecl()) - return CreateRecoveryExpr(Result->getBeginLoc(), Result->getEndLoc(), - {Result}, Result->getType()); - return Result; -} - ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc, Expr *E, ParsedType Ty, SourceLocation RPLoc) { TypeSourceInfo *TInfo; diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 7ccecf055feed..b7aa09b78cc4a 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -21,6 +21,7 @@ #include "clang/Edit/Commit.h" #include "clang/Edit/Rewriters.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" @@ -1893,7 +1894,7 @@ bool SemaObjC::CheckMessageArgumentTypes( Args[i]->getType()->isBlockPointerType() && origParamType->isObjCObjectPointerType()) { ExprResult arg = Args[i]; - SemaRef.maybeExtendBlockObject(arg); + maybeExtendBlockObject(arg); Args[i] = arg.get(); } } @@ -4923,7 +4924,7 @@ ExprResult SemaObjC::BuildIvarRefExpr(Scope *S, SourceLocation Loc, } if (getLangOpts().ObjCAutoRefCount && !SemaRef.isUnevaluatedContext()) if (const BlockDecl *BD = SemaRef.CurContext->getInnermostBlockDecl()) - SemaRef.ImplicitlyRetainedSelfLocs.push_back({Loc, BD}); + ImplicitlyRetainedSelfLocs.push_back({Loc, BD}); return Result; } @@ -5197,7 +5198,7 @@ CastKind SemaObjC::PrepareCastToObjCObjectPointer(ExprResult &E) { if (type->isObjCObjectPointerType()) { return CK_BitCast; } else if (type->isBlockPointerType()) { - SemaRef.maybeExtendBlockObject(E); + maybeExtendBlockObject(E); return CK_BlockPointerToObjCPointerCast; } else { assert(type->isPointerType()); @@ -5246,3 +5247,379 @@ SemaObjC::ObjCLiteralKind SemaObjC::CheckLiteralKind(Expr *FromE) { } return LK_None; } + +void SemaObjC::maybeExtendBlockObject(ExprResult &E) { + assert(E.get()->getType()->isBlockPointerType()); + assert(E.get()->isPRValue()); + + // Only do this in an r-value context. + if (!getLangOpts().ObjCAutoRefCount) + return; + + E = ImplicitCastExpr::Create( + getASTContext(), E.get()->getType(), CK_ARCExtendBlockObject, E.get(), + /*base path*/ nullptr, VK_PRValue, FPOptionsOverride()); + SemaRef.Cleanup.setExprNeedsCleanups(true); +} + +/// ActOnBlockStart - This callback is invoked when a block literal is started. +void SemaObjC::ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) { + ASTContext &Context = getASTContext(); + BlockDecl *Block = BlockDecl::Create(Context, SemaRef.CurContext, CaretLoc); + + if (getLangOpts().CPlusPlus) { + MangleNumberingContext *MCtx; + Decl *ManglingContextDecl; + std::tie(MCtx, ManglingContextDecl) = + SemaRef.getCurrentMangleNumberContext(Block->getDeclContext()); + if (MCtx) { + unsigned ManglingNumber = MCtx->getManglingNumber(Block); + Block->setBlockMangling(ManglingNumber, ManglingContextDecl); + } + } + + PushBlockScope(CurScope, Block); + SemaRef.CurContext->addDecl(Block); + if (CurScope) + SemaRef.PushDeclContext(CurScope, Block); + else + SemaRef.CurContext = Block; + + getCurBlock()->HasImplicitReturnType = true; + + // Enter a new evaluation context to insulate the block from any + // cleanups from the enclosing full-expression. + SemaRef.PushExpressionEvaluationContext( + Sema::ExpressionEvaluationContext::PotentiallyEvaluated); +} + +void SemaObjC::ActOnBlockArguments(SourceLocation CaretLoc, + Declarator &ParamInfo, Scope *CurScope) { + assert(ParamInfo.getIdentifier() == nullptr && + "block-id should have no identifier!"); + assert(ParamInfo.getContext() == DeclaratorContext::BlockLiteral); + ASTContext &Context = getASTContext(); + BlockScopeInfo *CurBlock = getCurBlock(); + + TypeSourceInfo *Sig = SemaRef.GetTypeForDeclarator(ParamInfo); + QualType T = Sig->getType(); + + // FIXME: We should allow unexpanded parameter packs here, but that would, + // in turn, make the block expression contain unexpanded parameter packs. + if (SemaRef.DiagnoseUnexpandedParameterPack(CaretLoc, Sig, + Sema::UPPC_Block)) { + // Drop the parameters. + FunctionProtoType::ExtProtoInfo EPI; + EPI.HasTrailingReturn = false; + EPI.TypeQuals.addConst(); + T = Context.getFunctionType(Context.DependentTy, std::nullopt, EPI); + Sig = Context.getTrivialTypeSourceInfo(T); + } + + // GetTypeForDeclarator always produces a function type for a block + // literal signature. Furthermore, it is always a FunctionProtoType + // unless the function was written with a typedef. + assert(T->isFunctionType() && + "GetTypeForDeclarator made a non-function block signature"); + + // Look for an explicit signature in that function type. + FunctionProtoTypeLoc ExplicitSignature; + + if ((ExplicitSignature = + Sig->getTypeLoc().getAsAdjusted())) { + + // Check whether that explicit signature was synthesized by + // GetTypeForDeclarator. If so, don't save that as part of the + // written signature. + if (ExplicitSignature.getLocalRangeBegin() == + ExplicitSignature.getLocalRangeEnd()) { + // This would be much cheaper if we stored TypeLocs instead of + // TypeSourceInfos. + TypeLoc Result = ExplicitSignature.getReturnLoc(); + unsigned Size = Result.getFullDataSize(); + Sig = Context.CreateTypeSourceInfo(Result.getType(), Size); + Sig->getTypeLoc().initializeFullCopy(Result, Size); + + ExplicitSignature = FunctionProtoTypeLoc(); + } + } + + CurBlock->TheDecl->setSignatureAsWritten(Sig); + CurBlock->FunctionType = T; + + const auto *Fn = T->castAs(); + QualType RetTy = Fn->getReturnType(); + bool isVariadic = + (isa(Fn) && cast(Fn)->isVariadic()); + + CurBlock->TheDecl->setIsVariadic(isVariadic); + + // Context.DependentTy is used as a placeholder for a missing block + // 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; + CurBlock->TheDecl->setBlockMissingReturnType(false); + CurBlock->HasImplicitReturnType = false; + } + + // Push block parameters from the declarator if we had them. + SmallVector Params; + if (ExplicitSignature) { + for (unsigned I = 0, E = ExplicitSignature.getNumParams(); I != E; ++I) { + ParmVarDecl *Param = ExplicitSignature.getParam(I); + if (Param->getIdentifier() == nullptr && !Param->isImplicit() && + !Param->isInvalidDecl() && !getLangOpts().CPlusPlus) { + // Diagnose this as an extension in C17 and earlier. + if (!getLangOpts().C23) + Diag(Param->getLocation(), diag::ext_parameter_name_omitted_c23); + } + Params.push_back(Param); + } + + // Fake up parameter variables if we have a typedef, like + // ^ fntype { ... } + } else if (const FunctionProtoType *Fn = T->getAs()) { + for (const auto &I : Fn->param_types()) { + ParmVarDecl *Param = SemaRef.BuildParmVarDeclForTypedef( + CurBlock->TheDecl, ParamInfo.getBeginLoc(), I); + Params.push_back(Param); + } + } + + // Set the parameters on the block decl. + if (!Params.empty()) { + CurBlock->TheDecl->setParams(Params); + SemaRef.CheckParmsForFunctionDef(CurBlock->TheDecl->parameters(), + /*CheckParameterNames=*/false); + } + + // Finally we can process decl attributes. + SemaRef.ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo); + + // Put the parameter variables in scope. + for (auto *AI : CurBlock->TheDecl->parameters()) { + AI->setOwningFunction(CurBlock->TheDecl); + + // If this has an identifier, add it to the scope stack. + if (AI->getIdentifier()) { + SemaRef.CheckShadow(CurBlock->TheScope, AI); + + SemaRef.PushOnScopeChains(AI, CurBlock->TheScope); + } + + if (AI->isInvalidDecl()) + CurBlock->TheDecl->setInvalidDecl(); + } +} + +/// ActOnBlockError - If there is an error parsing a block, this callback +/// is invoked to pop the information about the block from the action impl. +void SemaObjC::ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) { + // Leave the expression-evaluation context. + SemaRef.DiscardCleanupsInEvaluationContext(); + SemaRef.PopExpressionEvaluationContext(); + + // Pop off CurBlock, handle nested blocks. + SemaRef.PopDeclContext(); + SemaRef.PopFunctionScopeInfo(); +} + +/// ActOnBlockStmtExpr - This is called when the body of a block statement +/// literal was successfully completed. ^(int x){...} +ExprResult SemaObjC::ActOnBlockStmtExpr(SourceLocation CaretLoc, Stmt *Body, + Scope *CurScope) { + // If blocks are disabled, emit an error. + if (!getLangOpts().Blocks) + Diag(CaretLoc, diag::err_blocks_disable) << getLangOpts().OpenCL; + + ASTContext &Context = getASTContext(); + + // Leave the expression-evaluation context. + if (SemaRef.hasAnyUnrecoverableErrorsInThisFunction()) + SemaRef.DiscardCleanupsInEvaluationContext(); + assert(!SemaRef.Cleanup.exprNeedsCleanups() && + "cleanups within block not correctly bound!"); + SemaRef.PopExpressionEvaluationContext(); + + BlockScopeInfo *BSI = cast(SemaRef.FunctionScopes.back()); + BlockDecl *BD = BSI->TheDecl; + + if (BSI->HasImplicitReturnType) + SemaRef.deduceClosureReturnType(*BSI); + + QualType RetTy = Context.VoidTy; + if (!BSI->ReturnType.isNull()) + RetTy = BSI->ReturnType; + + bool NoReturn = BD->hasAttr(); + QualType BlockTy; + + // If the user wrote a function type in some form, try to use that. + if (!BSI->FunctionType.isNull()) { + const FunctionType *FTy = BSI->FunctionType->castAs(); + + FunctionType::ExtInfo Ext = FTy->getExtInfo(); + if (NoReturn && !Ext.getNoReturn()) + Ext = Ext.withNoReturn(true); + + // Turn protoless block types into nullary block types. + if (isa(FTy)) { + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExtInfo = Ext; + BlockTy = Context.getFunctionType(RetTy, std::nullopt, EPI); + + // Otherwise, if we don't need to change anything about the function type, + // preserve its sugar structure. + } else if (FTy->getReturnType() == RetTy && + (!NoReturn || FTy->getNoReturnAttr())) { + BlockTy = BSI->FunctionType; + + // Otherwise, make the minimal modifications to the function type. + } else { + const FunctionProtoType *FPT = cast(FTy); + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + EPI.TypeQuals = Qualifiers(); + EPI.ExtInfo = Ext; + BlockTy = Context.getFunctionType(RetTy, FPT->getParamTypes(), EPI); + } + + // If we don't have a function type, just build one from nothing. + } else { + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExtInfo = FunctionType::ExtInfo().withNoReturn(NoReturn); + BlockTy = Context.getFunctionType(RetTy, std::nullopt, EPI); + } + + SemaRef.DiagnoseUnusedParameters(BD->parameters()); + BlockTy = Context.getBlockPointerType(BlockTy); + + // If needed, diagnose invalid gotos and switches in the block. + if (SemaRef.getCurFunction()->NeedsScopeChecking() && + !SemaRef.PP.isCodeCompletionEnabled()) + SemaRef.DiagnoseInvalidJumps(cast(Body)); + + BD->setBody(cast(Body)); + + if (Body && SemaRef.getCurFunction()->HasPotentialAvailabilityViolations) + SemaRef.DiagnoseUnguardedAvailabilityViolations(BD); + + // Try to apply the named return value optimization. We have to check again + // if we can do this, though, because blocks keep return statements around + // to deduce an implicit return type. + if (getLangOpts().CPlusPlus && RetTy->isRecordType() && + !BD->isDependentContext()) + SemaRef.computeNRVO(Body, BSI); + + if (RetTy.hasNonTrivialToPrimitiveDestructCUnion() || + RetTy.hasNonTrivialToPrimitiveCopyCUnion()) + SemaRef.checkNonTrivialCUnion(RetTy, BD->getCaretLocation(), + Sema::NTCUC_FunctionReturn, + Sema::NTCUK_Destruct | Sema::NTCUK_Copy); + + SemaRef.PopDeclContext(); + + // Set the captured variables on the block. + SmallVector Captures; + for (Capture &Cap : BSI->Captures) { + if (Cap.isInvalid() || Cap.isThisCapture()) + continue; + // Cap.getVariable() is always a VarDecl because + // blocks cannot capture structured bindings or other ValueDecl kinds. + auto *Var = cast(Cap.getVariable()); + Expr *CopyExpr = nullptr; + if (getLangOpts().CPlusPlus && Cap.isCopyCapture()) { + if (const RecordType *Record = + Cap.getCaptureType()->getAs()) { + // 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(Var)) + SemaRef.FinalizeVarWithDestructor(Var, Record); + + // Enter a separate potentially-evaluated context while building block + // initializers to isolate their cleanups from those of the block + // itself. + // FIXME: Is this appropriate even when the block itself occurs in an + // unevaluated operand? + EnterExpressionEvaluationContext EvalContext( + SemaRef, Sema::ExpressionEvaluationContext::PotentiallyEvaluated); + + SourceLocation Loc = Cap.getLocation(); + + ExprResult Result = SemaRef.BuildDeclarationNameExpr( + CXXScopeSpec(), DeclarationNameInfo(Var->getDeclName(), Loc), Var); + + // 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. + if (!Result.isInvalid() && + !Result.get()->getType().isConstQualified()) { + Result = SemaRef.ImpCastExprToType( + Result.get(), Result.get()->getType().withConst(), CK_NoOp, + VK_LValue); + } + + if (!Result.isInvalid()) { + Result = SemaRef.PerformCopyInitialization( + InitializedEntity::InitializeBlock(Var->getLocation(), + Cap.getCaptureType()), + Loc, Result.get()); + } + + // 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(Result.get()) + ->getConstructor() + ->isTrivial()) { + Result = SemaRef.MaybeCreateExprWithCleanups(Result); + CopyExpr = Result.get(); + } + } + } + + BlockDecl::Capture NewCap(Var, Cap.isBlockCapture(), Cap.isNested(), + CopyExpr); + Captures.push_back(NewCap); + } + BD->setCaptures(Context, Captures, BSI->CXXThisCaptureIndex != 0); + + // Pop the block scope now but keep it alive to the end of this function. + AnalysisBasedWarnings::Policy WP = + SemaRef.AnalysisWarnings.getDefaultPolicy(); + Sema::PoppedFunctionScopePtr ScopeRAII = + SemaRef.PopFunctionScopeInfo(&WP, BD, BlockTy); + + BlockExpr *Result = new (Context) BlockExpr(BD, BlockTy); + + // If the block isn't obviously global, i.e. it captures anything at + // all, then we need to do a few things in the surrounding context: + if (Result->getBlockDecl()->hasCaptures()) { + // First, this expression has a new cleanup object. + SemaRef.ExprCleanupObjects.push_back(Result->getBlockDecl()); + SemaRef.Cleanup.setExprNeedsCleanups(true); + + // It also gets a branch-protected scope if any of the captured + // variables needs destruction. + for (const auto &CI : Result->getBlockDecl()->captures()) { + const VarDecl *var = CI.getVariable(); + if (var->getType().isDestructedType() != QualType::DK_none) { + SemaRef.setFunctionHasBranchProtectedScope(); + break; + } + } + } + + if (SemaRef.getCurFunction()) + SemaRef.getCurFunction()->addBlock(BD); + + if (BD->isInvalidDecl()) + return SemaRef.CreateRecoveryExpr(Result->getBeginLoc(), + Result->getEndLoc(), {Result}, + Result->getType()); + return Result; +} diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 9a3fabc5933ee..14ad80f448924 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -34,6 +34,7 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaInternal.h" +#include "clang/Sema/SemaObjC.h" #include "clang/Sema/SemaRISCV.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/TypoCorrection.h" @@ -5191,7 +5192,7 @@ static void AddKeywordsToConsumer(Sema &SemaRef, } if (CCC.WantRemainingKeywords) { - if (SemaRef.getCurFunctionOrMethodDecl() || SemaRef.getCurBlock()) { + if (SemaRef.getCurFunctionOrMethodDecl() || SemaRef.ObjC().getCurBlock()) { // Statements. static const char *const CStmts[] = { "do", "else", "for", "goto", "if", "return", "switch", "while" }; diff --git a/clang/lib/Sema/SemaObjC.cpp b/clang/lib/Sema/SemaObjC.cpp index 75233689769c5..6cfea25c53855 100644 --- a/clang/lib/Sema/SemaObjC.cpp +++ b/clang/lib/Sema/SemaObjC.cpp @@ -1737,17 +1737,17 @@ static bool isValidSubjectOfOSAttribute(QualType QT) { } void SemaObjC::AddXConsumedAttr(Decl *D, const AttributeCommonInfo &CI, - Sema::RetainOwnershipKind K, + RetainOwnershipKind K, bool IsTemplateInstantiation) { ValueDecl *VD = cast(D); switch (K) { - case Sema::RetainOwnershipKind::OS: + case RetainOwnershipKind::OS: handleSimpleAttributeOrDiagnose( *this, VD, CI, isValidSubjectOfOSAttribute(VD->getType()), diag::warn_ns_attribute_wrong_parameter_type, /*ExtraArgs=*/CI.getRange(), "os_consumed", /*pointers*/ 1); return; - case Sema::RetainOwnershipKind::NS: + case RetainOwnershipKind::NS: handleSimpleAttributeOrDiagnose( *this, VD, CI, isValidSubjectOfNSAttribute(VD->getType()), @@ -1760,7 +1760,7 @@ void SemaObjC::AddXConsumedAttr(Decl *D, const AttributeCommonInfo &CI, : diag::warn_ns_attribute_wrong_parameter_type), /*ExtraArgs=*/CI.getRange(), "ns_consumed", /*objc pointers*/ 0); return; - case Sema::RetainOwnershipKind::CF: + case RetainOwnershipKind::CF: handleSimpleAttributeOrDiagnose( *this, VD, CI, isValidSubjectOfCFAttribute(VD->getType()), diag::warn_ns_attribute_wrong_parameter_type, @@ -1769,26 +1769,26 @@ void SemaObjC::AddXConsumedAttr(Decl *D, const AttributeCommonInfo &CI, } } -Sema::RetainOwnershipKind +SemaObjC::RetainOwnershipKind SemaObjC::parsedAttrToRetainOwnershipKind(const ParsedAttr &AL) { switch (AL.getKind()) { case ParsedAttr::AT_CFConsumed: case ParsedAttr::AT_CFReturnsRetained: case ParsedAttr::AT_CFReturnsNotRetained: - return Sema::RetainOwnershipKind::CF; + return RetainOwnershipKind::CF; case ParsedAttr::AT_OSConsumesThis: case ParsedAttr::AT_OSConsumed: case ParsedAttr::AT_OSReturnsRetained: case ParsedAttr::AT_OSReturnsNotRetained: case ParsedAttr::AT_OSReturnsRetainedOnZero: case ParsedAttr::AT_OSReturnsRetainedOnNonZero: - return Sema::RetainOwnershipKind::OS; + return RetainOwnershipKind::OS; case ParsedAttr::AT_NSConsumesSelf: case ParsedAttr::AT_NSConsumed: case ParsedAttr::AT_NSReturnsRetained: case ParsedAttr::AT_NSReturnsNotRetained: case ParsedAttr::AT_NSReturnsAutoreleased: - return Sema::RetainOwnershipKind::NS; + return RetainOwnershipKind::NS; default: llvm_unreachable("Wrong argument supplied"); } @@ -1816,7 +1816,7 @@ bool SemaObjC::isValidOSObjectOutParameter(const Decl *D) { void SemaObjC::handleXReturnsXRetainedAttr(Decl *D, const ParsedAttr &AL) { QualType ReturnType; - Sema::RetainOwnershipKind K = parsedAttrToRetainOwnershipKind(AL); + RetainOwnershipKind K = parsedAttrToRetainOwnershipKind(AL); if (const auto *MD = dyn_cast(D)) { ReturnType = MD->getReturnType(); @@ -1830,7 +1830,7 @@ void SemaObjC::handleXReturnsXRetainedAttr(Decl *D, const ParsedAttr &AL) { } else if (const auto *Param = dyn_cast(D)) { // Attributes on parameters are used for out-parameters, // passed as pointers-to-pointers. - unsigned DiagID = K == Sema::RetainOwnershipKind::CF + unsigned DiagID = K == RetainOwnershipKind::CF ? /*pointer-to-CF-pointer*/ 2 : /*pointer-to-OSObject-pointer*/ 3; ReturnType = Param->getType()->getPointeeType(); @@ -2405,4 +2405,168 @@ void SemaObjC::checkDictionaryLiteral( } } +sema::BlockScopeInfo *SemaObjC::getCurBlock() { + if (SemaRef.FunctionScopes.empty()) + return nullptr; + + auto CurBSI = dyn_cast(SemaRef.FunctionScopes.back()); + if (CurBSI && CurBSI->TheDecl && + !CurBSI->TheDecl->Encloses(SemaRef.CurContext)) { + // We have switched contexts due to template instantiation. + assert(!SemaRef.CodeSynthesisContexts.empty()); + return nullptr; + } + + return CurBSI; +} + +static bool checkUnsafeAssignLiteral(Sema &S, SourceLocation Loc, Expr *RHS, + bool isProperty) { + // Check if RHS is an Objective-C object literal, which also can get + // immediately zapped in a weak reference. Note that we explicitly + // allow ObjCStringLiterals, since those are designed to never really die. + RHS = RHS->IgnoreParenImpCasts(); + + // This enum needs to match with the 'select' in + // warn_objc_arc_literal_assign (off-by-1). + SemaObjC::ObjCLiteralKind Kind = S.ObjC().CheckLiteralKind(RHS); + if (Kind == SemaObjC::LK_String || Kind == SemaObjC::LK_None) + return false; + + S.Diag(Loc, diag::warn_arc_literal_assign) + << (unsigned)Kind << (isProperty ? 0 : 1) << RHS->getSourceRange(); + + return true; +} + +static bool checkUnsafeAssignObject(Sema &S, SourceLocation Loc, + Qualifiers::ObjCLifetime LT, Expr *RHS, + bool isProperty) { + // Strip off any implicit cast added to get to the one ARC-specific. + while (ImplicitCastExpr *cast = dyn_cast(RHS)) { + if (cast->getCastKind() == CK_ARCConsumeObject) { + S.Diag(Loc, diag::warn_arc_retained_assign) + << (LT == Qualifiers::OCL_ExplicitNone) << (isProperty ? 0 : 1) + << RHS->getSourceRange(); + return true; + } + RHS = cast->getSubExpr(); + } + + if (LT == Qualifiers::OCL_Weak && + checkUnsafeAssignLiteral(S, Loc, RHS, isProperty)) + return true; + + return false; +} + +bool SemaObjC::checkUnsafeAssigns(SourceLocation Loc, QualType LHS, Expr *RHS) { + Qualifiers::ObjCLifetime LT = LHS.getObjCLifetime(); + + if (LT != Qualifiers::OCL_Weak && LT != Qualifiers::OCL_ExplicitNone) + return false; + + if (checkUnsafeAssignObject(SemaRef, Loc, LT, RHS, false)) + return true; + + return false; +} + +void SemaObjC::checkUnsafeExprAssigns(SourceLocation Loc, Expr *LHS, + Expr *RHS) { + QualType LHSType; + // PropertyRef on LHS type need be directly obtained from + // its declaration as it has a PseudoType. + ObjCPropertyRefExpr *PRE = dyn_cast(LHS->IgnoreParens()); + if (PRE && !PRE->isImplicitProperty()) { + const ObjCPropertyDecl *PD = PRE->getExplicitProperty(); + if (PD) + LHSType = PD->getType(); + } + + if (LHSType.isNull()) + LHSType = LHS->getType(); + + Qualifiers::ObjCLifetime LT = LHSType.getObjCLifetime(); + + if (LT == Qualifiers::OCL_Weak) { + if (!getDiagnostics().isIgnored(diag::warn_arc_repeated_use_of_weak, Loc)) + SemaRef.getCurFunction()->markSafeWeakUse(LHS); + } + + if (checkUnsafeAssigns(Loc, LHSType, RHS)) + return; + + // FIXME. Check for other life times. + if (LT != Qualifiers::OCL_None) + return; + + if (PRE) { + if (PRE->isImplicitProperty()) + return; + const ObjCPropertyDecl *PD = PRE->getExplicitProperty(); + if (!PD) + return; + + unsigned Attributes = PD->getPropertyAttributes(); + if (Attributes & ObjCPropertyAttribute::kind_assign) { + // when 'assign' attribute was not explicitly specified + // by user, ignore it and rely on property type itself + // for lifetime info. + unsigned AsWrittenAttr = PD->getPropertyAttributesAsWritten(); + if (!(AsWrittenAttr & ObjCPropertyAttribute::kind_assign) && + LHSType->isObjCRetainableType()) + return; + + while (ImplicitCastExpr *cast = dyn_cast(RHS)) { + if (cast->getCastKind() == CK_ARCConsumeObject) { + Diag(Loc, diag::warn_arc_retained_property_assign) + << RHS->getSourceRange(); + return; + } + RHS = cast->getSubExpr(); + } + } else if (Attributes & ObjCPropertyAttribute::kind_weak) { + if (checkUnsafeAssignObject(SemaRef, Loc, Qualifiers::OCL_Weak, RHS, + true)) + return; + } + } +} + +void SemaObjC::diagnoseImplicitlyRetainedSelf() { + llvm::DenseMap EscapeInfo; + + auto IsOrNestedInEscapingBlock = [&](const BlockDecl *BD) { + if (EscapeInfo.count(BD)) + return EscapeInfo[BD]; + + bool R = false; + const BlockDecl *CurBD = BD; + + do { + R = !CurBD->doesNotEscape(); + if (R) + break; + CurBD = CurBD->getParent()->getInnermostBlockDecl(); + } while (CurBD); + + return EscapeInfo[BD] = R; + }; + + // If the location where 'self' is implicitly retained is inside a escaping + // block, emit a diagnostic. + for (const std::pair &P : + ImplicitlyRetainedSelfLocs) + if (IsOrNestedInEscapingBlock(P.second)) + Diag(P.first, diag::warn_implicitly_retains_self) + << FixItHint::CreateInsertion(P.first, "self->"); +} + +void SemaObjC::PushBlockScope(Scope *BlockScope, BlockDecl *Block) { + SemaRef.FunctionScopes.push_back( + new sema::BlockScopeInfo(getDiagnostics(), BlockScope, Block)); + SemaRef.CapturingFunctionScopes++; +} + } // namespace clang diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 3e6c6c94a47cd..0b50f5a10b582 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -2372,7 +2372,7 @@ VarDecl *SemaOpenMP::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo, // 'target' we return true so that this global is also mapped to the device. // if (VD && !VD->hasLocalStorage() && - (SemaRef.getCurCapturedRegion() || SemaRef.getCurBlock() || + (SemaRef.getCurCapturedRegion() || SemaRef.ObjC().getCurBlock() || SemaRef.getCurLambda())) { if (isInOpenMPTargetExecutionDirective()) { DSAStackTy::DSAVarData DVarTop = @@ -22986,7 +22986,7 @@ static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR, OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD); if (SemaRef.LangOpts.OpenMP >= 50 && (SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true) || - SemaRef.getCurBlock() || SemaRef.getCurCapturedRegion()) && + SemaRef.ObjC().getCurBlock() || SemaRef.getCurCapturedRegion()) && VD->hasGlobalStorage()) { if (!MapTy || (*MapTy != OMPDeclareTargetDeclAttr::MT_To && *MapTy != OMPDeclareTargetDeclAttr::MT_Enter)) { diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp index fdb584ceb8105..fe39ec6bfa631 100644 --- a/clang/lib/Sema/SemaPseudoObject.cpp +++ b/clang/lib/Sema/SemaPseudoObject.cpp @@ -928,7 +928,7 @@ ObjCPropertyOpBuilder::buildAssignmentOperation(Scope *Sc, // Various warnings about property assignments in ARC. if (S.getLangOpts().ObjCAutoRefCount && InstanceReceiver) { S.ObjC().checkRetainCycles(InstanceReceiver->getSourceExpr(), RHS); - S.checkUnsafeExprAssigns(opcLoc, LHS, RHS); + S.ObjC().checkUnsafeExprAssigns(opcLoc, LHS, RHS); } return result; @@ -1017,7 +1017,7 @@ ObjCSubscriptOpBuilder::buildAssignmentOperation(Scope *Sc, // Various warnings about objc Index'ed assignments in ARC. if (S.getLangOpts().ObjCAutoRefCount && InstanceBase) { S.ObjC().checkRetainCycles(InstanceBase->getSourceExpr(), RHS); - S.checkUnsafeExprAssigns(opcLoc, LHS, RHS); + S.ObjC().checkUnsafeExprAssigns(opcLoc, LHS, RHS); } return result; diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 0681520764d9a..2b6622562c222 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -725,15 +725,14 @@ void Sema::InstantiateAttrsForDecl( } } -static Sema::RetainOwnershipKind -attrToRetainOwnershipKind(const Attr *A) { +static SemaObjC::RetainOwnershipKind attrToRetainOwnershipKind(const Attr *A) { switch (A->getKind()) { case clang::attr::CFConsumed: - return Sema::RetainOwnershipKind::CF; + return SemaObjC::RetainOwnershipKind::CF; case clang::attr::OSConsumed: - return Sema::RetainOwnershipKind::OS; + return SemaObjC::RetainOwnershipKind::OS; case clang::attr::NSConsumed: - return Sema::RetainOwnershipKind::NS; + return SemaObjC::RetainOwnershipKind::NS; default: llvm_unreachable("Wrong argument supplied"); } @@ -1238,7 +1237,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D, if (auto *F = dyn_cast(DC)) RT = F->getReturnType(); else if (isa(DC)) - RT = cast(SemaRef.getCurBlock()->FunctionType) + RT = cast(SemaRef.ObjC().getCurBlock()->FunctionType) ->getReturnType(); else llvm_unreachable("Unknown context type"); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 51ba22f99e3a3..7de40c416b87c 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -15817,8 +15817,8 @@ ExprResult TreeTransform::TransformBlockExpr(BlockExpr *E) { BlockDecl *oldBlock = E->getBlockDecl(); - SemaRef.ActOnBlockStart(E->getCaretLocation(), /*Scope=*/nullptr); - BlockScopeInfo *blockScope = SemaRef.getCurBlock(); + SemaRef.ObjC().ActOnBlockStart(E->getCaretLocation(), /*Scope=*/nullptr); + BlockScopeInfo *blockScope = SemaRef.ObjC().getCurBlock(); blockScope->TheDecl->setIsVariadic(oldBlock->isVariadic()); blockScope->TheDecl->setBlockMissingReturnType( @@ -15835,7 +15835,7 @@ TreeTransform::TransformBlockExpr(BlockExpr *E) { E->getCaretLocation(), oldBlock->parameters(), nullptr, exprFunctionType->getExtParameterInfosOrNull(), paramTypes, ¶ms, extParamInfos)) { - getSema().ActOnBlockError(E->getCaretLocation(), /*Scope=*/nullptr); + getSema().ObjC().ActOnBlockError(E->getCaretLocation(), /*Scope=*/nullptr); return ExprError(); } @@ -15861,7 +15861,7 @@ TreeTransform::TransformBlockExpr(BlockExpr *E) { // Transform the body StmtResult body = getDerived().TransformStmt(E->getBody()); if (body.isInvalid()) { - getSema().ActOnBlockError(E->getCaretLocation(), /*Scope=*/nullptr); + getSema().ObjC().ActOnBlockError(E->getCaretLocation(), /*Scope=*/nullptr); return ExprError(); } @@ -15890,8 +15890,8 @@ TreeTransform::TransformBlockExpr(BlockExpr *E) { } #endif - return SemaRef.ActOnBlockStmtExpr(E->getCaretLocation(), body.get(), - /*Scope=*/nullptr); + return SemaRef.ObjC().ActOnBlockStmtExpr(E->getCaretLocation(), body.get(), + /*Scope=*/nullptr); } template