https://github.com/sdkrystian created 
https://github.com/llvm/llvm-project/pull/90517

According to [[class.mem.general] 
p8](http://eel.is/c++draft/class.mem.general#8):
> A complete-class context of a class (template) is a
> - function body,
> - default argument,
> - default template argument,
> - _noexcept-specifier_, or
> - default member initializer
>
> within the member-specification of the class or class template.

When testing #90152, it came to my attention that we do _not_ consider the 
_noexcept-specifier_ of a friend function declaration to be a complete-class 
context (something which the Microsoft standard library depends on). Although a 
comment states that this is "consistent with what other implementations do", 
the only other implementation that exhibits this behavior is GCC (MSVC and EDG 
both late-parse the _noexcept-specifier_). 

This patch changes _noexcept-specifiers_ of friend function declarations to be 
late parsed, which is in agreement with the standard & majority of 
implementations. Pre-#90152, our existing implementation falls "in between" the 
implementation consensus: within non-template classes, we would not find latter 
declared members (qualified and unqualified), while within class templates we 
would not find latter declared member when named with a unqualified name, we 
would find members named with a qualified name (even when lookup context is the 
current instantiation). Therefore, this _shouldn't_ be a breaking change -- any 
code that didn't compile will continue to not compile (since a 
_noexcept-specifier_ is not part of the [deduction substitution 
loci](http://eel.is/c++draft/temp.deduct.general#7)), and any code which did 
compile should continue to do so.

>From 3f5feb2b17c06f6e001e9324e90eef07fd720539 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkryst...@gmail.com>
Date: Mon, 29 Apr 2024 15:34:40 -0400
Subject: [PATCH] [Clang][Parse] Delay parsing of noexcept-specifiers in friend
 function declarations

---
 clang/lib/Parse/ParseDecl.cpp | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index a7846e102a43c7..93950e27a08f35 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -7388,12 +7388,20 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
       std::optional<Sema::CXXThisScopeRAII> ThisScope;
       InitCXXThisScopeForDeclaratorIfRelevant(D, DS, ThisScope);
 
-      // Parse exception-specification[opt].
-      // FIXME: Per [class.mem]p6, all exception-specifications at class scope
-      // should be delayed, including those for non-members (eg, friend
-      // declarations). But only applying this to member declarations is
-      // consistent with what other implementations do.
-      bool Delayed = D.isFirstDeclarationOfMember() &&
+      // C++ [class.mem.general]p8:
+      //   A complete-class context of a class (template) is a
+      //     - function body,
+      //     - default argument,
+      //     - default template argument,
+      //     - noexcept-specifier, or
+      //     - default member initializer
+      //   within the member-specification of the class or class template.
+      //
+      // Parse exception-specification[opt]. If we are in the
+      // member-specification of a class or class template, this is a
+      // complete-class context and parsing of the noexcept-specifier should be
+      // delayed (even if this is a friend declaration).
+      bool Delayed = D.getContext() == DeclaratorContext::Member &&
                      D.isFunctionDeclaratorAFunctionDeclaration();
       if (Delayed && Actions.isLibstdcxxEagerExceptionSpecHack(D) &&
           GetLookAheadToken(0).is(tok::kw_noexcept) &&

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to