Skip to content

Commit 9e1f1cf

Browse files
authored
[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`).
1 parent 10f3f06 commit 9e1f1cf

File tree

2 files changed

+23
-10
lines changed

2 files changed

+23
-10
lines changed

clang/lib/Sema/SemaExprMember.cpp

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -789,9 +789,6 @@ ExprResult Sema::BuildMemberReferenceExpr(
789789
ActOnMemberAccessExtraArgs *ExtraArgs) {
790790
LookupResult R(*this, NameInfo, LookupMemberName);
791791

792-
if (SS.isInvalid())
793-
return ExprError();
794-
795792
// Implicit member accesses.
796793
if (!Base) {
797794
TypoExpr *TE = nullptr;
@@ -826,6 +823,11 @@ ExprResult Sema::BuildMemberReferenceExpr(
826823
BaseType = Base->getType();
827824
}
828825

826+
// BuildMemberReferenceExpr expects the nested-name-specifier, if any, to be
827+
// valid.
828+
if (SS.isInvalid())
829+
return ExprError();
830+
829831
return BuildMemberReferenceExpr(Base, BaseType,
830832
OpLoc, IsArrow, SS, TemplateKWLoc,
831833
FirstQualifierInScope, R, TemplateArgs, S,
@@ -1745,14 +1747,9 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
17451747

17461748
ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
17471749
SourceLocation OpLoc,
1748-
tok::TokenKind OpKind,
1749-
CXXScopeSpec &SS,
1750+
tok::TokenKind OpKind, CXXScopeSpec &SS,
17501751
SourceLocation TemplateKWLoc,
1751-
UnqualifiedId &Id,
1752-
Decl *ObjCImpDecl) {
1753-
if (SS.isSet() && SS.isInvalid())
1754-
return ExprError();
1755-
1752+
UnqualifiedId &Id, Decl *ObjCImpDecl) {
17561753
// Warn about the explicit constructor calls Microsoft extension.
17571754
if (getLangOpts().MicrosoftExt &&
17581755
Id.getKind() == UnqualifiedIdKind::IK_ConstructorName)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %clang_cc1 -verify -Wno-unused %s
2+
3+
struct A {
4+
int y;
5+
};
6+
7+
struct B; // expected-note 4{{forward declaration of 'B'}}
8+
9+
void f(A *a, B *b) {
10+
a->B::x; // expected-error {{incomplete type 'B' named in nested name specifier}}
11+
a->A::x; // expected-error {{no member named 'x' in 'A'}}
12+
a->A::y;
13+
b->B::x; // expected-error {{member access into incomplete type 'B'}}
14+
b->A::x; // expected-error {{member access into incomplete type 'B'}}
15+
b->A::y; // expected-error {{member access into incomplete type 'B'}}
16+
}

0 commit comments

Comments
 (0)