diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2024-07-27 23:34:35 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2024-10-23 18:26:01 +0000 |
commit | 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583 (patch) | |
tree | 6cf5ab1f05330c6773b1f3f64799d56a9c7a1faa /contrib/llvm-project/clang/lib/Parse/ParseCXXInlineMethods.cpp | |
parent | 6b9f7133aba44189d9625c352bc2c2a59baf18ef (diff) | |
parent | ac9a064cb179f3425b310fa2847f8764ac970a4d (diff) |
Diffstat (limited to 'contrib/llvm-project/clang/lib/Parse/ParseCXXInlineMethods.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseCXXInlineMethods.cpp | 86 |
1 files changed, 81 insertions, 5 deletions
diff --git a/contrib/llvm-project/clang/lib/Parse/ParseCXXInlineMethods.cpp b/contrib/llvm-project/clang/lib/Parse/ParseCXXInlineMethods.cpp index 573c90a36eea..9ccbbf9a7d5d 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -20,6 +20,49 @@ using namespace clang; +/// Parse the optional ("message") part of a deleted-function-body. +StringLiteral *Parser::ParseCXXDeletedFunctionMessage() { + if (!Tok.is(tok::l_paren)) + return nullptr; + StringLiteral *Message = nullptr; + BalancedDelimiterTracker BT{*this, tok::l_paren}; + BT.consumeOpen(); + + if (isTokenStringLiteral()) { + ExprResult Res = ParseUnevaluatedStringLiteralExpression(); + if (Res.isUsable()) { + Message = Res.getAs<StringLiteral>(); + Diag(Message->getBeginLoc(), getLangOpts().CPlusPlus26 + ? diag::warn_cxx23_delete_with_message + : diag::ext_delete_with_message) + << Message->getSourceRange(); + } + } else { + Diag(Tok.getLocation(), diag::err_expected_string_literal) + << /*Source='in'*/ 0 << "'delete'"; + SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch); + } + + BT.consumeClose(); + return Message; +} + +/// If we've encountered '= delete' in a context where it is ill-formed, such +/// as in the declaration of a non-function, also skip the ("message") part if +/// it is present to avoid issuing further diagnostics. +void Parser::SkipDeletedFunctionBody() { + if (!Tok.is(tok::l_paren)) + return; + + BalancedDelimiterTracker BT{*this, tok::l_paren}; + BT.consumeOpen(); + + // Just skip to the end of the current declaration. + SkipUntil(tok::r_paren, tok::comma, StopAtSemi | StopBeforeMatch); + if (Tok.is(tok::r_paren)) + BT.consumeClose(); +} + /// ParseCXXInlineMethodDef - We parsed and verified that the specified /// Declarator is a well formed C++ inline method definition. Now lex its body /// and store its tokens for parsing after the C++ class is complete. @@ -70,7 +113,8 @@ NamedDecl *Parser::ParseCXXInlineMethodDef( ? diag::warn_cxx98_compat_defaulted_deleted_function : diag::ext_defaulted_deleted_function) << 1 /* deleted */; - Actions.SetDeclDeleted(FnD, KWLoc); + StringLiteral *Message = ParseCXXDeletedFunctionMessage(); + Actions.SetDeclDeleted(FnD, KWLoc, Message); Delete = true; if (auto *DeclAsFunction = dyn_cast<FunctionDecl>(FnD)) { DeclAsFunction->setRangeEnd(KWEndLoc); @@ -422,14 +466,14 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { ConsumeAnyToken(); } else if (HasUnparsed) { assert(Param->hasInheritedDefaultArg()); - const FunctionDecl *Old; + FunctionDecl *Old; if (const auto *FunTmpl = dyn_cast<FunctionTemplateDecl>(LM.Method)) Old = cast<FunctionDecl>(FunTmpl->getTemplatedDecl())->getPreviousDecl(); else Old = cast<FunctionDecl>(LM.Method)->getPreviousDecl(); if (Old) { - ParmVarDecl *OldParam = const_cast<ParmVarDecl*>(Old->getParamDecl(I)); + ParmVarDecl *OldParam = Old->getParamDecl(I); assert(!OldParam->hasUnparsedDefaultArg()); if (OldParam->hasUninstantiatedDefaultArg()) Param->setUninstantiatedDefaultArg( @@ -467,11 +511,28 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { // and the end of the function-definition, member-declarator, or // declarator. CXXMethodDecl *Method; + FunctionDecl *FunctionToPush; if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(LM.Method)) - Method = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl()); + FunctionToPush = FunTmpl->getTemplatedDecl(); else - Method = dyn_cast<CXXMethodDecl>(LM.Method); + FunctionToPush = cast<FunctionDecl>(LM.Method); + Method = dyn_cast<CXXMethodDecl>(FunctionToPush); + + // Push a function scope so that tryCaptureVariable() can properly visit + // function scopes involving function parameters that are referenced inside + // the noexcept specifier e.g. through a lambda expression. + // Example: + // struct X { + // void ICE(int val) noexcept(noexcept([val]{})); + // }; + // Setup the CurScope to match the function DeclContext - we have such + // assumption in IsInFnTryBlockHandler(). + ParseScope FnScope(this, Scope::FnScope); + Sema::ContextRAII FnContext(Actions, FunctionToPush, + /*NewThisContext=*/false); + Sema::FunctionScopeRAII PopFnContext(Actions); + Actions.PushFunctionScope(); Sema::CXXThisScopeRAII ThisScope( Actions, Method ? Method->getParent() : nullptr, @@ -559,6 +620,8 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { // to be re-used for method bodies as well. ParseScope FnScope(this, Scope::FnScope | Scope::DeclScope | Scope::CompoundStmtScope); + Sema::FPFeaturesStateRAII SaveFPFeatures(Actions); + Actions.ActOnStartOfFunctionDef(getCurScope(), LM.D); if (Tok.is(tok::kw_try)) { @@ -978,6 +1041,19 @@ bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) { } else { break; } + // Pack indexing + if (Tok.is(tok::ellipsis) && NextToken().is(tok::l_square)) { + Toks.push_back(Tok); + SourceLocation OpenLoc = ConsumeToken(); + Toks.push_back(Tok); + ConsumeBracket(); + if (!ConsumeAndStoreUntil(tok::r_square, Toks, /*StopAtSemi=*/true)) { + Diag(Tok.getLocation(), diag::err_expected) << tok::r_square; + Diag(OpenLoc, diag::note_matching) << tok::l_square; + return true; + } + } + } while (Tok.is(tok::coloncolon)); if (Tok.is(tok::code_completion)) { |