From: Arthur O'Dwyer Date: Mon, 14 Feb 2022 21:03:01 +0000 (-0500) Subject: [clang] [concepts] Check constrained-auto return types for void-returning functions X-Git-Tag: upstream/15.0.7~14595 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f0891cd61b2f7cd57d906406ae785722bfd87603;p=platform%2Fupstream%2Fllvm.git [clang] [concepts] Check constrained-auto return types for void-returning functions Fixes #49188. Differential Revision: https://reviews.llvm.org/D119184 --- diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 7d9d5ec..b88d9f2 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -14674,18 +14674,20 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, 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 index d51a71f..e23fd23 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -3808,19 +3808,26 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, 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 index c297a75..20af504 100644 --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -169,3 +169,42 @@ namespace PR50561 { 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 + } +}