https://github.com/sdkrystian created https://github.com/llvm/llvm-project/pull/98167
The following code causes [this assert](https://github.com/llvm/llvm-project/blob/main/clang/lib/Sema/SemaExprMember.cpp#L981) to fail: ```cpp 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 to be 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. >From 85efbad994685903e01726b97ba0ab82172bae63 Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Tue, 9 Jul 2024 11:03:14 -0400 Subject: [PATCH] [Clang][Sema] Handle class member access expressions with valid nested-name-specifiers that become invalid after lookup --- clang/lib/Sema/SemaExprMember.cpp | 16 ++++++---------- .../basic.lookup.qual.general/p2.cpp | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 10 deletions(-) create mode 100644 clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p2.cpp diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index b7ea24790d361..daa9a4948f66c 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,10 @@ ExprResult Sema::BuildMemberReferenceExpr( BaseType = Base->getType(); } + // BuildMemberReferenceExpr expects a valid nested-name-specifier, if any. + if (SS.isInvalid()) + return ExprError(); + return BuildMemberReferenceExpr(Base, BaseType, OpLoc, IsArrow, SS, TemplateKWLoc, FirstQualifierInScope, R, TemplateArgs, S, @@ -1745,14 +1746,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