aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/Parse/ParseCXXInlineMethods.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2024-07-27 23:34:35 +0000
committerDimitry Andric <dim@FreeBSD.org>2024-10-23 18:26:01 +0000
commit0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583 (patch)
tree6cf5ab1f05330c6773b1f3f64799d56a9c7a1faa /contrib/llvm-project/clang/lib/Parse/ParseCXXInlineMethods.cpp
parent6b9f7133aba44189d9625c352bc2c2a59baf18ef (diff)
parentac9a064cb179f3425b310fa2847f8764ac970a4d (diff)
Diffstat (limited to 'contrib/llvm-project/clang/lib/Parse/ParseCXXInlineMethods.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/Parse/ParseCXXInlineMethods.cpp86
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)) {