aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-05-29 16:25:46 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-05-29 16:25:46 +0000
commitb5aee35cc5d62f11d98539f62e4fe63f0ac9edc6 (patch)
tree3e6ab962dbc73cfe1445a60d2eb4dfba7c939a22 /lib/Sema
parentaa803409c3bd3930126db630c29f63d42f255153 (diff)
downloadsrc-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.cpp24
-rw-r--r--lib/Sema/CoroutineStmtBuilder.h2
-rw-r--r--lib/Sema/SemaChecking.cpp71
-rw-r--r--lib/Sema/SemaCoroutine.cpp277
-rw-r--r--lib/Sema/SemaDecl.cpp19
-rw-r--r--lib/Sema/SemaDeclAttr.cpp17
-rw-r--r--lib/Sema/SemaDeclCXX.cpp255
-rw-r--r--lib/Sema/SemaExpr.cpp19
-rw-r--r--lib/Sema/SemaLambda.cpp1
-rw-r--r--lib/Sema/SemaLookup.cpp2
-rw-r--r--lib/Sema/SemaOverload.cpp10
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp13
-rw-r--r--lib/Sema/TreeTransform.h13
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);