diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 825e91876ffce..4ed610b1b6a50 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -209,6 +209,9 @@ C++23 Feature Support - Added a ``__reference_converts_from_temporary`` builtin, completing the necessary compiler support for `P2255R2: Type trait to determine if a reference binds to a temporary `_. +- Implemented `P2797R0: Static and explicit object member functions with the same parameter-type-lists `_. + This completes the support for "deducing this". + C++2c Feature Support ^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index dbf693611a7fa..d2e8d93656359 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -3025,9 +3025,10 @@ class OverloadExpr : public Expr { public: struct FindResult { - OverloadExpr *Expression; - bool IsAddressOfOperand; - bool HasFormOfMemberPointer; + OverloadExpr *Expression = nullptr; + bool IsAddressOfOperand = false; + bool IsAddressOfOperandWithParen = false; + bool HasFormOfMemberPointer = false; }; /// Finds the overloaded expression in the given expression \p E of @@ -3039,6 +3040,7 @@ class OverloadExpr : public Expr { assert(E->getType()->isSpecificBuiltinType(BuiltinType::Overload)); FindResult Result; + bool HasParen = isa(E); E = E->IgnoreParens(); if (isa(E)) { @@ -3048,10 +3050,9 @@ class OverloadExpr : public Expr { Result.HasFormOfMemberPointer = (E == Ovl && Ovl->getQualifier()); Result.IsAddressOfOperand = true; + Result.IsAddressOfOperandWithParen = HasParen; Result.Expression = Ovl; } else { - Result.HasFormOfMemberPointer = false; - Result.IsAddressOfOperand = false; Result.Expression = cast(E); } diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h index 76311b00d2fc5..4a5c9e8ca1229 100644 --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -899,6 +899,8 @@ class Sema; /// object argument. bool IgnoreObjectArgument : 1; + bool TookAddressOfOverload : 1; + /// True if the candidate was found using ADL. CallExpr::ADLCallKind IsADLCandidate : 1; @@ -999,6 +1001,10 @@ class Sema; /// Initialization of an object of class type by constructor, /// using either a parenthesized or braced list of arguments. CSK_InitByConstructor, + + /// C++ [over.match.call.general] + /// Resolve a call through the address of an overload set. + CSK_AddressOfOverloadSet, }; /// Information about operator rewrites to consider when adding operator diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 410f80ae864a1..079cbc00e788d 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -5813,6 +5813,27 @@ static TypoCorrection TryTypoCorrectionForCall(Sema &S, Expr *Fn, return TypoCorrection(); } +// [C++26][[expr.unary.op]/p4 +// A pointer to member is only formed when an explicit & +// is used and its operand is a qualified-id not enclosed in parentheses. +static bool isParenthetizedAndQualifiedAddressOfExpr(Expr *Fn) { + if (!isa(Fn)) + return false; + + Fn = Fn->IgnoreParens(); + + auto *UO = dyn_cast(Fn); + if (!UO || UO->getOpcode() != clang::UO_AddrOf) + return false; + if (auto *DRE = dyn_cast(UO->getSubExpr()->IgnoreParens())) { + assert(isa(DRE->getDecl()) && "expected a function"); + return DRE->hasQualifier(); + } + if (auto *OVL = dyn_cast(UO->getSubExpr()->IgnoreParens())) + return OVL->getQualifier(); + return false; +} + /// ConvertArgumentsForCall - Converts the arguments specified in /// Args/NumArgs to the parameter types of the function FDecl with /// function prototype Proto. Call is the call expression itself, and @@ -5834,8 +5855,10 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, // C99 6.5.2.2p7 - the arguments are implicitly converted, as if by // assignment, to the types of the corresponding parameter, ... + + bool AddressOf = isParenthetizedAndQualifiedAddressOfExpr(Fn); bool HasExplicitObjectParameter = - FDecl && FDecl->hasCXXExplicitFunctionObjectParameter(); + !AddressOf && FDecl && FDecl->hasCXXExplicitFunctionObjectParameter(); unsigned ExplicitObjectParameterOffset = HasExplicitObjectParameter ? 1 : 0; unsigned NumParams = Proto->getNumParams(); bool Invalid = false; @@ -6546,7 +6569,7 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, OverloadExpr::FindResult find = OverloadExpr::find(Fn); // We aren't supposed to apply this logic if there's an '&' involved. - if (!find.HasFormOfMemberPointer) { + if (!find.HasFormOfMemberPointer || find.IsAddressOfOperandWithParen) { if (Expr::hasAnyTypeDependentArguments(ArgExprs)) return CallExpr::Create(Context, Fn, ArgExprs, Context.DependentTy, VK_PRValue, RParenLoc, CurFPFeatureOverrides()); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 0c89fca8d38eb..d97cd2a8559aa 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -6971,6 +6971,7 @@ void Sema::AddOverloadCandidate( Candidate.IsSurrogate = false; Candidate.IsADLCandidate = IsADLCandidate; Candidate.IgnoreObjectArgument = false; + Candidate.TookAddressOfOverload = false; Candidate.ExplicitCallArguments = Args.size(); // Explicit functions are not actually candidates at all if we're not @@ -7545,10 +7546,24 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, CandidateSet.getRewriteInfo().getRewriteKind(Method, PO); Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; + Candidate.TookAddressOfOverload = + CandidateSet.getKind() == OverloadCandidateSet::CSK_AddressOfOverloadSet; Candidate.ExplicitCallArguments = Args.size(); - unsigned NumParams = Method->getNumExplicitParams(); - unsigned ExplicitOffset = Method->isExplicitObjectMemberFunction() ? 1 : 0; + bool IgnoreExplicitObject = + (Method->isExplicitObjectMemberFunction() && + CandidateSet.getKind() == + OverloadCandidateSet::CSK_AddressOfOverloadSet); + bool ImplicitObjectMethodTreatedAsStatic = + CandidateSet.getKind() == + OverloadCandidateSet::CSK_AddressOfOverloadSet && + Method->isImplicitObjectMemberFunction(); + + unsigned ExplicitOffset = + !IgnoreExplicitObject && Method->isExplicitObjectMemberFunction() ? 1 : 0; + + unsigned NumParams = Method->getNumParams() - ExplicitOffset + + int(ImplicitObjectMethodTreatedAsStatic); // (C++ 13.3.2p2): A candidate function having fewer than m // parameters is viable only if it has an ellipsis in its parameter @@ -7566,7 +7581,10 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, // (8.3.6). For the purposes of overload resolution, the // parameter list is truncated on the right, so that there are // exactly m parameters. - unsigned MinRequiredArgs = Method->getMinRequiredExplicitArguments(); + unsigned MinRequiredArgs = Method->getMinRequiredArguments() - + ExplicitOffset + + int(ImplicitObjectMethodTreatedAsStatic); + if (Args.size() < MinRequiredArgs && !PartialOverloading) { // Not enough arguments. Candidate.Viable = false; @@ -7636,7 +7654,14 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, // exist for each argument an implicit conversion sequence // (13.3.3.1) that converts that argument to the corresponding // parameter of F. - QualType ParamType = Proto->getParamType(ArgIdx + ExplicitOffset); + QualType ParamType; + if (ImplicitObjectMethodTreatedAsStatic) { + ParamType = ArgIdx == 0 + ? Method->getFunctionObjectParameterReferenceType() + : Proto->getParamType(ArgIdx - 1); + } else { + ParamType = Proto->getParamType(ArgIdx + ExplicitOffset); + } Candidate.Conversions[ConvIdx] = TryCopyInitialization(*this, Args[ArgIdx], ParamType, SuppressUserConversions, @@ -7717,6 +7742,7 @@ void Sema::AddMethodTemplateCandidate( Candidate.IgnoreObjectArgument = cast(Candidate.Function)->isStatic() || ObjectType.isNull(); + Candidate.TookAddressOfOverload = false; Candidate.ExplicitCallArguments = Args.size(); if (Result == TemplateDeductionResult::NonDependentConversionFailure) Candidate.FailureKind = ovl_fail_bad_conversion; @@ -7807,6 +7833,7 @@ void Sema::AddTemplateOverloadCandidate( Candidate.IgnoreObjectArgument = isa(Candidate.Function) && !isa(Candidate.Function); + Candidate.TookAddressOfOverload = false; Candidate.ExplicitCallArguments = Args.size(); if (Result == TemplateDeductionResult::NonDependentConversionFailure) Candidate.FailureKind = ovl_fail_bad_conversion; @@ -7998,6 +8025,7 @@ void Sema::AddConversionCandidate( Candidate.Function = Conversion; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; + Candidate.TookAddressOfOverload = false; Candidate.FinalConversion.setAsIdentityConversion(); Candidate.FinalConversion.setFromType(ConvType); Candidate.FinalConversion.setAllToTypes(ToType); @@ -8200,6 +8228,7 @@ void Sema::AddTemplateConversionCandidate( Candidate.FailureKind = ovl_fail_bad_deduction; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; + Candidate.TookAddressOfOverload = false; Candidate.ExplicitCallArguments = 1; Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, Info); @@ -8240,6 +8269,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, Candidate.Viable = true; Candidate.IsSurrogate = true; Candidate.IgnoreObjectArgument = false; + Candidate.TookAddressOfOverload = false; Candidate.ExplicitCallArguments = Args.size(); // Determine the implicit conversion sequence for the implicit @@ -8465,6 +8495,7 @@ void Sema::AddBuiltinCandidate(QualType *ParamTys, ArrayRef Args, Candidate.Function = nullptr; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; + Candidate.TookAddressOfOverload = false; std::copy(ParamTys, ParamTys + Args.size(), Candidate.BuiltinParamTypes); // Determine the implicit conversion sequences for each of the @@ -10929,6 +10960,12 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, if (Best->Function && Best->Function->isDeleted()) return OR_Deleted; + if (auto *M = dyn_cast_or_null(Best->Function); + Kind == CSK_AddressOfOverloadSet && M && + M->isImplicitObjectMemberFunction()) { + return OR_No_Viable_Function; + } + if (!EquivalentCands.empty()) S.diagnoseEquivalentInternalLinkageDeclarations(Loc, Best->Function, EquivalentCands); @@ -11508,9 +11545,10 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, /// candidates. This is not covered by the more general DiagnoseArityMismatch() /// over a candidate in any candidate set. static bool CheckArityMismatch(Sema &S, OverloadCandidate *Cand, - unsigned NumArgs) { + unsigned NumArgs, bool IsAddressOf = false) { FunctionDecl *Fn = Cand->Function; - unsigned MinParams = Fn->getMinRequiredArguments(); + unsigned MinParams = Fn->getMinRequiredExplicitArguments() + + ((IsAddressOf && !Fn->isStatic()) ? 1 : 0); // With invalid overloaded operators, it's possible that we think we // have an arity mismatch when in fact it looks like we have the @@ -11538,7 +11576,8 @@ static bool CheckArityMismatch(Sema &S, OverloadCandidate *Cand, /// General arity mismatch diagnosis over a candidate in a candidate set. static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D, - unsigned NumFormalArgs) { + unsigned NumFormalArgs, + bool IsAddressOf = false) { assert(isa(D) && "The templated declaration should at least be a function" " when diagnosing bad template argument deduction due to too many" @@ -11548,12 +11587,17 @@ static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D, // TODO: treat calls to a missing default constructor as a special case const auto *FnTy = Fn->getType()->castAs(); - unsigned MinParams = Fn->getMinRequiredExplicitArguments(); + unsigned MinParams = Fn->getMinRequiredExplicitArguments() + + ((IsAddressOf && !Fn->isStatic()) ? 1 : 0); // at least / at most / exactly - bool HasExplicitObjectParam = Fn->hasCXXExplicitFunctionObjectParameter(); - unsigned ParamCount = FnTy->getNumParams() - (HasExplicitObjectParam ? 1 : 0); + bool HasExplicitObjectParam = + !IsAddressOf && Fn->hasCXXExplicitFunctionObjectParameter(); + + unsigned ParamCount = + Fn->getNumNonObjectParams() + ((IsAddressOf && !Fn->isStatic()) ? 1 : 0); unsigned mode, modeCount; + if (NumFormalArgs < MinParams) { if (MinParams != ParamCount || FnTy->isVariadic() || FnTy->isTemplateVariadic()) @@ -11573,7 +11617,7 @@ static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D, std::pair FnKindPair = ClassifyOverloadCandidate(S, Found, Fn, CRK_None, Description); - if (modeCount == 1 && + if (modeCount == 1 && !IsAddressOf && Fn->getParamDecl(HasExplicitObjectParam ? 1 : 0)->getDeclName()) S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity_one) << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second @@ -11592,8 +11636,9 @@ static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D, /// Arity mismatch diagnosis specific to a function overload candidate. static void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand, unsigned NumFormalArgs) { - if (!CheckArityMismatch(S, Cand, NumFormalArgs)) - DiagnoseArityMismatch(S, Cand->FoundDecl, Cand->Function, NumFormalArgs); + if (!CheckArityMismatch(S, Cand, NumFormalArgs, Cand->TookAddressOfOverload)) + DiagnoseArityMismatch(S, Cand->FoundDecl, Cand->Function, NumFormalArgs, + Cand->TookAddressOfOverload); } static TemplateDecl *getDescribedTemplate(Decl *Templated) { @@ -12033,6 +12078,13 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, Cand->FailureKind != ovl_fail_bad_conversion) return; + // Skip implicit member functions when trying to resolve + // the address of a an overload set for a function pointer. + if (Cand->TookAddressOfOverload && + !Cand->Function->hasCXXExplicitFunctionObjectParameter() && + !Cand->Function->isStatic()) + return; + // Note deleted candidates, but only if they're viable. if (Cand->Viable) { if (Fn->isDeleted()) { @@ -14076,6 +14128,21 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, } case OR_No_Viable_Function: { + if (*Best != CandidateSet->end() && + CandidateSet->getKind() == + clang::OverloadCandidateSet::CSK_AddressOfOverloadSet) { + if (CXXMethodDecl *M = + dyn_cast_if_present((*Best)->Function); + M && M->isImplicitObjectMemberFunction()) { + CandidateSet->NoteCandidates( + PartialDiagnosticAt( + Fn->getBeginLoc(), + SemaRef.PDiag(diag::err_member_call_without_object) << 0 << M), + SemaRef, OCD_AmbiguousCandidates, Args); + return ExprError(); + } + } + // Try to recover by looking for viable functions which the user might // have meant to call. ExprResult Recovery = BuildRecoveryCallExpr(SemaRef, S, Fn, ULE, LParenLoc, @@ -14167,8 +14234,10 @@ ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, Expr *ExecConfig, bool AllowTypoCorrection, bool CalleesAddressIsTaken) { - OverloadCandidateSet CandidateSet(Fn->getExprLoc(), - OverloadCandidateSet::CSK_Normal); + OverloadCandidateSet CandidateSet( + Fn->getExprLoc(), CalleesAddressIsTaken + ? OverloadCandidateSet::CSK_AddressOfOverloadSet + : OverloadCandidateSet::CSK_Normal); ExprResult result; if (buildOverloadedCallSet(S, Fn, ULE, Args, LParenLoc, &CandidateSet, @@ -16333,9 +16402,9 @@ ExprResult Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, assert(UnOp->getOpcode() == UO_AddrOf && "Can only take the address of an overloaded function"); if (CXXMethodDecl *Method = dyn_cast(Fn)) { - if (Method->isStatic()) { - // Do nothing: static member functions aren't any different - // from non-member functions. + if (!Method->isImplicitObjectMemberFunction()) { + // Do nothing: the address of static and + // explicit object member functions is a (non-member) function pointer. } else { // Fix the subexpression, which really has to be an // UnresolvedLookupExpr holding an overloaded member function @@ -16393,7 +16462,10 @@ ExprResult Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, } QualType Type = Fn->getType(); - ExprValueKind ValueKind = getLangOpts().CPlusPlus ? VK_LValue : VK_PRValue; + ExprValueKind ValueKind = + getLangOpts().CPlusPlus && !Fn->hasCXXExplicitFunctionObjectParameter() + ? VK_LValue + : VK_PRValue; // FIXME: Duplicated from BuildDeclarationNameExpr. if (unsigned BID = Fn->getBuiltinID()) { diff --git a/clang/test/CXX/drs/cwg1xx.cpp b/clang/test/CXX/drs/cwg1xx.cpp index a8f9b705a9866..21859fc6b1cbf 100644 --- a/clang/test/CXX/drs/cwg1xx.cpp +++ b/clang/test/CXX/drs/cwg1xx.cpp @@ -843,23 +843,21 @@ namespace cwg161 { // cwg161: 3.1 }; } -namespace cwg162 { // cwg162: no +namespace cwg162 { // cwg162: 19 struct A { char &f(char); static int &f(int); void g() { int &a = (&A::f)(0); - // FIXME: expected-error@-1 {{reference to overloaded function could not be resolved; did you mean to call it?}} char &b = (&A::f)('0'); - // expected-error@-1 {{reference to overloaded function could not be resolved; did you mean to call it?}} + // expected-error@-1 {{non-const lvalue reference to type 'char' cannot bind to a value of unrelated type 'int'}} } }; int &c = (&A::f)(0); - // FIXME: expected-error@-1 {{reference to overloaded function could not be resolved; did you mean to call it?}} char &d = (&A::f)('0'); - // expected-error@-1 {{reference to overloaded function could not be resolved; did you mean to call it?}} + // expected-error@-1 {{non-const lvalue reference to type 'char' cannot bind to a value of unrelated type 'int'}} } // cwg163: na diff --git a/clang/test/CXX/drs/cwg26xx.cpp b/clang/test/CXX/drs/cwg26xx.cpp index d3c5b5bb7b6b9..7e79b150f36d7 100644 --- a/clang/test/CXX/drs/cwg26xx.cpp +++ b/clang/test/CXX/drs/cwg26xx.cpp @@ -240,3 +240,30 @@ void test() { } } #endif + + +namespace cwg2692 { // cwg2692: 19 +#if __cplusplus >= 202302L + + struct A { + static void f(A); // #cwg2692-1 + void f(this A); // #cwg2692-2 + + void g(); + }; + + void A::g() { + (&A::f)(A()); + // expected-error@-1 {{call to 'f' is ambiguous}} + // expected-note@#cwg2692-1 {{candidate}} + // expected-note@#cwg2692-2 {{candidate}} + + + + (&A::f)(); + // expected-error@-1 {{no matching function for call to 'f'}} + // expected-note@#cwg2692-1 {{candidate function not viable: requires 1 argument, but 0 were provided}} + // expected-note@#cwg2692-2 {{candidate function not viable: requires 1 argument, but 0 were provided}} + } +#endif +} diff --git a/clang/test/CXX/drs/cwg2771.cpp b/clang/test/CXX/drs/cwg2771.cpp new file mode 100644 index 0000000000000..474660aa28440 --- /dev/null +++ b/clang/test/CXX/drs/cwg2771.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -std=c++23 %s -ast-dump | FileCheck --check-prefixes=CXX23 %s + +namespace cwg2771 { // cwg2771: 18 + +struct A{ + int a; + void cwg2771(){ + int* r = &a; + } +}; +// CXX23: CXXMethodDecl{{.+}}cwg2771 +// CXX23-NEXT: CompoundStmt +// CXX23-NEXT: DeclStmt +// CXX23-NEXT: VarDecl +// CXX23-NEXT: UnaryOperator +// CXX23-NEXT: MemberExpr +// CXX23-NEXT: CXXThisExpr{{.+}}'cwg2771::A *' + +} // namespace cwg2771 diff --git a/clang/test/CodeGenCXX/cxx2b-deducing-this.cpp b/clang/test/CodeGenCXX/cxx2b-deducing-this.cpp index 649fe2afbf4e9..f9f9fbd7397f8 100644 --- a/clang/test/CodeGenCXX/cxx2b-deducing-this.cpp +++ b/clang/test/CodeGenCXX/cxx2b-deducing-this.cpp @@ -245,3 +245,23 @@ void f() { d(); } } + + +namespace P2797 { +struct C { + void c(this const C&); // #first + void c() &; // #second + static void c(int = 0); // #third + + void d() { + (&C::c)(C{}); + (&C::c)(); + } +}; +void test() { + (void)C{}.d(); +} +// CHECK-LABEL: {{.*}} @_ZN5P27971C1dEv +// CHECK: call void @_ZNH5P27971C1cERKS0_ +// CHECK: call void @_ZN5P27971C1cEi +} diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp b/clang/test/SemaCXX/cxx2b-deducing-this.cpp index cdb9d1324b974..2c19b091fabad 100644 --- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp +++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp @@ -893,3 +893,28 @@ void g() { a * lval; } } + +namespace P2797 { +struct C { + void c(this const C&); // #first + void c() &; // #second + static void c(int = 0); // #third + + void d() { + c(); // expected-error {{call to member function 'c' is ambiguous}} + // expected-note@#first {{candidate function}} + // expected-note@#second {{candidate function}} + // expected-note@#third {{candidate function}} + + (C::c)(); // expected-error {{call to member function 'c' is ambiguous}} + // expected-note@#first {{candidate function}} + // expected-note@#second {{candidate function}} + // expected-note@#third {{candidate function}} + + (&(C::c))(); // expected-error {{cannot create a non-constant pointer to member function}} + (&C::c)(C{}); + (&C::c)(*this); // expected-error {{call to non-static member function without an object argument}} + (&C::c)(); + } +}; +} diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index 4cce88fe0490f..7df6c0a05a487 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -1010,7 +1010,7 @@

C++ defect report implementation status

162 CD1 (&C::f)() with nonstatic members - No + Clang 19 163 @@ -15960,7 +15960,7 @@

C++ defect report implementation status

2692 C++23 Static and explicit object member functions with the same parameter-type-lists - Unknown + Clang 19 2693 @@ -16435,7 +16435,7 @@

C++ defect report implementation status

2771 DR Transformation for unqualified-ids in address operator - Unknown + Clang 18 2772 diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index 45416170b16e5..65dd31a0fb802 100755 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -283,7 +283,7 @@

C++23 implementation status

P2797R0 - No + Clang 19 Change scope of lambda trailing-return-type