https://github.com/zyn0217 updated 
https://github.com/llvm/llvm-project/pull/142945

>From cdd6868879abf4b6c991c7f2b3e9cf9673b0570a Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7...@gmail.com>
Date: Thu, 5 Jun 2025 18:52:01 +0800
Subject: [PATCH 1/2] [Clang] Fix name lookup of conversion operators

(TODO: Add explanation)
---
 clang/include/clang/Parse/Parser.h            | 57 ++++++++++++-------
 clang/include/clang/Sema/DeclSpec.h           | 23 +++++---
 clang/include/clang/Sema/Sema.h               |  1 +
 clang/lib/Parse/ParseDecl.cpp                 | 32 +++++++----
 clang/lib/Parse/ParseDeclCXX.cpp              | 10 +++-
 clang/lib/Parse/ParseExpr.cpp                 |  3 +-
 clang/lib/Parse/ParseExprCXX.cpp              | 42 +++++++++-----
 clang/lib/Parse/ParseOpenMP.cpp               | 16 +++---
 clang/lib/Parse/ParseStmtAsm.cpp              |  3 +-
 clang/lib/Parse/ParseTemplate.cpp             |  1 +
 clang/lib/Parse/Parser.cpp                    |  9 ++-
 clang/lib/Sema/SemaDecl.cpp                   | 20 ++++---
 clang/lib/Sema/SemaType.cpp                   |  4 ++
 .../basic.lookup/basic.lookup.unqual/p5.cpp   | 52 +++++++++++++++++
 clang/test/CXX/drs/cwg11xx.cpp                |  4 +-
 clang/test/CXX/temp/temp.res/p4.cpp           |  2 +-
 clang/unittests/Tooling/TestVisitor.h         |  8 +--
 17 files changed, 204 insertions(+), 83 deletions(-)
 create mode 100644 clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p5.cpp

diff --git a/clang/include/clang/Parse/Parser.h 
b/clang/include/clang/Parse/Parser.h
index 98db8201390be..16764b5ba1ad6 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -359,7 +359,8 @@ class Parser : public CodeCompletionHandler {
   /// Note that this routine emits an error if you call it with ::new or
   /// ::delete as the current tokens, so only call it in contexts where these
   /// are invalid.
-  bool TryAnnotateCXXScopeToken(bool EnteringContext = false);
+  bool TryAnnotateCXXScopeToken(bool EnteringContext = false,
+                                ParsedType ObjectType = nullptr);
 
   bool MightBeCXXScopeToken() {
     return getLangOpts().CPlusPlus &&
@@ -1525,8 +1526,10 @@ class Parser : public CodeCompletionHandler {
     DSC_class,          // class context, enables 'friend'
     DSC_type_specifier, // C++ type-specifier-seq or C specifier-qualifier-list
     DSC_trailing, // C++11 trailing-type-specifier in a trailing return type
-    DSC_alias_declaration,  // C++11 type-specifier-seq in an alias-declaration
-    DSC_conv_operator,      // C++ type-specifier-seq in an conversion operator
+    DSC_alias_declaration, // C++11 type-specifier-seq in an alias-declaration
+    DSC_conv_operator,     // C++ type-specifier-seq in an conversion operator
+    DSC_conv_operator_in_postfix_expr, // C++ type-specifier-seq which is
+                                       // referenced in a postfix expression
     DSC_top_level,          // top-level/namespace declaration context
     DSC_template_param,     // template parameter context
     DSC_template_arg,       // template argument context
@@ -1554,6 +1557,7 @@ class Parser : public CodeCompletionHandler {
     case DeclSpecContext::DSC_template_type_arg:
     case DeclSpecContext::DSC_type_specifier:
     case DeclSpecContext::DSC_conv_operator:
+    case DeclSpecContext::DSC_conv_operator_in_postfix_expr:
     case DeclSpecContext::DSC_trailing:
     case DeclSpecContext::DSC_alias_declaration:
     case DeclSpecContext::DSC_association:
@@ -1605,6 +1609,7 @@ class Parser : public CodeCompletionHandler {
 
     case DeclSpecContext::DSC_trailing:
     case DeclSpecContext::DSC_conv_operator:
+    case DeclSpecContext::DSC_conv_operator_in_postfix_expr:
     case DeclSpecContext::DSC_template_arg:
     case DeclSpecContext::DSC_new:
       return AllowDefiningTypeSpec::No;
@@ -1629,6 +1634,7 @@ class Parser : public CodeCompletionHandler {
     case DeclSpecContext::DSC_trailing:
     case DeclSpecContext::DSC_association:
     case DeclSpecContext::DSC_conv_operator:
+    case DeclSpecContext::DSC_conv_operator_in_postfix_expr:
     case DeclSpecContext::DSC_template_arg:
     case DeclSpecContext::DSC_new:
 
@@ -1650,6 +1656,7 @@ class Parser : public CodeCompletionHandler {
     case DeclSpecContext::DSC_type_specifier:
     case DeclSpecContext::DSC_association:
     case DeclSpecContext::DSC_conv_operator:
+    case DeclSpecContext::DSC_conv_operator_in_postfix_expr:
     case DeclSpecContext::DSC_new:
       return true;
 
@@ -1673,6 +1680,7 @@ class Parser : public CodeCompletionHandler {
     case DeclSpecContext::DSC_trailing:
     case DeclSpecContext::DSC_alias_declaration:
     case DeclSpecContext::DSC_template_param:
+    case DeclSpecContext::DSC_conv_operator_in_postfix_expr:
     case DeclSpecContext::DSC_new:
       return ImplicitTypenameContext::Yes;
 
@@ -1826,9 +1834,11 @@ class Parser : public CodeCompletionHandler {
   ParseDeclarationSpecifiers(DeclSpec &DS, ParsedTemplateInfo &TemplateInfo,
                              AccessSpecifier AS = AS_none,
                              DeclSpecContext DSC = DeclSpecContext::DSC_normal,
-                             LateParsedAttrList *LateAttrs = nullptr) {
+                             LateParsedAttrList *LateAttrs = nullptr,
+                             ParsedType ObjectType = nullptr) {
     return ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC, LateAttrs,
-                                      getImplicitTypenameContext(DSC));
+                                      getImplicitTypenameContext(DSC),
+                                      ObjectType);
   }
 
   /// ParseDeclarationSpecifiers
@@ -1860,11 +1870,12 @@ class Parser : public CodeCompletionHandler {
   ///       'friend': [C++ dcl.friend]
   ///       'constexpr': [C++0x dcl.constexpr]
   /// \endverbatim
-  void
-  ParseDeclarationSpecifiers(DeclSpec &DS, ParsedTemplateInfo &TemplateInfo,
-                             AccessSpecifier AS, DeclSpecContext DSC,
-                             LateParsedAttrList *LateAttrs,
-                             ImplicitTypenameContext AllowImplicitTypename);
+  void ParseDeclarationSpecifiers(DeclSpec &DS,
+                                  ParsedTemplateInfo &TemplateInfo,
+                                  AccessSpecifier AS, DeclSpecContext DSC,
+                                  LateParsedAttrList *LateAttrs,
+                                  ImplicitTypenameContext 
AllowImplicitTypename,
+                                  ParsedType ObjectType);
 
   /// Determine whether we're looking at something that might be a declarator
   /// in a simple-declaration. If it can't possibly be a declarator, maybe
@@ -1877,10 +1888,12 @@ class Parser : public CodeCompletionHandler {
       DeclSpec &DS, AccessSpecifier AS, DeclSpecContext DSContext,
       LateParsedAttrList *LateAttrs = nullptr);
 
-  void ParseSpecifierQualifierList(
-      DeclSpec &DS, AccessSpecifier AS = AS_none,
-      DeclSpecContext DSC = DeclSpecContext::DSC_normal) {
-    ParseSpecifierQualifierList(DS, getImplicitTypenameContext(DSC), AS, DSC);
+  void
+  ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS = AS_none,
+                              DeclSpecContext DSC = 
DeclSpecContext::DSC_normal,
+                              ParsedType ObjectType = nullptr) {
+    ParseSpecifierQualifierList(DS, getImplicitTypenameContext(DSC), AS, DSC,
+                                ObjectType);
   }
 
   /// ParseSpecifierQualifierList
@@ -1891,10 +1904,12 @@ class Parser : public CodeCompletionHandler {
   /// [GNU]    attributes     specifier-qualifier-list[opt]
   /// \endverbatim
   ///
-  void ParseSpecifierQualifierList(
-      DeclSpec &DS, ImplicitTypenameContext AllowImplicitTypename,
-      AccessSpecifier AS = AS_none,
-      DeclSpecContext DSC = DeclSpecContext::DSC_normal);
+  void
+  ParseSpecifierQualifierList(DeclSpec &DS,
+                              ImplicitTypenameContext AllowImplicitTypename,
+                              AccessSpecifier AS = AS_none,
+                              DeclSpecContext DSC = 
DeclSpecContext::DSC_normal,
+                              ParsedType ObjectType = nullptr);
 
   /// ParseEnumSpecifier
   /// \verbatim
@@ -4413,7 +4428,7 @@ class Parser : public CodeCompletionHandler {
   bool ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType,
                           bool ObjectHadErrors, bool EnteringContext,
                           bool AllowDestructorName, bool AllowConstructorName,
-                          bool AllowDeductionGuide,
+                          bool AllowDeductionGuide, bool ForPostfixExpression,
                           SourceLocation *TemplateKWLoc, UnqualifiedId 
&Result);
 
 private:
@@ -4826,7 +4841,8 @@ class Parser : public CodeCompletionHandler {
   /// \endverbatim
   ///
   bool ParseCXXTypeSpecifierSeq(
-      DeclSpec &DS, DeclaratorContext Context = DeclaratorContext::TypeName);
+      DeclSpec &DS, DeclaratorContext Context = DeclaratorContext::TypeName,
+      ParsedType ObjectType = nullptr);
 
   
//===--------------------------------------------------------------------===//
   // C++ 5.3.4 and 5.3.5: C++ new and delete
@@ -5091,6 +5107,7 @@ class Parser : public CodeCompletionHandler {
   ///
   /// \returns true if parsing fails, false otherwise.
   bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
+                                  bool ForPostfixExpression,
                                   ParsedType ObjectType, UnqualifiedId 
&Result);
 
   
//===--------------------------------------------------------------------===//
diff --git a/clang/include/clang/Sema/DeclSpec.h 
b/clang/include/clang/Sema/DeclSpec.h
index 6c4a32c4ac2f0..e33411a1bd7dd 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -1871,14 +1871,15 @@ enum class DeclaratorContext {
   LambdaExpr,          // Lambda-expression declarator.
   LambdaExprParameter, // Lambda-expression parameter declarator.
   ConversionId,        // C++ conversion-type-id.
-  TrailingReturn,      // C++11 trailing-type-specifier.
-  TrailingReturnVar,   // C++11 trailing-type-specifier for variable.
-  TemplateArg,         // Any template argument (in template argument list).
-  TemplateTypeArg,     // Template type argument (in default argument).
-  AliasDecl,           // C++11 alias-declaration.
-  AliasTemplate,       // C++11 alias-declaration template.
-  RequiresExpr,        // C++2a requires-expression.
-  Association          // C11 _Generic selection expression association.
+  ConversionIdInPostfixExpr, // C++ conversion-type-id.
+  TrailingReturn,            // C++11 trailing-type-specifier.
+  TrailingReturnVar,         // C++11 trailing-type-specifier for variable.
+  TemplateArg,     // Any template argument (in template argument list).
+  TemplateTypeArg, // Template type argument (in default argument).
+  AliasDecl,       // C++11 alias-declaration.
+  AliasTemplate,   // C++11 alias-declaration template.
+  RequiresExpr,    // C++2a requires-expression.
+  Association,     // C11 _Generic selection expression association.
 };
 
 // Describes whether the current context is a context where an implicit
@@ -2159,6 +2160,7 @@ class Declarator {
     case DeclaratorContext::BlockLiteral:
     case DeclaratorContext::LambdaExpr:
     case DeclaratorContext::ConversionId:
+    case DeclaratorContext::ConversionIdInPostfixExpr:
     case DeclaratorContext::TemplateArg:
     case DeclaratorContext::TemplateTypeArg:
     case DeclaratorContext::TrailingReturn:
@@ -2200,6 +2202,7 @@ class Declarator {
     case DeclaratorContext::BlockLiteral:
     case DeclaratorContext::LambdaExpr:
     case DeclaratorContext::ConversionId:
+    case DeclaratorContext::ConversionIdInPostfixExpr:
     case DeclaratorContext::TemplateArg:
     case DeclaratorContext::TemplateTypeArg:
     case DeclaratorContext::TrailingReturn:
@@ -2244,6 +2247,7 @@ class Declarator {
     case DeclaratorContext::BlockLiteral:
     case DeclaratorContext::LambdaExpr:
     case DeclaratorContext::ConversionId:
+    case DeclaratorContext::ConversionIdInPostfixExpr:
     case DeclaratorContext::TemplateArg:
     case DeclaratorContext::TemplateTypeArg:
     case DeclaratorContext::TrailingReturn:
@@ -2301,6 +2305,7 @@ class Declarator {
     case DeclaratorContext::BlockLiteral:
     case DeclaratorContext::LambdaExpr:
     case DeclaratorContext::ConversionId:
+    case DeclaratorContext::ConversionIdInPostfixExpr:
     case DeclaratorContext::TemplateArg:
     case DeclaratorContext::TemplateTypeArg:
     case DeclaratorContext::TrailingReturn:
@@ -2539,6 +2544,7 @@ class Declarator {
     case DeclaratorContext::BlockLiteral:
     case DeclaratorContext::LambdaExpr:
     case DeclaratorContext::ConversionId:
+    case DeclaratorContext::ConversionIdInPostfixExpr:
     case DeclaratorContext::TemplateArg:
     case DeclaratorContext::TemplateTypeArg:
     case DeclaratorContext::TrailingReturn:
@@ -2587,6 +2593,7 @@ class Declarator {
     case DeclaratorContext::SelectionInit:
     case DeclaratorContext::Condition:
     case DeclaratorContext::TemplateArg:
+    case DeclaratorContext::ConversionIdInPostfixExpr:
       return true;
     }
 
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 84d30561fecde..265d35bff16c3 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3568,6 +3568,7 @@ class Sema final : public SemaBase {
                          bool isClassName = false, bool HasTrailingDot = false,
                          ParsedType ObjectType = nullptr,
                          bool IsCtorOrDtorName = false,
+                         bool IsOperatorName = false,
                          bool WantNontrivialTypeSourceInfo = false,
                          bool IsClassTemplateDeductionContext = true,
                          ImplicitTypenameContext AllowImplicitTypename =
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index d6c36616bab47..11477da097f43 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2728,13 +2728,13 @@ Decl 
*Parser::ParseDeclarationAfterDeclaratorAndAttributes(
 
 void Parser::ParseSpecifierQualifierList(
     DeclSpec &DS, ImplicitTypenameContext AllowImplicitTypename,
-    AccessSpecifier AS, DeclSpecContext DSC) {
+    AccessSpecifier AS, DeclSpecContext DSC, ParsedType ObjectType) {
   ParsedTemplateInfo TemplateInfo;
   /// specifier-qualifier-list is a subset of declaration-specifiers.  Just
   /// parse declaration-specifiers and complain about extra stuff.
   /// TODO: diagnose attribute-specifiers and alignment-specifiers.
   ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC, nullptr,
-                             AllowImplicitTypename);
+                             AllowImplicitTypename, ObjectType);
 
   // Validate declspec for type-name.
   unsigned Specs = DS.getParsedSpecifiers();
@@ -3055,6 +3055,8 @@ 
Parser::getDeclSpecContextFromDeclaratorContext(DeclaratorContext Context) {
     return DeclSpecContext::DSC_condition;
   case DeclaratorContext::ConversionId:
     return DeclSpecContext::DSC_conv_operator;
+  case DeclaratorContext::ConversionIdInPostfixExpr:
+    return DeclSpecContext::DSC_conv_operator_in_postfix_expr;
   case DeclaratorContext::CXXNew:
     return DeclSpecContext::DSC_new;
   case DeclaratorContext::Prototype:
@@ -3360,7 +3362,7 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec 
&DS, AccessSpecifier AS,
 void Parser::ParseDeclarationSpecifiers(
     DeclSpec &DS, ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS,
     DeclSpecContext DSContext, LateParsedAttrList *LateAttrs,
-    ImplicitTypenameContext AllowImplicitTypename) {
+    ImplicitTypenameContext AllowImplicitTypename, ParsedType ObjectType) {
   if (DS.getSourceRange().isInvalid()) {
     // Start the range at the current token but make the end of the range
     // invalid.  This will make the entire range invalid unless we successfully
@@ -3369,7 +3371,7 @@ void Parser::ParseDeclarationSpecifiers(
     DS.SetRangeEnd(SourceLocation());
   }
 
-  // If we are in a operator context, convert it back into a type specifier
+  // If we are in an operator context, convert it back into a type specifier
   // context for better error handling later on.
   if (DSContext == DeclSpecContext::DSC_conv_operator) {
     // No implicit typename here.
@@ -3610,7 +3612,10 @@ void Parser::ParseDeclarationSpecifiers(
         ConsumeAnnotationToken(); // The C++ scope.
         assert(Tok.is(tok::annot_template_id) &&
                "ParseOptionalCXXScopeSpecifier not working");
-        AnnotateTemplateIdTokenAsType(SS, AllowImplicitTypename);
+        AnnotateTemplateIdTokenAsType(
+            SS, AllowImplicitTypename,
+            /*IsClassName=*/DSContext ==
+                DeclSpecContext::DSC_conv_operator_in_postfix_expr);
         continue;
       }
 
@@ -3673,6 +3678,8 @@ void Parser::ParseDeclarationSpecifiers(
           *Next.getIdentifierInfo(), Next.getLocation(), getCurScope(), &SS,
           false, false, nullptr,
           /*IsCtorOrDtorName=*/false,
+          /*IsOperatorName=*/DSContext ==
+              DeclSpecContext::DSC_conv_operator_in_postfix_expr,
           /*WantNontrivialTypeSourceInfo=*/true,
           isClassTemplateDeductionContext(DSContext), AllowImplicitTypename);
 
@@ -3796,12 +3803,13 @@ void Parser::ParseDeclarationSpecifiers(
         // - `return type`.
         SuppressAccessChecks SAC(*this, IsTemplateSpecOrInst);
 
-        const bool Success = TryAnnotateCXXScopeToken(EnteringContext);
+        const bool Failed =
+            TryAnnotateCXXScopeToken(EnteringContext, ObjectType);
 
         if (IsTemplateSpecOrInst)
           SAC.done();
 
-        if (Success) {
+        if (Failed) {
           if (IsTemplateSpecOrInst)
             SAC.redelay();
           DS.SetTypeSpecError();
@@ -3846,7 +3854,9 @@ void Parser::ParseDeclarationSpecifiers(
 
       ParsedType TypeRep = Actions.getTypeName(
           *Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), nullptr,
-          false, false, nullptr, false, false,
+          false, false, ObjectType, false,
+          /*IsOperatorName=*/DSContext ==
+              DeclSpecContext::DSC_conv_operator_in_postfix_expr,
           isClassTemplateDeductionContext(DSContext));
 
       // If this is not a typedef name, don't parse it as part of the declspec,
@@ -6648,7 +6658,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
                              /*ObjectHadErrors=*/false,
                              /*EnteringContext=*/true,
                              /*AllowDestructorName=*/true, 
AllowConstructorName,
-                             AllowDeductionGuide, &TemplateKWLoc,
+                             AllowDeductionGuide,
+                             /*ForPostfixExpression=*/false, &TemplateKWLoc,
                              D.getName()) ||
           // Once we're past the identifier, if the scope was bad, mark the
           // whole declarator bad.
@@ -7509,7 +7520,8 @@ void Parser::ParseParameterDeclarationClause(
     ParsedTemplateInfo TemplateInfo;
     ParseDeclarationSpecifiers(DS, TemplateInfo, AS_none,
                                DeclSpecContext::DSC_normal,
-                               /*LateAttrs=*/nullptr, AllowImplicitTypename);
+                               /*LateAttrs=*/nullptr, AllowImplicitTypename,
+                               /*ObjectType=*/nullptr);
 
     DS.takeAttributesFrom(ArgDeclSpecAttrs);
 
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 2cf33a856c4f4..21686bb5a97dd 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -604,7 +604,8 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context,
             /*AllowDestructorName=*/true,
             /*AllowConstructorName=*/
             !(Tok.is(tok::identifier) && NextToken().is(tok::equal)),
-            /*AllowDeductionGuide=*/false, nullptr, D.Name))
+            /*AllowDeductionGuide=*/false, /*ForPostfixExpression=*/false,
+            nullptr, D.Name))
       return true;
   }
 
@@ -641,7 +642,7 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration(
     }
     CXXScopeSpec SS;
     if (ParseOptionalCXXScopeSpecifier(SS, /*ParsedType=*/nullptr,
-                                       /*ObectHasErrors=*/false,
+                                       /*ObjectHasErrors=*/false,
                                        /*EnteringConttext=*/false,
                                        /*MayBePseudoDestructor=*/nullptr,
                                        /*IsTypename=*/true,
@@ -670,6 +671,7 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration(
           *IdentInfo, IdentLoc, getCurScope(), &SS, /*isClassName=*/true,
           /*HasTrailingDot=*/false,
           /*ObjectType=*/nullptr, /*IsCtorOrDtorName=*/false,
+          /*IsOperatorName=*/false,
           /*WantNontrivialTypeSourceInfo=*/true);
 
       UED = Actions.ActOnUsingEnumDeclaration(
@@ -1399,6 +1401,7 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation 
&BaseLoc,
   ParsedType Type = Actions.getTypeName(
       *Id, IdLoc, getCurScope(), &SS, /*isClassName=*/true, false, nullptr,
       /*IsCtorOrDtorName=*/false,
+      /*IsOperatorName=*/false,
       /*WantNontrivialTypeSourceInfo=*/true,
       /*IsClassTemplateDeductionContext=*/false, ImplicitTypenameContext::No,
       &CorrectedII);
@@ -2750,7 +2753,8 @@ Parser::DeclGroupPtrTy 
Parser::ParseCXXClassMemberDeclaration(
       UnqualifiedId Name;
       if (ParseUnqualifiedId(SS, /*ObjectType=*/nullptr,
                              /*ObjectHadErrors=*/false, false, true, true,
-                             false, &TemplateKWLoc, Name)) {
+                             false, /*ForPostfixExpression=*/false,
+                             &TemplateKWLoc, Name)) {
         SkipUntil(tok::semi);
         return nullptr;
       }
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 951a157305ddc..a18d0ac262de3 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -2049,7 +2049,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
                      /*AllowDestructorName=*/true,
                      /*AllowConstructorName=*/
                      getLangOpts().MicrosoftExt && SS.isNotEmpty(),
-                     /*AllowDeductionGuide=*/false, &TemplateKWLoc, Name)) {
+                     /*AllowDeductionGuide=*/false,
+                     /*ForPostfixExpression=*/true, &TemplateKWLoc, Name)) {
         (void)Actions.CorrectDelayedTyposInExpr(LHS);
         LHS = ExprError();
       }
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index d95260829e4a0..d74f51b2fb7dc 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -283,8 +283,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
         // because a simple-template-id cannot start with 'operator', but
         // go ahead and parse it anyway for consistency with the case where
         // we already annotated the template-id.
-        if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType,
-                                       TemplateName)) {
+        if (ParseUnqualifiedIdOperator(SS, EnteringContext,
+                                       /*ForPostfixExpression=*/false,
+                                       ObjectType, TemplateName)) {
           TPA.Commit();
           break;
         }
@@ -608,7 +609,8 @@ ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS,
                            /*EnteringContext=*/false,
                            /*AllowDestructorName=*/false,
                            /*AllowConstructorName=*/false,
-                           /*AllowDeductionGuide=*/false, &TemplateKWLoc, 
Name))
+                           /*AllowDeductionGuide=*/false,
+                           /*ForPostfixExpression=*/true, &TemplateKWLoc, 
Name))
       return ExprError();
 
     // This is only the direct operand of an & operator if it is not
@@ -2212,9 +2214,11 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
   DS.Finish(Actions, Policy);
 }
 
-bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS, DeclaratorContext Context) 
{
+bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS, DeclaratorContext Context,
+                                      ParsedType ObjectType) {
   ParseSpecifierQualifierList(DS, AS_none,
-                              
getDeclSpecContextFromDeclaratorContext(Context));
+                              getDeclSpecContextFromDeclaratorContext(Context),
+                              ObjectType);
   DS.Finish(Actions, Actions.getASTContext().getPrintingPolicy());
   return false;
 }
@@ -2375,6 +2379,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(
 }
 
 bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
+                                        bool ForPostfixExpression,
                                         ParsedType ObjectType,
                                         UnqualifiedId &Result) {
   assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword");
@@ -2555,8 +2560,18 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec 
&SS, bool EnteringContext,
 
   // Parse the type-specifier-seq.
   DeclSpec DS(AttrFactory);
+  if (ForPostfixExpression && !SS.isEmpty() && Tok.is(tok::identifier)) {
+    if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
+                                       /*ObjectHasErrors=*/false,
+                                       EnteringContext))
+      return true;
+    AnnotateScopeToken(SS, /*IsNewAnnotation=*/true);
+  }
   if (ParseCXXTypeSpecifierSeq(
-          DS, DeclaratorContext::ConversionId)) // FIXME: ObjectType?
+          DS,
+          ForPostfixExpression ? DeclaratorContext::ConversionIdInPostfixExpr
+                               : DeclaratorContext::ConversionId,
+          ObjectType))
     return true;
 
   // Parse the conversion-declarator, which is merely a sequence of
@@ -2576,13 +2591,11 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec 
&SS, bool EnteringContext,
   return false;
 }
 
-bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType,
-                                bool ObjectHadErrors, bool EnteringContext,
-                                bool AllowDestructorName,
-                                bool AllowConstructorName,
-                                bool AllowDeductionGuide,
-                                SourceLocation *TemplateKWLoc,
-                                UnqualifiedId &Result) {
+bool Parser::ParseUnqualifiedId(
+    CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHadErrors,
+    bool EnteringContext, bool AllowDestructorName, bool AllowConstructorName,
+    bool AllowDeductionGuide, bool ForPostfixExpression,
+    SourceLocation *TemplateKWLoc, UnqualifiedId &Result) {
   if (TemplateKWLoc)
     *TemplateKWLoc = SourceLocation();
 
@@ -2723,7 +2736,8 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, 
ParsedType ObjectType,
   //   operator-function-id
   //   conversion-function-id
   if (Tok.is(tok::kw_operator)) {
-    if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, Result))
+    if (ParseUnqualifiedIdOperator(SS, EnteringContext, ForPostfixExpression,
+                                   ObjectType, Result))
       return true;
 
     // If we have an operator-function-id or a literal-operator-id and the next
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index e41e5ba8596b9..6a149131b046e 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -2997,7 +2997,7 @@ bool Parser::ParseOpenMPSimpleVarList(
                 StopBeforeMatch);
     } else if (ParseUnqualifiedId(SS, /*ObjectType=*/nullptr,
                                   /*ObjectHadErrors=*/false, false, false,
-                                  false, false, nullptr, Name)) {
+                                  false, false, false, nullptr, Name)) {
       IsCorrect = false;
       SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
                 StopBeforeMatch);
@@ -4052,12 +4052,14 @@ static bool ParseReductionId(Parser &P, CXXScopeSpec 
&ReductionIdScopeSpec,
       return false;
     }
   }
-  return P.ParseUnqualifiedId(
-      ReductionIdScopeSpec, /*ObjectType=*/nullptr,
-      /*ObjectHadErrors=*/false, /*EnteringContext*/ false,
-      /*AllowDestructorName*/ false,
-      /*AllowConstructorName*/ false,
-      /*AllowDeductionGuide*/ false, nullptr, ReductionId);
+  return P.ParseUnqualifiedId(ReductionIdScopeSpec, /*ObjectType=*/nullptr,
+                              /*ObjectHadErrors=*/false,
+                              /*EnteringContext*/ false,
+                              /*AllowDestructorName*/ false,
+                              /*AllowConstructorName*/ false,
+                              /*AllowDeductionGuide*/ false,
+                              /*ForPostfixExpression=*/false, nullptr,
+                              ReductionId);
 }
 
 /// Checks if the token is a valid map-type-modifier.
diff --git a/clang/lib/Parse/ParseStmtAsm.cpp b/clang/lib/Parse/ParseStmtAsm.cpp
index f2417479a0e78..ac240138bc492 100644
--- a/clang/lib/Parse/ParseStmtAsm.cpp
+++ b/clang/lib/Parse/ParseStmtAsm.cpp
@@ -237,7 +237,8 @@ ExprResult 
Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
                            /*EnteringContext=*/false,
                            /*AllowDestructorName=*/false,
                            /*AllowConstructorName=*/false,
-                           /*AllowDeductionGuide=*/false, &TemplateKWLoc, Id);
+                           /*AllowDeductionGuide=*/false,
+                           /*ForPostfixExpression=*/false, &TemplateKWLoc, Id);
     // Perform the lookup.
     Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id,
                                                IsUnevaluatedContext);
diff --git a/clang/lib/Parse/ParseTemplate.cpp 
b/clang/lib/Parse/ParseTemplate.cpp
index d3c9ca029c9aa..dfd8e5d835de1 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -266,6 +266,7 @@ Parser::ParseConceptDefinition(const ParsedTemplateInfo 
&TemplateInfo,
                          /*AllowDestructorName=*/false,
                          /*AllowConstructorName=*/false,
                          /*AllowDeductionGuide=*/false,
+                         /*ForPostfixExpression=*/false,
                          /*TemplateKWLoc=*/nullptr, Result)) {
     SkipUntil(tok::semi);
     return nullptr;
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index db65c05cc114a..39bd83eccd02d 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -2019,6 +2019,7 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(
             *Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), &SS,
             false, NextToken().is(tok::period), nullptr,
             /*IsCtorOrDtorName=*/false,
+            /*IsOperatorName=*/false,
             /*NonTrivialTypeSourceInfo=*/true,
             /*IsClassTemplateDeductionContext=*/true, AllowImplicitTypename)) {
       SourceLocation BeginLoc = Tok.getLocation();
@@ -2126,13 +2127,14 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(
   return false;
 }
 
-bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) {
+bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext,
+                                      ParsedType ObjectType) {
   assert(getLangOpts().CPlusPlus &&
          "Call sites of this function should be guarded by checking for C++");
   assert(MightBeCXXScopeToken() && "Cannot be a type or scope token!");
 
   CXXScopeSpec SS;
-  if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
+  if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/ObjectType,
                                      /*ObjectHasErrors=*/false,
                                      EnteringContext))
     return true;
@@ -2262,7 +2264,8 @@ bool 
Parser::ParseMicrosoftIfExistsCondition(IfExistsCondition& Result) {
                          /*ObjectHadErrors=*/false, /*EnteringContext*/ false,
                          /*AllowDestructorName*/ true,
                          /*AllowConstructorName*/ true,
-                         /*AllowDeductionGuide*/ false, &TemplateKWLoc,
+                         /*AllowDeductionGuide*/ false,
+                         /*ForPostfixExpression=*/false, &TemplateKWLoc,
                          Result.Name)) {
     T.skipToEnd();
     return true;
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 86b871396ec90..089a660c89179 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -311,12 +311,13 @@ static ParsedType buildNamedType(Sema &S, const 
CXXScopeSpec *SS, QualType T,
 ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
                              Scope *S, CXXScopeSpec *SS, bool isClassName,
                              bool HasTrailingDot, ParsedType ObjectTypePtr,
-                             bool IsCtorOrDtorName,
+                             bool IsCtorOrDtorName, bool IsOperatorName,
                              bool WantNontrivialTypeSourceInfo,
                              bool IsClassTemplateDeductionContext,
                              ImplicitTypenameContext AllowImplicitTypename,
                              IdentifierInfo **CorrectedII) {
-  bool IsImplicitTypename = !isClassName && !IsCtorOrDtorName;
+  bool IsImplicitTypename =
+      !isClassName && !IsCtorOrDtorName && !IsOperatorName;
   // FIXME: Consider allowing this outside C++1z mode as an extension.
   bool AllowDeducedTemplate = IsClassTemplateDeductionContext &&
                               getLangOpts().CPlusPlus17 && IsImplicitTypename 
&&
@@ -368,6 +369,9 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, 
SourceLocation NameLoc,
                                : ElaboratedTypeKeyword::None,
             SourceLocation(), QualifierLoc, II, NameLoc);
         return ParsedType::make(T);
+        // return CreateParsedType(
+        //     T, Context.getTrivialTypeSourceInfo(T,
+        //     QualifierLoc.getBeginLoc()));
       }
 
       return nullptr;
@@ -393,7 +397,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, 
SourceLocation NameLoc,
     // nested-name-specifier.
     LookupQualifiedName(Result, LookupCtx);
 
-    if (ObjectTypePtr && Result.empty()) {
+    if ((ObjectTypePtr || IsOperatorName) && Result.empty()) {
       // C++ [basic.lookup.classref]p3:
       //   If the unqualified-id is ~type-name, the type-name is looked up
       //   in the context of the entire postfix-expression. If the type T of
@@ -443,11 +447,10 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, 
SourceLocation NameLoc,
           !(getLangOpts().CPlusPlus && NewSSPtr &&
             isTemplateName(S, *NewSSPtr, false, TemplateName, nullptr, false,
                            Template, MemberOfUnknownSpecialization))) {
-        ParsedType Ty = getTypeName(*NewII, NameLoc, S, NewSSPtr,
-                                    isClassName, HasTrailingDot, ObjectTypePtr,
-                                    IsCtorOrDtorName,
-                                    WantNontrivialTypeSourceInfo,
-                                    IsClassTemplateDeductionContext);
+        ParsedType Ty = getTypeName(
+            *NewII, NameLoc, S, NewSSPtr, isClassName, HasTrailingDot,
+            ObjectTypePtr, IsCtorOrDtorName, IsOperatorName,
+            WantNontrivialTypeSourceInfo, IsClassTemplateDeductionContext);
         if (Ty) {
           diagnoseTypo(Correction,
                        PDiag(diag::err_unknown_type_or_class_name_suggest)
@@ -755,6 +758,7 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
           getTypeName(*Corrected.getCorrectionAsIdentifierInfo(), IILoc, S,
                       tmpSS.isSet() ? &tmpSS : SS, false, false, nullptr,
                       /*IsCtorOrDtorName=*/false,
+                      /*IsOperatorName=*/false,
                       /*WantNontrivialTypeSourceInfo=*/true);
     }
     return;
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 338b81fe89748..06807a7a1f6e5 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -3310,6 +3310,7 @@ static QualType 
GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
       IsDeducedReturnType = true;
       break;
     case DeclaratorContext::ConversionId:
+    case DeclaratorContext::ConversionIdInPostfixExpr:
       if (!SemaRef.getLangOpts().CPlusPlus14 || !IsCXXAutoType)
         Error = 14; // conversion-type-id
       IsDeducedReturnType = true;
@@ -3432,6 +3433,7 @@ static QualType 
GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
     case DeclaratorContext::TypeName:
     case DeclaratorContext::FunctionalCast:
     case DeclaratorContext::ConversionId:
+    case DeclaratorContext::ConversionIdInPostfixExpr:
     case DeclaratorContext::TemplateParam:
     case DeclaratorContext::CXXNew:
     case DeclaratorContext::CXXCatch:
@@ -4488,6 +4490,7 @@ static TypeSourceInfo 
*GetFullTypeForDeclarator(TypeProcessingState &state,
     }
 
     case DeclaratorContext::ConversionId:
+    case DeclaratorContext::ConversionIdInPostfixExpr:
       complainAboutMissingNullability = CAMN_Yes;
       break;
 
@@ -5663,6 +5666,7 @@ static TypeSourceInfo 
*GetFullTypeForDeclarator(TypeProcessingState &state,
     case DeclaratorContext::BlockLiteral:
     case DeclaratorContext::LambdaExpr:
     case DeclaratorContext::ConversionId:
+    case DeclaratorContext::ConversionIdInPostfixExpr:
     case DeclaratorContext::TrailingReturn:
     case DeclaratorContext::TrailingReturnVar:
     case DeclaratorContext::TemplateArg:
diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p5.cpp 
b/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p5.cpp
new file mode 100644
index 0000000000000..683d2091a3bfd
--- /dev/null
+++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p5.cpp
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -fsyntax-only -Wno-unused-result -verify=expected,pre-cxx20 
%s
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -Wno-unused-result 
-verify=expected,since-cxx20 %s
+
+// expected-no-diagnostics
+
+namespace GH28181 {
+
+struct S {
+  using T = int;
+  operator T() { return 42; }
+};
+
+void foo() {
+  S{}.operator T();
+}
+
+}
+
+namespace GH94052 {
+
+namespace a {
+template <typename> class b {
+  public:
+  typedef int string_type;
+  operator string_type();
+};
+} // namespace a
+template <class> void c() {
+  (void)&a::b<char>::operator string_type;
+}
+
+}
+
+namespace CXXScopeSpec {
+
+struct S {
+  template <class U>
+  struct T {
+
+  };
+
+  template <class U>
+  operator T<U>() { return 42; }
+};
+
+template <class U>
+void foo() {
+  &S::operator T<U>();
+  S().operator T<U>();
+}
+
+}
diff --git a/clang/test/CXX/drs/cwg11xx.cpp b/clang/test/CXX/drs/cwg11xx.cpp
index 03612b6d87645..0867a26e544b5 100644
--- a/clang/test/CXX/drs/cwg11xx.cpp
+++ b/clang/test/CXX/drs/cwg11xx.cpp
@@ -80,9 +80,7 @@ struct B : A {
   operator T();
 } b;
 void foo() {
-  b.A::operator T(); // FIXME: qualified lookup should find T in A.
-  // expected-error@-1 {{unknown type name 'T'}}
-  //   expected-note@#cwg1111-A-T {{'A::T' declared here}}
+  b.A::operator T();
 }
 } // namespace example4
 
diff --git a/clang/test/CXX/temp/temp.res/p4.cpp 
b/clang/test/CXX/temp/temp.res/p4.cpp
index 9dbdd235e925d..5cf2aef91c33d 100644
--- a/clang/test/CXX/temp/temp.res/p4.cpp
+++ b/clang/test/CXX/temp/temp.res/p4.cpp
@@ -158,7 +158,7 @@ template int Test<X>;
 template<typename T> struct A {
   enum E : T::type {}; // expected-error{{missing 'typename'}}
   operator T::type() {} // expected-error{{missing 'typename'}}
-  void f() { this->operator T::type(); } // expected-error{{missing 
'typename'}}
+  void f() { this->operator T::type(); }
 };
 
 template<typename T>
diff --git a/clang/unittests/Tooling/TestVisitor.h 
b/clang/unittests/Tooling/TestVisitor.h
index fdf57a946a6e2..228214d33e834 100644
--- a/clang/unittests/Tooling/TestVisitor.h
+++ b/clang/unittests/Tooling/TestVisitor.h
@@ -253,8 +253,8 @@ class ExpectedLocationVisitorHelper {
 ///
 /// Visits template instantiations and implicit code by default.
 ///
-/// For post-order traversal etc. use CTRPTestVisitor from
-/// CTRPTestVisitor.h instead.
+/// For post-order traversal etc. use CRTPTestVisitor from
+/// CRTPTestVisitor.h instead.
 class TestVisitor : public DynamicRecursiveASTVisitor,
                     public detail::TestVisitorHelper {
 public:
@@ -273,8 +273,8 @@ class TestVisitor : public DynamicRecursiveASTVisitor,
 /// and allows simple creation of test visitors running matches on only a small
 /// subset of the Visit* methods.
 ///
-/// For post-order traversal etc. use CTRPExpectedLocationVisitor from
-/// CTRPTestVisitor.h instead.
+/// For post-order traversal etc. use CRTPExpectedLocationVisitor from
+/// CRTPTestVisitor.h instead.
 class ExpectedLocationVisitor : public TestVisitor,
                                 public detail::ExpectedLocationVisitorHelper {
   ASTContext *getASTContext() override { return Context; }

>From ae8be50f312bfef100d74ca572a01ea20fc82eb0 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7...@gmail.com>
Date: Fri, 6 Jun 2025 00:43:08 +0800
Subject: [PATCH 2/2] Add the libcxx regression

---
 .../basic.lookup/basic.lookup.unqual/p5.cpp   | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p5.cpp 
b/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p5.cpp
index 683d2091a3bfd..0277e6a8001a9 100644
--- a/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p5.cpp
+++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p5.cpp
@@ -50,3 +50,22 @@ void foo() {
 }
 
 }
+
+namespace Regression {
+
+namespace ns {
+template <class T>
+struct Bar {};
+}
+
+template <class T>
+struct S {
+  operator T();
+};
+
+template <class T>
+void foo(T t) {
+  t.operator ns::Bar<T>();
+}
+
+}

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

Reply via email to