diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -14674,18 +14674,20 @@ if (getLangOpts().CPlusPlus14) { if (!FD->isInvalidDecl() && Body && !FD->isDependentContext() && FD->getReturnType()->isUndeducedType()) { - // If the function has a deduced result type but contains no 'return' - // statements, the result type as written must be exactly 'auto', and - // the deduced result type is 'void'. + // For a function with a deduced result type to return void, + // the result type as written must be 'auto' or 'decltype(auto)', + // possibly cv-qualified or constrained, but not ref-qualified. if (!FD->getReturnType()->getAs()) { Diag(dcl->getLocation(), diag::err_auto_fn_no_return_but_not_auto) << FD->getReturnType(); FD->setInvalidDecl(); } else { - // Substitute 'void' for the 'auto' in the type. - TypeLoc ResultType = getReturnTypeLoc(FD); - Context.adjustDeducedFunctionResultType( - FD, SubstAutoType(ResultType.getType(), Context.VoidTy)); + // Falling off the end of the function is the same as 'return;'. + Expr *Dummy = nullptr; + if (DeduceFunctionTypeFromReturnExpr( + FD, dcl->getLocation(), Dummy, + FD->getReturnType()->getAs())) + FD->setInvalidDecl(); } } } else if (getLangOpts().CPlusPlus11 && isLambdaCallOperator(FD)) { diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -3808,19 +3808,26 @@ LocalTypedefNameReferencer Referencer(*this); Referencer.TraverseType(RetExpr->getType()); } else { - // In the case of a return with no operand, the initializer is considered - // to be void(). - // - // Deduction here can only succeed if the return type is exactly 'cv auto' - // or 'decltype(auto)', so just check for that case directly. + // For a function with a deduced result type to return void, + // the result type as written must be 'auto' or 'decltype(auto)', + // possibly cv-qualified or constrained, but not ref-qualified. if (!OrigResultType.getType()->getAs()) { Diag(ReturnLoc, diag::err_auto_fn_return_void_but_not_auto) << OrigResultType.getType(); return true; } - // We always deduce U = void in this case. - Deduced = SubstAutoType(OrigResultType.getType(), Context.VoidTy); - if (Deduced.isNull()) + // In the case of a return with no operand, the initializer is considered + // to be 'void()'. + Expr *Dummy = new (Context) CXXScalarValueInitExpr( + Context.VoidTy, + Context.getTrivialTypeSourceInfo(Context.VoidTy, ReturnLoc), ReturnLoc); + DeduceAutoResult DAR = DeduceAutoType(OrigResultType, Dummy, Deduced); + + if (DAR == DAR_Failed && !FD->isInvalidDecl()) + Diag(ReturnLoc, diag::err_auto_fn_deduction_failure) + << OrigResultType.getType() << Dummy->getType(); + + if (DAR != DAR_Succeeded) return true; } diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -169,3 +169,42 @@ template void f(T, U) = delete; void g() { f(0, 0); } } + +namespace PR49188 { + template concept C = false; // expected-note 6 {{because 'false' evaluated to false}} + + C auto f1() { // expected-error {{deduced type 'void' does not satisfy 'C'}} + return void(); + } + C auto f2() { // expected-error {{deduced type 'void' does not satisfy 'C'}} + return; + } + C auto f3() { // expected-error {{deduced type 'void' does not satisfy 'C'}} + } + C decltype(auto) f4() { // expected-error {{deduced type 'void' does not satisfy 'C'}} + return void(); + } + C decltype(auto) f5() { // expected-error {{deduced type 'void' does not satisfy 'C'}} + return; + } + C decltype(auto) f6() { // expected-error {{deduced type 'void' does not satisfy 'C'}} + } + C auto& f7() { // expected-error {{cannot form a reference to 'void'}} + return void(); + } + C auto& f8() { + return; // expected-error {{cannot deduce return type 'C auto &' from omitted return expression}} + } + C auto& f9() { // expected-error {{cannot deduce return type 'C auto &' for function with no return statements}} + } +} +namespace PR53911 { + template concept C = false; + + C auto *f1() { + return (void*)nullptr; // FIXME: should error + } + C auto *f2() { + return (int*)nullptr; // FIXME: should error + } +}