Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -2895,6 +2895,21 @@ void ActOnDocumentableDecl(Decl *D); void ActOnDocumentableDecls(ArrayRef Group); + enum class FnBodyKind { + /// C++ [dcl.fct.def.general]p1 + /// function-body: + /// = delete ; + /// = default ; + EqDelete, + EqDefault, + + /// Not yet parsed + /// Could be one of: + /// ctor-initializer[opt] compound-statement + /// function-try-block + NotYetParsed + }; + void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, SourceLocation LocAfterDecls); void CheckForFunctionRedefinition( @@ -2902,9 +2917,11 @@ SkipBodyInfo *SkipBody = nullptr); Decl *ActOnStartOfFunctionDef(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParamLists, - SkipBodyInfo *SkipBody = nullptr); + SkipBodyInfo *SkipBody = nullptr, + FnBodyKind BodyKind = FnBodyKind::NotYetParsed); Decl *ActOnStartOfFunctionDef(Scope *S, Decl *D, - SkipBodyInfo *SkipBody = nullptr); + SkipBodyInfo *SkipBody = nullptr, + FnBodyKind BodyKind = FnBodyKind::NotYetParsed); void ActOnStartTrailingRequiresClause(Scope *S, Declarator &D); ExprResult ActOnFinishTrailingRequiresClause(ExprResult ConstraintExpr); ExprResult ActOnRequiresClause(ExprResult ConstraintExpr); Index: clang/lib/Parse/Parser.cpp =================================================================== --- clang/lib/Parse/Parser.cpp +++ clang/lib/Parse/Parser.cpp @@ -1299,6 +1299,41 @@ ParseScope BodyScope(this, Scope::FnScope | Scope::DeclScope | Scope::CompoundStmtScope); + // Parse function body eagerly if it is either '= delete;' or '= default;' as + // ActOnStartOfFunctionDef needs to know whether the function is deleted. + Sema::FnBodyKind BodyKind = Sema::FnBodyKind::NotYetParsed; + SourceLocation KWLoc; + if (TryConsumeToken(tok::equal)) { + assert(getLangOpts().CPlusPlus && "Only C++ function definitions have '='"); + + if (TryConsumeToken(tok::kw_delete, KWLoc)) { + Diag(KWLoc, getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_defaulted_deleted_function + : diag::ext_defaulted_deleted_function) + << 1 /* deleted */; + BodyKind = Sema::FnBodyKind::EqDelete; + } else if (TryConsumeToken(tok::kw_default, KWLoc)) { + Diag(KWLoc, getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_defaulted_deleted_function + : diag::ext_defaulted_deleted_function) + << 0 /* defaulted */; + BodyKind = Sema::FnBodyKind::EqDefault; + } else { + llvm_unreachable("function definition after = not 'delete' or 'default'"); + } + + if (Tok.is(tok::comma)) { + Diag(KWLoc, diag::err_default_delete_in_multiple_declaration) + << (BodyKind == Sema::FnBodyKind::EqDelete); + SkipUntil(tok::semi); + } else if (ExpectAndConsume(tok::semi, diag::err_expected_after, + BodyKind == Sema::FnBodyKind::EqDelete + ? "delete" + : "default")) { + SkipUntil(tok::semi); + } + } + // Tell the actions module that we have entered a function definition with the // specified Declarator for the function. Sema::SkipBodyInfo SkipBody; @@ -1306,10 +1341,13 @@ TemplateInfo.TemplateParams ? *TemplateInfo.TemplateParams : MultiTemplateParamsArg(), - &SkipBody); + &SkipBody, BodyKind); if (SkipBody.ShouldSkip) { - SkipFunctionBody(); + // Do NOT enter SkipFunctionBody if we already consumed the tokens. + if (BodyKind == Sema::FnBodyKind::NotYetParsed) + SkipFunctionBody(); + return Res; } @@ -1320,6 +1358,20 @@ // safe because we're always the sole owner. D.getMutableDeclSpec().abort(); + if (BodyKind != Sema::FnBodyKind::NotYetParsed) { + if (BodyKind == Sema::FnBodyKind::EqDelete) + Actions.SetDeclDeleted(Res, KWLoc); + else if (BodyKind == Sema::FnBodyKind::EqDefault) + Actions.SetDeclDefaulted(Res, KWLoc); + else + llvm_unreachable( + "Eagerly parsed function body should be '= delete;' or '= default;'"); + + Stmt *GeneratedBody = Res ? Res->getBody() : nullptr; + Actions.ActOnFinishFunctionBody(Res, GeneratedBody, false); + return Res; + } + // With abbreviated function templates - we need to explicitly add depth to // account for the implicit template parameter list induced by the template. if (auto *Template = dyn_cast_or_null(Res)) @@ -1329,42 +1381,6 @@ // parameter list was specified. CurTemplateDepthTracker.addDepth(1); - if (TryConsumeToken(tok::equal)) { - assert(getLangOpts().CPlusPlus && "Only C++ function definitions have '='"); - - bool Delete = false; - SourceLocation KWLoc; - if (TryConsumeToken(tok::kw_delete, KWLoc)) { - Diag(KWLoc, getLangOpts().CPlusPlus11 - ? diag::warn_cxx98_compat_defaulted_deleted_function - : diag::ext_defaulted_deleted_function) - << 1 /* deleted */; - Actions.SetDeclDeleted(Res, KWLoc); - Delete = true; - } else if (TryConsumeToken(tok::kw_default, KWLoc)) { - Diag(KWLoc, getLangOpts().CPlusPlus11 - ? diag::warn_cxx98_compat_defaulted_deleted_function - : diag::ext_defaulted_deleted_function) - << 0 /* defaulted */; - Actions.SetDeclDefaulted(Res, KWLoc); - } else { - llvm_unreachable("function definition after = not 'delete' or 'default'"); - } - - if (Tok.is(tok::comma)) { - Diag(KWLoc, diag::err_default_delete_in_multiple_declaration) - << Delete; - SkipUntil(tok::semi); - } else if (ExpectAndConsume(tok::semi, diag::err_expected_after, - Delete ? "delete" : "default")) { - SkipUntil(tok::semi); - } - - Stmt *GeneratedBody = Res ? Res->getBody() : nullptr; - Actions.ActOnFinishFunctionBody(Res, GeneratedBody, false); - return Res; - } - if (SkipFunctionBodies && (!Res || Actions.canSkipFunctionBody(Res)) && trySkippingFunctionBody()) { BodyScope.Exit(); Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -14185,7 +14185,7 @@ Decl * Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, - SkipBodyInfo *SkipBody) { + SkipBodyInfo *SkipBody, FnBodyKind BodyKind) { assert(getCurFunctionDecl() == nullptr && "Function parsing confused"); assert(D.isFunctionDeclarator() && "Not a function declarator!"); Scope *ParentScope = FnBodyScope->getParent(); @@ -14204,7 +14204,7 @@ D.setFunctionDefinitionKind(FunctionDefinitionKind::Definition); Decl *DP = HandleDeclarator(ParentScope, D, TemplateParameterLists); - Decl *Dcl = ActOnStartOfFunctionDef(FnBodyScope, DP, SkipBody); + Decl *Dcl = ActOnStartOfFunctionDef(FnBodyScope, DP, SkipBody, BodyKind); if (!Bases.empty()) ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope(Dcl, Bases); @@ -14380,7 +14380,8 @@ } Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, - SkipBodyInfo *SkipBody) { + SkipBodyInfo *SkipBody, + FnBodyKind BodyKind) { if (!D) { // Parsing the function declaration failed in some way. Push on a fake scope // anyway so we can try to parse the function body. @@ -14470,10 +14471,11 @@ } // The return type of a function definition must be complete - // (C99 6.9.1p3, C++ [dcl.fct]p6). + // unless the function is deleted + // (C99 6.9.1p3, C++ [dcl.fct.def.general]p2). QualType ResultType = FD->getReturnType(); if (!ResultType->isDependentType() && !ResultType->isVoidType() && - !FD->isInvalidDecl() && + !FD->isInvalidDecl() && BodyKind != FnBodyKind::EqDelete && RequireCompleteType(FD->getLocation(), ResultType, diag::err_func_def_incomplete_result)) FD->setInvalidDecl(); @@ -14482,8 +14484,9 @@ PushDeclContext(FnBodyScope, FD); // Check the validity of our function parameters - CheckParmsForFunctionDef(FD->parameters(), - /*CheckParameterNames=*/true); + if (BodyKind != FnBodyKind::EqDelete) + CheckParmsForFunctionDef(FD->parameters(), + /*CheckParameterNames=*/true); // Add non-parameter declarations already in the function to the current // scope. Index: clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.general/p2.cpp =================================================================== --- /dev/null +++ clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.general/p2.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +struct Incomplete; // expected-note 4{{forward declaration of 'Incomplete'}} +Incomplete f(Incomplete) = delete; // well-formed +Incomplete g(Incomplete) {} // expected-error{{incomplete result type 'Incomplete' in function definition}}\ +// expected-error{{variable has incomplete type 'Incomplete'}} + +struct C { + Incomplete f(Incomplete) = delete; // well-formed + Incomplete g(Incomplete) {} // expected-error{{incomplete result type 'Incomplete' in function definition}}\ + // expected-error{{variable has incomplete type 'Incomplete'}} +};