diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-05-29 16:25:46 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-05-29 16:25:46 +0000 |
commit | b5aee35cc5d62f11d98539f62e4fe63f0ac9edc6 (patch) | |
tree | 3e6ab962dbc73cfe1445a60d2eb4dfba7c939a22 /lib/Sema | |
parent | aa803409c3bd3930126db630c29f63d42f255153 (diff) | |
download | src-b5aee35cc5d62f11d98539f62e4fe63f0ac9edc6.tar.gz src-b5aee35cc5d62f11d98539f62e4fe63f0ac9edc6.zip |
Vendor import of clang trunk r304149:vendor/clang/clang-trunk-r304149
Notes
Notes:
svn path=/vendor/clang/dist/; revision=319142
svn path=/vendor/clang/clang-trunk-r304149/; revision=319143; tag=vendor/clang/clang-trunk-r304149
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/AnalysisBasedWarnings.cpp | 24 | ||||
-rw-r--r-- | lib/Sema/CoroutineStmtBuilder.h | 2 | ||||
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 71 | ||||
-rw-r--r-- | lib/Sema/SemaCoroutine.cpp | 277 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 19 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 17 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 255 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 19 | ||||
-rw-r--r-- | lib/Sema/SemaLambda.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 10 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 13 |
13 files changed, 511 insertions, 212 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index 50ad113fc880..db688b12cbcf 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -542,6 +542,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, bool ReturnsVoid = false; bool HasNoReturn = false; + bool IsCoroutine = S.getCurFunction() && S.getCurFunction()->isCoroutine(); if (const auto *FD = dyn_cast<FunctionDecl>(D)) { if (const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body)) @@ -570,8 +571,13 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, // Short circuit for compilation speed. if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn)) return; - SourceLocation LBrace = Body->getLocStart(), RBrace = Body->getLocEnd(); + auto EmitDiag = [&](SourceLocation Loc, unsigned DiagID) { + if (IsCoroutine) + S.Diag(Loc, DiagID) << S.getCurFunction()->CoroutinePromise->getType(); + else + S.Diag(Loc, DiagID); + }; // Either in a function body compound statement, or a function-try-block. switch (CheckFallThrough(AC)) { case UnknownFallThrough: @@ -579,15 +585,15 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, case MaybeFallThrough: if (HasNoReturn) - S.Diag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn); + EmitDiag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn); else if (!ReturnsVoid) - S.Diag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid); + EmitDiag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid); break; case AlwaysFallThrough: if (HasNoReturn) - S.Diag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn); + EmitDiag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn); else if (!ReturnsVoid) - S.Diag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid); + EmitDiag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid); break; case NeverFallThroughOrReturn: if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) { @@ -2027,12 +2033,6 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // Warning: check missing 'return' if (P.enableCheckFallThrough) { - auto IsCoro = [&]() { - if (auto *FD = dyn_cast<FunctionDecl>(D)) - if (FD->getBody() && isa<CoroutineBodyStmt>(FD->getBody())) - return true; - return false; - }; const CheckFallThroughDiagnostics &CD = (isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock() @@ -2040,7 +2040,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, cast<CXXMethodDecl>(D)->getOverloadedOperator() == OO_Call && cast<CXXMethodDecl>(D)->getParent()->isLambda()) ? CheckFallThroughDiagnostics::MakeForLambda() - : (IsCoro() + : (fscope->isCoroutine() ? CheckFallThroughDiagnostics::MakeForCoroutine(D) : CheckFallThroughDiagnostics::MakeForFunction(D))); CheckFallThroughForBody(S, D, Body, blkExpr, CD, AC); diff --git a/lib/Sema/CoroutineStmtBuilder.h b/lib/Sema/CoroutineStmtBuilder.h index 4958576219e5..954a0f100ebb 100644 --- a/lib/Sema/CoroutineStmtBuilder.h +++ b/lib/Sema/CoroutineStmtBuilder.h @@ -28,7 +28,6 @@ class CoroutineStmtBuilder : public CoroutineBodyStmt::CtorArgs { sema::FunctionScopeInfo &Fn; bool IsValid = true; SourceLocation Loc; - QualType RetType; SmallVector<Stmt *, 4> ParamMovesVector; const bool IsPromiseDependentType; CXXRecordDecl *PromiseRecordDecl = nullptr; @@ -61,6 +60,7 @@ private: bool makeOnFallthrough(); bool makeOnException(); bool makeReturnObject(); + bool makeGroDeclAndReturnStmt(); bool makeReturnOnAllocFailure(); bool makeParamMoves(); }; diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 14dd6267b854..b794628db738 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -1696,6 +1696,9 @@ bool Sema::CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case PPC::BI__builtin_tabortdci: return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31) || SemaBuiltinConstantArgRange(TheCall, 2, 0, 31); + case PPC::BI__builtin_vsx_xxpermdi: + case PPC::BI__builtin_vsx_xxsldwi: + return SemaBuiltinVSX(TheCall); } return SemaBuiltinConstantArgRange(TheCall, i, l, u); } @@ -3892,6 +3895,65 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { return false; } +// Customized Sema Checking for VSX builtins that have the following signature: +// vector [...] builtinName(vector [...], vector [...], const int); +// Which takes the same type of vectors (any legal vector type) for the first +// two arguments and takes compile time constant for the third argument. +// Example builtins are : +// vector double vec_xxpermdi(vector double, vector double, int); +// vector short vec_xxsldwi(vector short, vector short, int); +bool Sema::SemaBuiltinVSX(CallExpr *TheCall) { + unsigned ExpectedNumArgs = 3; + if (TheCall->getNumArgs() < ExpectedNumArgs) + return Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_few_args_at_least) + << 0 /*function call*/ << ExpectedNumArgs << TheCall->getNumArgs() + << TheCall->getSourceRange(); + + if (TheCall->getNumArgs() > ExpectedNumArgs) + return Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_many_args_at_most) + << 0 /*function call*/ << ExpectedNumArgs << TheCall->getNumArgs() + << TheCall->getSourceRange(); + + // Check the third argument is a compile time constant + llvm::APSInt Value; + if(!TheCall->getArg(2)->isIntegerConstantExpr(Value, Context)) + return Diag(TheCall->getLocStart(), + diag::err_vsx_builtin_nonconstant_argument) + << 3 /* argument index */ << TheCall->getDirectCallee() + << SourceRange(TheCall->getArg(2)->getLocStart(), + TheCall->getArg(2)->getLocEnd()); + + QualType Arg1Ty = TheCall->getArg(0)->getType(); + QualType Arg2Ty = TheCall->getArg(1)->getType(); + + // Check the type of argument 1 and argument 2 are vectors. + SourceLocation BuiltinLoc = TheCall->getLocStart(); + if ((!Arg1Ty->isVectorType() && !Arg1Ty->isDependentType()) || + (!Arg2Ty->isVectorType() && !Arg2Ty->isDependentType())) { + return Diag(BuiltinLoc, diag::err_vec_builtin_non_vector) + << TheCall->getDirectCallee() + << SourceRange(TheCall->getArg(0)->getLocStart(), + TheCall->getArg(1)->getLocEnd()); + } + + // Check the first two arguments are the same type. + if (!Context.hasSameUnqualifiedType(Arg1Ty, Arg2Ty)) { + return Diag(BuiltinLoc, diag::err_vec_builtin_incompatible_vector) + << TheCall->getDirectCallee() + << SourceRange(TheCall->getArg(0)->getLocStart(), + TheCall->getArg(1)->getLocEnd()); + } + + // When default clang type checking is turned off and the customized type + // checking is used, the returning type of the function must be explicitly + // set. Otherwise it is _Bool by default. + TheCall->setType(Arg1Ty); + + return false; +} + /// SemaBuiltinShuffleVector - Handle __builtin_shufflevector. // This is declared to take (...), so we have to check everything. ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { @@ -3914,7 +3976,8 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { if (!LHSType->isVectorType() || !RHSType->isVectorType()) return ExprError(Diag(TheCall->getLocStart(), - diag::err_shufflevector_non_vector) + diag::err_vec_builtin_non_vector) + << TheCall->getDirectCallee() << SourceRange(TheCall->getArg(0)->getLocStart(), TheCall->getArg(1)->getLocEnd())); @@ -3928,12 +3991,14 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { if (!RHSType->hasIntegerRepresentation() || RHSType->getAs<VectorType>()->getNumElements() != numElements) return ExprError(Diag(TheCall->getLocStart(), - diag::err_shufflevector_incompatible_vector) + diag::err_vec_builtin_incompatible_vector) + << TheCall->getDirectCallee() << SourceRange(TheCall->getArg(1)->getLocStart(), TheCall->getArg(1)->getLocEnd())); } else if (!Context.hasSameUnqualifiedType(LHSType, RHSType)) { return ExprError(Diag(TheCall->getLocStart(), - diag::err_shufflevector_incompatible_vector) + diag::err_vec_builtin_incompatible_vector) + << TheCall->getDirectCallee() << SourceRange(TheCall->getArg(0)->getLocStart(), TheCall->getArg(1)->getLocEnd())); } else if (numElements != numResElements) { diff --git a/lib/Sema/SemaCoroutine.cpp b/lib/Sema/SemaCoroutine.cpp index c709a1a723d0..ae6c35f22065 100644 --- a/lib/Sema/SemaCoroutine.cpp +++ b/lib/Sema/SemaCoroutine.cpp @@ -23,14 +23,22 @@ using namespace clang; using namespace sema; -static bool lookupMember(Sema &S, const char *Name, CXXRecordDecl *RD, - SourceLocation Loc) { +static LookupResult lookupMember(Sema &S, const char *Name, CXXRecordDecl *RD, + SourceLocation Loc, bool &Res) { DeclarationName DN = S.PP.getIdentifierInfo(Name); LookupResult LR(S, DN, Loc, Sema::LookupMemberName); // Suppress diagnostics when a private member is selected. The same warnings // will be produced again when building the call. LR.suppressDiagnostics(); - return S.LookupQualifiedName(LR, RD); + Res = S.LookupQualifiedName(LR, RD); + return LR; +} + +static bool lookupMember(Sema &S, const char *Name, CXXRecordDecl *RD, + SourceLocation Loc) { + bool Res; + lookupMember(S, Name, RD, Loc, Res); + return Res; } /// Look up the std::coroutine_traits<...>::promise_type for the given @@ -120,8 +128,7 @@ static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType, return PromiseType; } -/// Look up the std::coroutine_traits<...>::promise_type for the given -/// function type. +/// Look up the std::experimental::coroutine_handle<PromiseType>. static QualType lookupCoroutineHandleType(Sema &S, QualType PromiseType, SourceLocation Loc) { if (PromiseType.isNull()) @@ -314,6 +321,7 @@ static ExprResult buildCoroutineHandle(Sema &S, QualType PromiseType, } struct ReadySuspendResumeResult { + enum AwaitCallType { ACT_Ready, ACT_Suspend, ACT_Resume }; Expr *Results[3]; OpaqueValueExpr *OpaqueValue; bool IsInvalid; @@ -359,7 +367,41 @@ static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise, Calls.Results[I] = Result.get(); } + // Assume the calls are valid; all further checking should make them invalid. Calls.IsInvalid = false; + + using ACT = ReadySuspendResumeResult::AwaitCallType; + CallExpr *AwaitReady = cast<CallExpr>(Calls.Results[ACT::ACT_Ready]); + if (!AwaitReady->getType()->isDependentType()) { + // [expr.await]p3 [...] + // — await-ready is the expression e.await_ready(), contextually converted + // to bool. + ExprResult Conv = S.PerformContextuallyConvertToBool(AwaitReady); + if (Conv.isInvalid()) { + S.Diag(AwaitReady->getDirectCallee()->getLocStart(), + diag::note_await_ready_no_bool_conversion); + S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required) + << AwaitReady->getDirectCallee() << E->getSourceRange(); + Calls.IsInvalid = true; + } + Calls.Results[ACT::ACT_Ready] = Conv.get(); + } + CallExpr *AwaitSuspend = cast<CallExpr>(Calls.Results[ACT::ACT_Suspend]); + if (!AwaitSuspend->getType()->isDependentType()) { + // [expr.await]p3 [...] + // - await-suspend is the expression e.await_suspend(h), which shall be + // a prvalue of type void or bool. + QualType RetType = AwaitSuspend->getType(); + if (RetType != S.Context.BoolTy && RetType != S.Context.VoidTy) { + S.Diag(AwaitSuspend->getCalleeDecl()->getLocation(), + diag::err_await_suspend_invalid_return_type) + << RetType; + S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required) + << AwaitSuspend->getDirectCallee(); + Calls.IsInvalid = true; + } + } + return Calls; } @@ -373,7 +415,6 @@ static ExprResult buildPromiseCall(Sema &S, VarDecl *Promise, if (PromiseRef.isInvalid()) return ExprError(); - // Call 'yield_value', passing in E. return buildMemberCall(S, PromiseRef.get(), Loc, Name, Args); } @@ -721,17 +762,19 @@ static FunctionDecl *findDeleteForPromise(Sema &S, SourceLocation Loc, void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) { FunctionScopeInfo *Fn = getCurFunction(); - assert(Fn && Fn->CoroutinePromise && "not a coroutine"); - + assert(Fn && Fn->isCoroutine() && "not a coroutine"); if (!Body) { assert(FD->isInvalidDecl() && "a null body is only allowed for invalid declarations"); return; } + // We have a function that uses coroutine keywords, but we failed to build + // the promise type. + if (!Fn->CoroutinePromise) + return FD->setInvalidDecl(); if (isa<CoroutineBodyStmt>(Body)) { - // FIXME(EricWF): Nothing todo. the body is already a transformed coroutine - // body statement. + // Nothing todo. the body is already a transformed coroutine body statement. return; } @@ -780,7 +823,8 @@ bool CoroutineStmtBuilder::buildDependentStatements() { assert(!this->IsPromiseDependentType && "coroutine cannot have a dependent promise type"); this->IsValid = makeOnException() && makeOnFallthrough() && - makeReturnOnAllocFailure() && makeNewAndDeleteExpr(); + makeGroDeclAndReturnStmt() && makeReturnOnAllocFailure() && + makeNewAndDeleteExpr(); return this->IsValid; } @@ -857,15 +901,15 @@ bool CoroutineStmtBuilder::makeReturnOnAllocFailure() { if (ReturnObjectOnAllocationFailure.isInvalid()) return false; - // FIXME: ActOnReturnStmt expects a scope that is inside of the function, due - // to CheckJumpOutOfSEHFinally(*this, ReturnLoc, *CurScope->getFnParent()); - // S.getCurScope()->getFnParent() == nullptr at ActOnFinishFunctionBody when - // CoroutineBodyStmt is built. Figure it out and fix it. - // Use BuildReturnStmt here to unbreak sanitized tests. (Gor:3/27/2017) StmtResult ReturnStmt = S.BuildReturnStmt(Loc, ReturnObjectOnAllocationFailure.get()); - if (ReturnStmt.isInvalid()) + if (ReturnStmt.isInvalid()) { + S.Diag(Found.getFoundDecl()->getLocation(), diag::note_member_declared_here) + << DN; + S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here) + << Fn.getFirstCoroutineStmtKeyword(); return false; + } this->ReturnStmtOnAllocFailure = ReturnStmt.get(); return true; @@ -991,13 +1035,32 @@ bool CoroutineStmtBuilder::makeOnFallthrough() { // [dcl.fct.def.coroutine]/4 // The unqualified-ids 'return_void' and 'return_value' are looked up in // the scope of class P. If both are found, the program is ill-formed. - const bool HasRVoid = lookupMember(S, "return_void", PromiseRecordDecl, Loc); - const bool HasRValue = lookupMember(S, "return_value", PromiseRecordDecl, Loc); + bool HasRVoid, HasRValue; + LookupResult LRVoid = + lookupMember(S, "return_void", PromiseRecordDecl, Loc, HasRVoid); + LookupResult LRValue = + lookupMember(S, "return_value", PromiseRecordDecl, Loc, HasRValue); StmtResult Fallthrough; if (HasRVoid && HasRValue) { // FIXME Improve this diagnostic - S.Diag(FD.getLocation(), diag::err_coroutine_promise_return_ill_formed) + S.Diag(FD.getLocation(), + diag::err_coroutine_promise_incompatible_return_functions) + << PromiseRecordDecl; + S.Diag(LRVoid.getRepresentativeDecl()->getLocation(), + diag::note_member_first_declared_here) + << LRVoid.getLookupName(); + S.Diag(LRValue.getRepresentativeDecl()->getLocation(), + diag::note_member_first_declared_here) + << LRValue.getLookupName(); + return false; + } else if (!HasRVoid && !HasRValue) { + // FIXME: The PDTS currently specifies this case as UB, not ill-formed. + // However we still diagnose this as an error since until the PDTS is fixed. + S.Diag(FD.getLocation(), + diag::err_coroutine_promise_requires_return_function) + << PromiseRecordDecl; + S.Diag(PromiseRecordDecl->getLocation(), diag::note_defined_here) << PromiseRecordDecl; return false; } else if (HasRVoid) { @@ -1029,6 +1092,8 @@ bool CoroutineStmtBuilder::makeOnException() { : diag:: warn_coroutine_promise_unhandled_exception_required_with_exceptions; S.Diag(Loc, DiagID) << PromiseRecordDecl; + S.Diag(PromiseRecordDecl->getLocation(), diag::note_defined_here) + << PromiseRecordDecl; return !RequireUnhandledException; } @@ -1042,37 +1107,185 @@ bool CoroutineStmtBuilder::makeOnException() { if (UnhandledException.isInvalid()) return false; + // Since the body of the coroutine will be wrapped in try-catch, it will + // be incompatible with SEH __try if present in a function. + if (!S.getLangOpts().Borland && Fn.FirstSEHTryLoc.isValid()) { + S.Diag(Fn.FirstSEHTryLoc, diag::err_seh_in_a_coroutine_with_cxx_exceptions); + S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here) + << Fn.getFirstCoroutineStmtKeyword(); + return false; + } + this->OnException = UnhandledException.get(); return true; } bool CoroutineStmtBuilder::makeReturnObject() { - // Build implicit 'p.get_return_object()' expression and form initialization // of return type from it. ExprResult ReturnObject = buildPromiseCall(S, Fn.CoroutinePromise, Loc, "get_return_object", None); if (ReturnObject.isInvalid()) return false; - QualType RetType = FD.getReturnType(); - if (!RetType->isDependentType()) { - InitializedEntity Entity = - InitializedEntity::InitializeResult(Loc, RetType, false); - ReturnObject = S.PerformMoveOrCopyInitialization(Entity, nullptr, RetType, - ReturnObject.get()); - if (ReturnObject.isInvalid()) + + this->ReturnValue = ReturnObject.get(); + return true; +} + +static void noteMemberDeclaredHere(Sema &S, Expr *E, FunctionScopeInfo &Fn) { + if (auto *MbrRef = dyn_cast<CXXMemberCallExpr>(E)) { + auto *MethodDecl = MbrRef->getMethodDecl(); + S.Diag(MethodDecl->getLocation(), diag::note_member_declared_here) + << MethodDecl; + } + S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here) + << Fn.getFirstCoroutineStmtKeyword(); +} + +bool CoroutineStmtBuilder::makeGroDeclAndReturnStmt() { + assert(!IsPromiseDependentType && + "cannot make statement while the promise type is dependent"); + assert(this->ReturnValue && "ReturnValue must be already formed"); + + QualType const GroType = this->ReturnValue->getType(); + assert(!GroType->isDependentType() && + "get_return_object type must no longer be dependent"); + + QualType const FnRetType = FD.getReturnType(); + assert(!FnRetType->isDependentType() && + "get_return_object type must no longer be dependent"); + + if (FnRetType->isVoidType()) { + ExprResult Res = S.ActOnFinishFullExpr(this->ReturnValue, Loc); + if (Res.isInvalid()) return false; + + this->ResultDecl = Res.get(); + return true; } - ReturnObject = S.ActOnFinishFullExpr(ReturnObject.get(), Loc); - if (ReturnObject.isInvalid()) + + if (GroType->isVoidType()) { + // Trigger a nice error message. + InitializedEntity Entity = + InitializedEntity::InitializeResult(Loc, FnRetType, false); + S.PerformMoveOrCopyInitialization(Entity, nullptr, FnRetType, ReturnValue); + noteMemberDeclaredHere(S, ReturnValue, Fn); return false; + } - this->ReturnValue = ReturnObject.get(); + auto *GroDecl = VarDecl::Create( + S.Context, &FD, FD.getLocation(), FD.getLocation(), + &S.PP.getIdentifierTable().get("__coro_gro"), GroType, + S.Context.getTrivialTypeSourceInfo(GroType, Loc), SC_None); + + S.CheckVariableDeclarationType(GroDecl); + if (GroDecl->isInvalidDecl()) + return false; + + InitializedEntity Entity = InitializedEntity::InitializeVariable(GroDecl); + ExprResult Res = S.PerformMoveOrCopyInitialization(Entity, nullptr, GroType, + this->ReturnValue); + if (Res.isInvalid()) + return false; + + Res = S.ActOnFinishFullExpr(Res.get()); + if (Res.isInvalid()) + return false; + + if (GroType == FnRetType) { + GroDecl->setNRVOVariable(true); + } + + S.AddInitializerToDecl(GroDecl, Res.get(), + /*DirectInit=*/false); + + S.FinalizeDeclaration(GroDecl); + + // Form a declaration statement for the return declaration, so that AST + // visitors can more easily find it. + StmtResult GroDeclStmt = + S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(GroDecl), Loc, Loc); + if (GroDeclStmt.isInvalid()) + return false; + + this->ResultDecl = GroDeclStmt.get(); + + ExprResult declRef = S.BuildDeclRefExpr(GroDecl, GroType, VK_LValue, Loc); + if (declRef.isInvalid()) + return false; + + StmtResult ReturnStmt = S.BuildReturnStmt(Loc, declRef.get()); + if (ReturnStmt.isInvalid()) { + noteMemberDeclaredHere(S, ReturnValue, Fn); + return false; + } + + this->ReturnStmt = ReturnStmt.get(); return true; } +// Create a static_cast\<T&&>(expr). +static Expr *castForMoving(Sema &S, Expr *E, QualType T = QualType()) { + if (T.isNull()) + T = E->getType(); + QualType TargetType = S.BuildReferenceType( + T, /*SpelledAsLValue*/ false, SourceLocation(), DeclarationName()); + SourceLocation ExprLoc = E->getLocStart(); + TypeSourceInfo *TargetLoc = + S.Context.getTrivialTypeSourceInfo(TargetType, ExprLoc); + + return S + .BuildCXXNamedCast(ExprLoc, tok::kw_static_cast, TargetLoc, E, + SourceRange(ExprLoc, ExprLoc), E->getSourceRange()) + .get(); +} + +/// \brief Build a variable declaration for move parameter. +static VarDecl *buildVarDecl(Sema &S, SourceLocation Loc, QualType Type, + StringRef Name) { + DeclContext *DC = S.CurContext; + IdentifierInfo *II = &S.PP.getIdentifierTable().get(Name); + TypeSourceInfo *TInfo = S.Context.getTrivialTypeSourceInfo(Type, Loc); + VarDecl *Decl = + VarDecl::Create(S.Context, DC, Loc, Loc, II, Type, TInfo, SC_None); + Decl->setImplicit(); + return Decl; +} + bool CoroutineStmtBuilder::makeParamMoves() { - // FIXME: Perform move-initialization of parameters into frame-local copies. + for (auto *paramDecl : FD.parameters()) { + auto Ty = paramDecl->getType(); + if (Ty->isDependentType()) + continue; + + // No need to copy scalars, llvm will take care of them. + if (Ty->getAsCXXRecordDecl()) { + if (!paramDecl->getIdentifier()) + continue; + + ExprResult ParamRef = + S.BuildDeclRefExpr(paramDecl, paramDecl->getType(), + ExprValueKind::VK_LValue, Loc); // FIXME: scope? + if (ParamRef.isInvalid()) + return false; + + Expr *RCast = castForMoving(S, ParamRef.get()); + + auto D = buildVarDecl(S, Loc, Ty, paramDecl->getIdentifier()->getName()); + + S.AddInitializerToDecl(D, RCast, /*DirectInit=*/true); + + // Convert decl to a statement. + StmtResult Stmt = S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(D), Loc, Loc); + if (Stmt.isInvalid()) + return false; + + ParamMovesVector.push_back(Stmt.get()); + } + } + + // Convert to ArrayRef in CtorArgs structure that builder inherits from. + ParamMoves = ParamMovesVector; return true; } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 5e937aa69963..96fd952c81c7 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -6516,7 +6516,7 @@ NamedDecl *Sema::ActOnVariableDeclarator( diag::err_thread_non_global) << DeclSpec::getSpecifierName(TSCS); else if (!Context.getTargetInfo().isTLSSupported()) { - if (getLangOpts().CUDA) { + if (getLangOpts().CUDA || getLangOpts().OpenMPIsDevice) { // Postpone error emission until we've collected attributes required to // figure out whether it's a host or device variable and whether the // error should be ignored. @@ -6578,8 +6578,11 @@ NamedDecl *Sema::ActOnVariableDeclarator( // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewVD, D); - if (getLangOpts().CUDA) { - if (EmitTLSUnsupportedError && DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) + if (getLangOpts().CUDA || getLangOpts().OpenMPIsDevice) { + if (EmitTLSUnsupportedError && + ((getLangOpts().CUDA && DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) || + (getLangOpts().OpenMPIsDevice && + NewVD->hasAttr<OMPDeclareTargetDeclAttr>()))) Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), diag::err_thread_unsupported); // CUDA B.2.5: "__shared__ and __constant__ variables have implied static @@ -7917,10 +7920,7 @@ static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) { if (PT->isImageType()) return PtrKernelParam; - if (PT->isBooleanType()) - return InvalidKernelParam; - - if (PT->isEventT()) + if (PT->isBooleanType() || PT->isEventT() || PT->isReserveIDT()) return InvalidKernelParam; // OpenCL extension spec v1.2 s9.5: @@ -12176,7 +12176,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy(); sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; - if (getLangOpts().CoroutinesTS && getCurFunction()->CoroutinePromise) + if (getLangOpts().CoroutinesTS && getCurFunction()->isCoroutine()) CheckCompletedCoroutineBody(FD, Body); if (FD) { @@ -16097,7 +16097,8 @@ void Sema::ActOnModuleEnd(SourceLocation EomLoc, Module *Mod) { void Sema::createImplicitModuleImportForErrorRecovery(SourceLocation Loc, Module *Mod) { // Bail if we're not allowed to implicitly import a module here. - if (isSFINAEContext() || !getLangOpts().ModulesErrorRecovery) + if (isSFINAEContext() || !getLangOpts().ModulesErrorRecovery || + VisibleModules.isVisible(Mod)) return; // Create the implicit import declaration. diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 32be26efa14f..6c492fac9eb9 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -238,7 +238,7 @@ static typename std::enable_if<std::is_base_of<clang::Attr, AttrInfo>::value, getAttrName(const AttrInfo &Attr) { return &Attr; } -const IdentifierInfo *getAttrName(const clang::AttributeList &Attr) { +static const IdentifierInfo *getAttrName(const clang::AttributeList &Attr) { return Attr.getName(); } @@ -949,7 +949,7 @@ static bool checkFunctionConditionAttr(Sema &S, Decl *D, Msg = "<no message provided>"; SmallVector<PartialDiagnosticAt, 8> Diags; - if (!Cond->isValueDependent() && + if (isa<FunctionDecl>(D) && !Cond->isValueDependent() && !Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(D), Diags)) { S.Diag(Attr.getLoc(), diag::err_attr_cond_never_constant_expr) @@ -1037,10 +1037,11 @@ static void handleDiagnoseIfAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - auto *FD = cast<FunctionDecl>(D); - bool ArgDependent = ArgumentDependenceChecker(FD).referencesArgs(Cond); + bool ArgDependent = false; + if (const auto *FD = dyn_cast<FunctionDecl>(D)) + ArgDependent = ArgumentDependenceChecker(FD).referencesArgs(Cond); D->addAttr(::new (S.Context) DiagnoseIfAttr( - Attr.getRange(), S.Context, Cond, Msg, DiagType, ArgDependent, FD, + Attr.getRange(), S.Context, Cond, Msg, DiagType, ArgDependent, cast<NamedDecl>(D), Attr.getAttributeSpellingListIndex())); } @@ -7283,6 +7284,12 @@ public: return true; } + bool VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) { + SemaRef.Diag(E->getLocStart(), diag::warn_at_available_unchecked_use) + << (!SemaRef.getLangOpts().ObjC1); + return true; + } + bool VisitTypeLoc(TypeLoc Ty); }; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index b543a731641f..d9528be2d383 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -10348,32 +10348,33 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, !Constructor->doesThisDeclarationHaveABody() && !Constructor->isDeleted()) && "DefineImplicitDefaultConstructor - call it for implicit default ctor"); + if (Constructor->willHaveBody() || Constructor->isInvalidDecl()) + return; CXXRecordDecl *ClassDecl = Constructor->getParent(); assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor"); SynthesizedFunctionScope Scope(*this, Constructor); - DiagnosticErrorTrap Trap(Diags); - if (SetCtorInitializers(Constructor, /*AnyErrors=*/false) || - Trap.hasErrorOccurred()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXDefaultConstructor << Context.getTagDeclType(ClassDecl); - Constructor->setInvalidDecl(); - return; - } // The exception specification is needed because we are defining the // function. ResolveExceptionSpec(CurrentLocation, Constructor->getType()->castAs<FunctionProtoType>()); + MarkVTableUsed(CurrentLocation, ClassDecl); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(CurrentLocation); + + if (SetCtorInitializers(Constructor, /*AnyErrors=*/false)) { + Constructor->setInvalidDecl(); + return; + } SourceLocation Loc = Constructor->getLocEnd().isValid() ? Constructor->getLocEnd() : Constructor->getLocation(); Constructor->setBody(new (Context) CompoundStmt(Loc)); - Constructor->markUsed(Context); - MarkVTableUsed(CurrentLocation, ClassDecl); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Constructor); @@ -10483,9 +10484,22 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation, assert(Constructor->getInheritedConstructor() && !Constructor->doesThisDeclarationHaveABody() && !Constructor->isDeleted()); - if (Constructor->isInvalidDecl()) + if (Constructor->willHaveBody() || Constructor->isInvalidDecl()) return; + // Initializations are performed "as if by a defaulted default constructor", + // so enter the appropriate scope. + SynthesizedFunctionScope Scope(*this, Constructor); + + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + Constructor->getType()->castAs<FunctionProtoType>()); + MarkVTableUsed(CurrentLocation, ClassDecl); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(CurrentLocation); + ConstructorUsingShadowDecl *Shadow = Constructor->getInheritedConstructor().getShadowDecl(); CXXConstructorDecl *InheritedCtor = @@ -10500,11 +10514,6 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation, CXXRecordDecl *RD = Shadow->getParent(); SourceLocation InitLoc = Shadow->getLocation(); - // Initializations are performed "as if by a defaulted default constructor", - // so enter the appropriate scope. - SynthesizedFunctionScope Scope(*this, Constructor); - DiagnosticErrorTrap Trap(Diags); - // Build explicit initializers for all base classes from which the // constructor was inherited. SmallVector<CXXCtorInitializer*, 8> Inits; @@ -10535,22 +10544,13 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation, // We now proceed as if for a defaulted default constructor, with the relevant // initializers replaced. - bool HadError = SetCtorInitializers(Constructor, /*AnyErrors*/false, Inits); - if (HadError || Trap.hasErrorOccurred()) { - Diag(CurrentLocation, diag::note_inhctor_synthesized_at) << RD; + if (SetCtorInitializers(Constructor, /*AnyErrors*/false, Inits)) { Constructor->setInvalidDecl(); return; } - // The exception specification is needed because we are defining the - // function. - ResolveExceptionSpec(CurrentLocation, - Constructor->getType()->castAs<FunctionProtoType>()); - Constructor->setBody(new (Context) CompoundStmt(InitLoc)); - Constructor->markUsed(Context); - MarkVTableUsed(CurrentLocation, ClassDecl); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Constructor); @@ -10626,37 +10626,36 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, !Destructor->doesThisDeclarationHaveABody() && !Destructor->isDeleted()) && "DefineImplicitDestructor - call it for implicit default dtor"); + if (Destructor->willHaveBody() || Destructor->isInvalidDecl()) + return; + CXXRecordDecl *ClassDecl = Destructor->getParent(); assert(ClassDecl && "DefineImplicitDestructor - invalid destructor"); - if (Destructor->isInvalidDecl()) - return; - SynthesizedFunctionScope Scope(*this, Destructor); - DiagnosticErrorTrap Trap(Diags); + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + Destructor->getType()->castAs<FunctionProtoType>()); + MarkVTableUsed(CurrentLocation, ClassDecl); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(CurrentLocation); + MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(), Destructor->getParent()); - if (CheckDestructor(Destructor) || Trap.hasErrorOccurred()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXDestructor << Context.getTagDeclType(ClassDecl); - + if (CheckDestructor(Destructor)) { Destructor->setInvalidDecl(); return; } - // The exception specification is needed because we are defining the - // function. - ResolveExceptionSpec(CurrentLocation, - Destructor->getType()->castAs<FunctionProtoType>()); - SourceLocation Loc = Destructor->getLocEnd().isValid() ? Destructor->getLocEnd() : Destructor->getLocation(); Destructor->setBody(new (Context) CompoundStmt(Loc)); Destructor->markUsed(Context); - MarkVTableUsed(CurrentLocation, ClassDecl); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Destructor); @@ -11224,8 +11223,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { /// Diagnose an implicit copy operation for a class which is odr-used, but /// which is deprecated because the class has a user-declared copy constructor, /// copy assignment operator, or destructor. -static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp, - SourceLocation UseLoc) { +static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp) { assert(CopyOp->isImplicit()); CXXRecordDecl *RD = CopyOp->getParent(); @@ -11264,10 +11262,6 @@ static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp, diag::warn_deprecated_copy_operation) << RD << /*copy assignment*/!isa<CXXConstructorDecl>(CopyOp) << /*destructor*/isa<CXXDestructorDecl>(UserDeclaredOperation); - S.Diag(UseLoc, diag::note_member_synthesized_at) - << (isa<CXXConstructorDecl>(CopyOp) ? Sema::CXXCopyConstructor - : Sema::CXXCopyAssignment) - << RD; } } @@ -11279,25 +11273,31 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, !CopyAssignOperator->doesThisDeclarationHaveABody() && !CopyAssignOperator->isDeleted()) && "DefineImplicitCopyAssignment called for wrong function"); + if (CopyAssignOperator->willHaveBody() || CopyAssignOperator->isInvalidDecl()) + return; CXXRecordDecl *ClassDecl = CopyAssignOperator->getParent(); - - if (ClassDecl->isInvalidDecl() || CopyAssignOperator->isInvalidDecl()) { + if (ClassDecl->isInvalidDecl()) { CopyAssignOperator->setInvalidDecl(); return; } + SynthesizedFunctionScope Scope(*this, CopyAssignOperator); + + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + CopyAssignOperator->getType()->castAs<FunctionProtoType>()); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(CurrentLocation); + // C++11 [class.copy]p18: // The [definition of an implicitly declared copy assignment operator] is // deprecated if the class has a user-declared copy constructor or a // user-declared destructor. if (getLangOpts().CPlusPlus11 && CopyAssignOperator->isImplicit()) - diagnoseDeprecatedCopyOperation(*this, CopyAssignOperator, CurrentLocation); - - CopyAssignOperator->markUsed(Context); - - SynthesizedFunctionScope Scope(*this, CopyAssignOperator); - DiagnosticErrorTrap Trap(Diags); + diagnoseDeprecatedCopyOperation(*this, CopyAssignOperator); // C++0x [class.copy]p30: // The implicitly-defined or explicitly-defaulted copy assignment operator @@ -11363,8 +11363,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, /*CopyingBaseSubobject=*/true, /*Copying=*/true); if (Copy.isInvalid()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); CopyAssignOperator->setInvalidDecl(); return; } @@ -11390,8 +11388,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); Invalid = true; continue; } @@ -11402,8 +11398,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); Invalid = true; continue; } @@ -11436,8 +11430,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, /*CopyingBaseSubobject=*/false, /*Copying=*/true); if (Copy.isInvalid()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); CopyAssignOperator->setInvalidDecl(); return; } @@ -11453,22 +11445,10 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, StmtResult Return = BuildReturnStmt(Loc, ThisObj.get()); if (Return.isInvalid()) Invalid = true; - else { + else Statements.push_back(Return.getAs<Stmt>()); - - if (Trap.hasErrorOccurred()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); - Invalid = true; - } - } } - // The exception specification is needed because we are defining the - // function. - ResolveExceptionSpec(CurrentLocation, - CopyAssignOperator->getType()->castAs<FunctionProtoType>()); - if (Invalid) { CopyAssignOperator->setInvalidDecl(); return; @@ -11482,6 +11462,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, assert(!Body.isInvalid() && "Compound statement creation cannot fail"); } CopyAssignOperator->setBody(Body.getAs<Stmt>()); + CopyAssignOperator->markUsed(Context); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(CopyAssignOperator); @@ -11654,19 +11635,15 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, !MoveAssignOperator->doesThisDeclarationHaveABody() && !MoveAssignOperator->isDeleted()) && "DefineImplicitMoveAssignment called for wrong function"); + if (MoveAssignOperator->willHaveBody() || MoveAssignOperator->isInvalidDecl()) + return; CXXRecordDecl *ClassDecl = MoveAssignOperator->getParent(); - - if (ClassDecl->isInvalidDecl() || MoveAssignOperator->isInvalidDecl()) { + if (ClassDecl->isInvalidDecl()) { MoveAssignOperator->setInvalidDecl(); return; } - MoveAssignOperator->markUsed(Context); - - SynthesizedFunctionScope Scope(*this, MoveAssignOperator); - DiagnosticErrorTrap Trap(Diags); - // C++0x [class.copy]p28: // The implicitly-defined or move assignment operator for a non-union class // X performs memberwise move assignment of its subobjects. The direct base @@ -11679,6 +11656,16 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, // from a virtual base more than once. checkMoveAssignmentForRepeatedMove(*this, ClassDecl, CurrentLocation); + SynthesizedFunctionScope Scope(*this, MoveAssignOperator); + + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + MoveAssignOperator->getType()->castAs<FunctionProtoType>()); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(CurrentLocation); + // The statements that form the synthesized function body. SmallVector<Stmt*, 8> Statements; @@ -11743,8 +11730,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, /*CopyingBaseSubobject=*/true, /*Copying=*/false); if (Move.isInvalid()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); MoveAssignOperator->setInvalidDecl(); return; } @@ -11770,8 +11755,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); Invalid = true; continue; } @@ -11782,8 +11765,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); Invalid = true; continue; } @@ -11819,8 +11800,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, /*CopyingBaseSubobject=*/false, /*Copying=*/false); if (Move.isInvalid()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); MoveAssignOperator->setInvalidDecl(); return; } @@ -11837,22 +11816,10 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, StmtResult Return = BuildReturnStmt(Loc, ThisObj.get()); if (Return.isInvalid()) Invalid = true; - else { + else Statements.push_back(Return.getAs<Stmt>()); - - if (Trap.hasErrorOccurred()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); - Invalid = true; - } - } } - // The exception specification is needed because we are defining the - // function. - ResolveExceptionSpec(CurrentLocation, - MoveAssignOperator->getType()->castAs<FunctionProtoType>()); - if (Invalid) { MoveAssignOperator->setInvalidDecl(); return; @@ -11866,6 +11833,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, assert(!Body.isInvalid() && "Compound statement creation cannot fail"); } MoveAssignOperator->setBody(Body.getAs<Stmt>()); + MoveAssignOperator->markUsed(Context); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(MoveAssignOperator); @@ -11952,30 +11920,37 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( } void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, - CXXConstructorDecl *CopyConstructor) { + CXXConstructorDecl *CopyConstructor) { assert((CopyConstructor->isDefaulted() && CopyConstructor->isCopyConstructor() && !CopyConstructor->doesThisDeclarationHaveABody() && !CopyConstructor->isDeleted()) && "DefineImplicitCopyConstructor - call it for implicit copy ctor"); + if (CopyConstructor->willHaveBody() || CopyConstructor->isInvalidDecl()) + return; CXXRecordDecl *ClassDecl = CopyConstructor->getParent(); assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor"); + SynthesizedFunctionScope Scope(*this, CopyConstructor); + + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + CopyConstructor->getType()->castAs<FunctionProtoType>()); + MarkVTableUsed(CurrentLocation, ClassDecl); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(CurrentLocation); + // C++11 [class.copy]p7: // The [definition of an implicitly declared copy constructor] is // deprecated if the class has a user-declared copy assignment operator // or a user-declared destructor. if (getLangOpts().CPlusPlus11 && CopyConstructor->isImplicit()) - diagnoseDeprecatedCopyOperation(*this, CopyConstructor, CurrentLocation); - - SynthesizedFunctionScope Scope(*this, CopyConstructor); - DiagnosticErrorTrap Trap(Diags); + diagnoseDeprecatedCopyOperation(*this, CopyConstructor); - if (SetCtorInitializers(CopyConstructor, /*AnyErrors=*/false) || - Trap.hasErrorOccurred()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXCopyConstructor << Context.getTagDeclType(ClassDecl); + if (SetCtorInitializers(CopyConstructor, /*AnyErrors=*/false)) { CopyConstructor->setInvalidDecl(); } else { SourceLocation Loc = CopyConstructor->getLocEnd().isValid() @@ -11984,16 +11959,9 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, Sema::CompoundScopeRAII CompoundScope(*this); CopyConstructor->setBody( ActOnCompoundStmt(Loc, Loc, None, /*isStmtExpr=*/false).getAs<Stmt>()); + CopyConstructor->markUsed(Context); } - // The exception specification is needed because we are defining the - // function. - ResolveExceptionSpec(CurrentLocation, - CopyConstructor->getType()->castAs<FunctionProtoType>()); - - CopyConstructor->markUsed(Context); - MarkVTableUsed(CurrentLocation, ClassDecl); - if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(CopyConstructor); } @@ -12075,41 +12043,41 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( } void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation, - CXXConstructorDecl *MoveConstructor) { + CXXConstructorDecl *MoveConstructor) { assert((MoveConstructor->isDefaulted() && MoveConstructor->isMoveConstructor() && !MoveConstructor->doesThisDeclarationHaveABody() && !MoveConstructor->isDeleted()) && "DefineImplicitMoveConstructor - call it for implicit move ctor"); + if (MoveConstructor->willHaveBody() || MoveConstructor->isInvalidDecl()) + return; CXXRecordDecl *ClassDecl = MoveConstructor->getParent(); assert(ClassDecl && "DefineImplicitMoveConstructor - invalid constructor"); SynthesizedFunctionScope Scope(*this, MoveConstructor); - DiagnosticErrorTrap Trap(Diags); - if (SetCtorInitializers(MoveConstructor, /*AnyErrors=*/false) || - Trap.hasErrorOccurred()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXMoveConstructor << Context.getTagDeclType(ClassDecl); + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + MoveConstructor->getType()->castAs<FunctionProtoType>()); + MarkVTableUsed(CurrentLocation, ClassDecl); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(CurrentLocation); + + if (SetCtorInitializers(MoveConstructor, /*AnyErrors=*/false)) { MoveConstructor->setInvalidDecl(); - } else { + } else { SourceLocation Loc = MoveConstructor->getLocEnd().isValid() ? MoveConstructor->getLocEnd() : MoveConstructor->getLocation(); Sema::CompoundScopeRAII CompoundScope(*this); MoveConstructor->setBody(ActOnCompoundStmt( Loc, Loc, None, /*isStmtExpr=*/ false).getAs<Stmt>()); + MoveConstructor->markUsed(Context); } - // The exception specification is needed because we are defining the - // function. - ResolveExceptionSpec(CurrentLocation, - MoveConstructor->getType()->castAs<FunctionProtoType>()); - - MoveConstructor->markUsed(Context); - MarkVTableUsed(CurrentLocation, ClassDecl); - if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(MoveConstructor); } @@ -12122,6 +12090,8 @@ bool Sema::isImplicitlyDeleted(FunctionDecl *FD) { void Sema::DefineImplicitLambdaToFunctionPointerConversion( SourceLocation CurrentLocation, CXXConversionDecl *Conv) { + SynthesizedFunctionScope Scope(*this, Conv); + CXXRecordDecl *Lambda = Conv->getParent(); CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator(); // If we are defining a specialization of a conversion to function-ptr @@ -12144,6 +12114,7 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion( "Conversion operator must have a corresponding call operator"); CallOp = cast<CXXMethodDecl>(CallOpSpec); } + // Mark the call operator referenced (and add to pending instantiations // if necessary). // For both the conversion and static-invoker template specializations @@ -12151,9 +12122,6 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion( // to the PendingInstantiations. MarkFunctionReferenced(CurrentLocation, CallOp); - SynthesizedFunctionScope Scope(*this, Conv); - DiagnosticErrorTrap Trap(Diags); - // Retrieve the static invoker... CXXMethodDecl *Invoker = Lambda->getLambdaStaticInvoker(); // ... and get the corresponding specialization for a generic lambda. @@ -12191,7 +12159,7 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion( if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Conv); L->CompletedImplicitDefinition(Invoker); - } + } } @@ -12202,10 +12170,7 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion( { assert(!Conv->getParent()->isGenericLambda()); - Conv->markUsed(Context); - SynthesizedFunctionScope Scope(*this, Conv); - DiagnosticErrorTrap Trap(Diags); // Copy-initialize the lambda object as needed to capture it. Expr *This = ActOnCXXThis(CurrentLocation).get(); @@ -12244,6 +12209,7 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion( Conv->setBody(new (Context) CompoundStmt(Context, ReturnS, Conv->getLocation(), Conv->getLocation())); + Conv->markUsed(Context); // We're done; notify the mutation listener, if any. if (ASTMutationListener *L = getASTMutationListener()) { @@ -13971,6 +13937,11 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { MD->setDefaulted(); MD->setExplicitlyDefaulted(); + // Unset that we will have a body for this function. We might not, + // if it turns out to be trivial, and we don't need this marking now + // that we've marked it as defaulted. + MD->setWillHaveBody(false); + // If this definition appears within the record, do the checking when // the record is complete. const FunctionDecl *Primary = MD; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 14efc9672061..759c82eeaa07 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -366,8 +366,18 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, if (getLangOpts().CUDA && !CheckCUDACall(Loc, FD)) return true; + } - if (diagnoseArgIndependentDiagnoseIfAttrs(FD, Loc)) + auto getReferencedObjCProp = [](const NamedDecl *D) -> + const ObjCPropertyDecl * { + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) + return MD->findPropertyDecl(); + return nullptr; + }; + if (const ObjCPropertyDecl *ObjCPDecl = getReferencedObjCProp(D)) { + if (diagnoseArgIndependentDiagnoseIfAttrs(ObjCPDecl, Loc)) + return true; + } else if (diagnoseArgIndependentDiagnoseIfAttrs(D, Loc)) { return true; } @@ -15742,6 +15752,13 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr( if (Spec != AvailSpecs.end()) Version = Spec->getVersion(); + // The use of `@available` in the enclosing function should be analyzed to + // warn when it's used inappropriately (i.e. not if(@available)). + if (getCurFunctionOrMethodDecl()) + getEnclosingFunction()->HasPotentialAvailabilityViolations = true; + else if (getCurBlock() || getCurLambda()) + getCurFunction()->HasPotentialAvailabilityViolations = true; + return new (Context) ObjCAvailabilityCheckExpr(Version, AtLoc, RParen, Context.BoolTy); } diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 7a9a8ff911aa..4b1d7fd3cf23 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -1591,6 +1591,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, // its constexpr-ness, supressing diagnostics while doing so. if (getLangOpts().CPlusPlus1z && !CallOperator->isInvalidDecl() && !CallOperator->isConstexpr() && + !isa<CoroutineBodyStmt>(CallOperator->getBody()) && !Class->getDeclContext()->isDependentContext()) { TentativeAnalysisScope DiagnosticScopeGuard(*this); CallOperator->setConstexpr( diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 678817f02996..c97da740e4d2 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -4929,8 +4929,6 @@ static NamedDecl *getDefinitionToImport(NamedDecl *D) { void Sema::diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, MissingImportKind MIK, bool Recover) { - assert(!isVisible(Decl) && "missing import for non-hidden decl?"); - // Suggest importing a module providing the definition of this entity, if // possible. NamedDecl *Def = getDefinitionToImport(Decl); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 51794160278c..1ba84034fa47 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -6242,11 +6242,11 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args, } template <typename CheckFn> -static bool diagnoseDiagnoseIfAttrsWith(Sema &S, const FunctionDecl *FD, +static bool diagnoseDiagnoseIfAttrsWith(Sema &S, const NamedDecl *ND, bool ArgDependent, SourceLocation Loc, CheckFn &&IsSuccessful) { SmallVector<const DiagnoseIfAttr *, 8> Attrs; - for (const auto *DIA : FD->specific_attrs<DiagnoseIfAttr>()) { + for (const auto *DIA : ND->specific_attrs<DiagnoseIfAttr>()) { if (ArgDependent == DIA->getArgDependent()) Attrs.push_back(DIA); } @@ -6293,16 +6293,16 @@ bool Sema::diagnoseArgDependentDiagnoseIfAttrs(const FunctionDecl *Function, // EvaluateWithSubstitution only cares about the position of each // argument in the arg list, not the ParmVarDecl* it maps to. if (!DIA->getCond()->EvaluateWithSubstitution( - Result, Context, DIA->getParent(), Args, ThisArg)) + Result, Context, cast<FunctionDecl>(DIA->getParent()), Args, ThisArg)) return false; return Result.isInt() && Result.getInt().getBoolValue(); }); } -bool Sema::diagnoseArgIndependentDiagnoseIfAttrs(const FunctionDecl *Function, +bool Sema::diagnoseArgIndependentDiagnoseIfAttrs(const NamedDecl *ND, SourceLocation Loc) { return diagnoseDiagnoseIfAttrsWith( - *this, Function, /*ArgDependent=*/false, Loc, + *this, ND, /*ArgDependent=*/false, Loc, [&](const DiagnoseIfAttr *DIA) { bool Result; return DIA->getCond()->EvaluateAsBooleanCondition(Result, Context) && diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 2d44489023ef..a654ca800b05 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -197,6 +197,7 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const { case DefaultTemplateArgumentChecking: case DeclaringSpecialMember: + case DefiningSynthesizedFunction: return false; } @@ -624,6 +625,17 @@ void Sema::PrintInstantiationStack() { diag::note_in_declaration_of_implicit_special_member) << cast<CXXRecordDecl>(Active->Entity) << Active->SpecialMember; break; + + case CodeSynthesisContext::DefiningSynthesizedFunction: + // FIXME: For synthesized members other than special members, produce a note. + auto *MD = dyn_cast<CXXMethodDecl>(Active->Entity); + auto CSM = MD ? getSpecialMember(MD) : CXXInvalid; + if (CSM != CXXInvalid) { + Diags.Report(Active->PointOfInstantiation, + diag::note_member_synthesized_at) + << CSM << Context.getTagDeclType(MD->getParent()); + } + break; } } } @@ -666,6 +678,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { return Active->DeductionInfo; case CodeSynthesisContext::DeclaringSpecialMember: + case CodeSynthesisContext::DefiningSynthesizedFunction: // This happens in a context unrelated to template instantiation, so // there is no SFINAE. return None; diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index f4a97f55789e..a65584e3c912 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -6945,6 +6945,19 @@ TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) { if (DeallocRes.isInvalid()) return StmtError(); Builder.Deallocate = DeallocRes.get(); + + assert(S->getResultDecl() && "ResultDecl must already be built"); + StmtResult ResultDecl = getDerived().TransformStmt(S->getResultDecl()); + if (ResultDecl.isInvalid()) + return StmtError(); + Builder.ResultDecl = ResultDecl.get(); + + if (auto *ReturnStmt = S->getReturnStmt()) { + StmtResult Res = getDerived().TransformStmt(ReturnStmt); + if (Res.isInvalid()) + return StmtError(); + Builder.ReturnStmt = Res.get(); + } } return getDerived().RebuildCoroutineBodyStmt(Builder); |