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