Author: Krystian Stasiowski Date: 2024-07-09T16:40:53-04:00 New Revision: 9e1f1cfa59c4513798de5c326d77e1e5912b1634
URL: https://github.com/llvm/llvm-project/commit/9e1f1cfa59c4513798de5c326d77e1e5912b1634 DIFF: https://github.com/llvm/llvm-project/commit/9e1f1cfa59c4513798de5c326d77e1e5912b1634.diff LOG: [Clang][Sema] Handle class member access expressions with valid nested-name-specifiers that become invalid after lookup (#98167) The following code causes an assert in `SemaExprMember.cpp` on line 981 to fail: ``` struct A { }; struct B; void f(A *x) { x->B::y; // crash here } ``` This happens because we only return early from `BuildMemberReferenceExpr` when the `CXXScopeSpecifier` is invalid _before_ the lookup is performed. Since the lookup may invalidate the `CXXScopeSpecifier` (e.g. if the _nested-name-specifier_ is incomplete), this results in the second `BuildMemberReferenceExpr` overload being called with an invalid `CXXScopeSpecifier`, which causes the assert to fail. This patch moves the early return for invalid `CXXScopeSpecifiers` to occur _after_ lookup is performed. This fixes #92972. I also removed the `if (SS.isSet() && SS.isInvalid())` check in `ActOnMemberAccessExpr` because the condition can never be true (`isSet` returns `getScopeRep() != nullptr` and `isInvalid` returns `Range.isValid() && getScopeRep() == nullptr`). Added: clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p2.cpp Modified: clang/lib/Sema/SemaExprMember.cpp Removed: ################################################################################ diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index b7ea24790d361..2070f3b7bb3a2 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -789,9 +789,6 @@ ExprResult Sema::BuildMemberReferenceExpr( ActOnMemberAccessExtraArgs *ExtraArgs) { LookupResult R(*this, NameInfo, LookupMemberName); - if (SS.isInvalid()) - return ExprError(); - // Implicit member accesses. if (!Base) { TypoExpr *TE = nullptr; @@ -826,6 +823,11 @@ ExprResult Sema::BuildMemberReferenceExpr( BaseType = Base->getType(); } + // BuildMemberReferenceExpr expects the nested-name-specifier, if any, to be + // valid. + if (SS.isInvalid()) + return ExprError(); + return BuildMemberReferenceExpr(Base, BaseType, OpLoc, IsArrow, SS, TemplateKWLoc, FirstQualifierInScope, R, TemplateArgs, S, @@ -1745,14 +1747,9 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, SourceLocation OpLoc, - tok::TokenKind OpKind, - CXXScopeSpec &SS, + tok::TokenKind OpKind, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, - UnqualifiedId &Id, - Decl *ObjCImpDecl) { - if (SS.isSet() && SS.isInvalid()) - return ExprError(); - + UnqualifiedId &Id, Decl *ObjCImpDecl) { // Warn about the explicit constructor calls Microsoft extension. if (getLangOpts().MicrosoftExt && Id.getKind() == UnqualifiedIdKind::IK_ConstructorName) diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p2.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p2.cpp new file mode 100644 index 0000000000000..ebdae971a929e --- /dev/null +++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p2.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -verify -Wno-unused %s + +struct A { + int y; +}; + +struct B; // expected-note 4{{forward declaration of 'B'}} + +void f(A *a, B *b) { + a->B::x; // expected-error {{incomplete type 'B' named in nested name specifier}} + a->A::x; // expected-error {{no member named 'x' in 'A'}} + a->A::y; + b->B::x; // expected-error {{member access into incomplete type 'B'}} + b->A::x; // expected-error {{member access into incomplete type 'B'}} + b->A::y; // expected-error {{member access into incomplete type 'B'}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits