Skip to content

Commit 4527085

Browse files
authored
[clang] diagnose invalid member pointer class on instantiation (#132516)
1 parent b9180c5 commit 4527085

File tree

6 files changed

+44
-32
lines changed

6 files changed

+44
-32
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6976,7 +6976,7 @@ def err_illegal_decl_mempointer_to_reference : Error<
69766976
def err_illegal_decl_mempointer_to_void : Error<
69776977
"'%0' declared as a member pointer to void">;
69786978
def err_illegal_decl_mempointer_in_nonclass
6979-
: Error<"'%0' does not point into a class">;
6979+
: Error<"%0 does not point into a class">;
69806980
def err_reference_to_void : Error<"cannot form a reference to 'void'">;
69816981
def err_nonfunction_block_type : Error<
69826982
"block pointer to non-function type is invalid">;

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14885,7 +14885,7 @@ class Sema final : public SemaBase {
1488514885
///
1488614886
/// \returns a member pointer type, if successful, or a NULL type if there was
1488714887
/// an error.
14888-
QualType BuildMemberPointerType(QualType T, NestedNameSpecifier *Qualifier,
14888+
QualType BuildMemberPointerType(QualType T, const CXXScopeSpec &SS,
1488914889
CXXRecordDecl *Cls, SourceLocation Loc,
1489014890
DeclarationName Entity);
1489114891

clang/lib/Sema/SemaType.cpp

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2685,10 +2685,23 @@ QualType Sema::BuildFunctionType(QualType T,
26852685
return Context.getFunctionType(T, ParamTypes, EPI);
26862686
}
26872687

2688-
QualType Sema::BuildMemberPointerType(QualType T,
2689-
NestedNameSpecifier *Qualifier,
2688+
QualType Sema::BuildMemberPointerType(QualType T, const CXXScopeSpec &SS,
26902689
CXXRecordDecl *Cls, SourceLocation Loc,
26912690
DeclarationName Entity) {
2691+
if (!Cls && !isDependentScopeSpecifier(SS)) {
2692+
Cls = dyn_cast_or_null<CXXRecordDecl>(computeDeclContext(SS));
2693+
if (!Cls) {
2694+
auto D =
2695+
Diag(SS.getBeginLoc(), diag::err_illegal_decl_mempointer_in_nonclass)
2696+
<< SS.getRange();
2697+
if (const IdentifierInfo *II = Entity.getAsIdentifierInfo())
2698+
D << II;
2699+
else
2700+
D << "member pointer";
2701+
return QualType();
2702+
}
2703+
}
2704+
26922705
// Verify that we're not building a pointer to pointer to function with
26932706
// exception specification.
26942707
if (CheckDistantExceptionSpec(T)) {
@@ -2730,7 +2743,7 @@ QualType Sema::BuildMemberPointerType(QualType T,
27302743
if (T->isFunctionType())
27312744
adjustMemberFunctionCC(T, /*HasThisPointer=*/true, IsCtorOrDtor, Loc);
27322745

2733-
return Context.getMemberPointerType(T, Qualifier, Cls);
2746+
return Context.getMemberPointerType(T, SS.getScopeRep(), Cls);
27342747
}
27352748

27362749
QualType Sema::BuildBlockPointerType(QualType T,
@@ -5344,20 +5357,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
53445357
// Avoid emitting extra errors if we already errored on the scope.
53455358
D.setInvalidType(true);
53465359
AreDeclaratorChunksValid = false;
5347-
} else if (auto *RD =
5348-
dyn_cast_or_null<CXXRecordDecl>(S.computeDeclContext(SS));
5349-
RD || S.isDependentScopeSpecifier(SS)) {
5350-
T = S.BuildMemberPointerType(T, SS.getScopeRep(), RD, DeclType.Loc,
5351-
D.getIdentifier());
53525360
} else {
5353-
S.Diag(DeclType.Mem.Scope().getBeginLoc(),
5354-
diag::err_illegal_decl_mempointer_in_nonclass)
5355-
<< (D.getIdentifier() ? D.getIdentifier()->getName() : "type name")
5356-
<< DeclType.Mem.Scope().getRange();
5357-
D.setInvalidType(true);
5358-
AreDeclaratorChunksValid = false;
5359-
// FIXME: Maybe we could model these as as a MemberPointerType with a
5360-
// non-dependent, non-class qualifier anyway.
5361+
T = S.BuildMemberPointerType(T, SS, /*Cls=*/nullptr, DeclType.Loc,
5362+
D.getIdentifier());
53615363
}
53625364

53635365
if (T.isNull()) {
@@ -9255,10 +9257,10 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
92559257
// "Can't ask whether a dependent type is complete");
92569258

92579259
if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>()) {
9258-
if (!MPTy->getQualifier()->isDependent()) {
9259-
QualType T = Context.getTypeDeclType(MPTy->getMostRecentCXXRecordDecl());
9260-
if (getLangOpts().CompleteMemberPointers &&
9261-
!MPTy->getMostRecentCXXRecordDecl()->isBeingDefined() &&
9260+
if (CXXRecordDecl *RD = MPTy->getMostRecentCXXRecordDecl();
9261+
RD && !RD->isDependentType()) {
9262+
QualType T = Context.getTypeDeclType(RD);
9263+
if (getLangOpts().CompleteMemberPointers && !RD->isBeingDefined() &&
92629264
RequireCompleteType(Loc, T, Kind, diag::err_memptr_incomplete))
92639265
return true;
92649266

clang/lib/Sema/TreeTransform.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -864,8 +864,8 @@ class TreeTransform {
864864
/// By default, performs semantic analysis when building the member pointer
865865
/// type. Subclasses may override this routine to provide different behavior.
866866
QualType RebuildMemberPointerType(QualType PointeeType,
867-
NestedNameSpecifier *Qualifier,
868-
CXXRecordDecl *Cls, SourceLocation Sigil);
867+
const CXXScopeSpec &SS, CXXRecordDecl *Cls,
868+
SourceLocation Sigil);
869869

870870
QualType RebuildObjCTypeParamType(const ObjCTypeParamDecl *Decl,
871871
SourceLocation ProtocolLAngleLoc,
@@ -5631,9 +5631,10 @@ TreeTransform<Derived>::TransformMemberPointerType(TypeLocBuilder &TLB,
56315631
NewQualifierLoc.getNestedNameSpecifier() !=
56325632
OldQualifierLoc.getNestedNameSpecifier() ||
56335633
NewCls != OldCls) {
5634-
Result = getDerived().RebuildMemberPointerType(
5635-
PointeeType, NewQualifierLoc.getNestedNameSpecifier(), NewCls,
5636-
TL.getStarLoc());
5634+
CXXScopeSpec SS;
5635+
SS.Adopt(NewQualifierLoc);
5636+
Result = getDerived().RebuildMemberPointerType(PointeeType, SS, NewCls,
5637+
TL.getStarLoc());
56375638
if (Result.isNull())
56385639
return QualType();
56395640
}
@@ -17044,9 +17045,9 @@ TreeTransform<Derived>::RebuildReferenceType(QualType ReferentType,
1704417045

1704517046
template <typename Derived>
1704617047
QualType TreeTransform<Derived>::RebuildMemberPointerType(
17047-
QualType PointeeType, NestedNameSpecifier *Qualifier, CXXRecordDecl *Cls,
17048+
QualType PointeeType, const CXXScopeSpec &SS, CXXRecordDecl *Cls,
1704817049
SourceLocation Sigil) {
17049-
return SemaRef.BuildMemberPointerType(PointeeType, Qualifier, Cls, Sigil,
17050+
return SemaRef.BuildMemberPointerType(PointeeType, SS, Cls, Sigil,
1705017051
getDerived().getBaseEntity());
1705117052
}
1705217053

clang/test/SemaCXX/member-pointer.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,3 +333,14 @@ namespace test9 {
333333
struct C { int BAR::*mp; };
334334
// expected-error@-1 {{'BAR' is not a class, namespace, or enumeration}}
335335
} // namespace test9
336+
337+
namespace GH132494 {
338+
enum E {};
339+
340+
void f(int E::*); // expected-error {{member pointer does not point into a class}}
341+
342+
template <class T> struct A {
343+
int T::*foo; // expected-error {{'foo' does not point into a class}}
344+
};
345+
template struct A<E>; // expected-note {{requested here}}
346+
} // namespace GH132494

libc/test/src/__support/CPP/type_traits_test.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -334,9 +334,7 @@ TEST(LlvmLibcTypeTraitsTest, is_class) {
334334
// Neither other types.
335335
EXPECT_FALSE((is_class_v<Union>));
336336
EXPECT_FALSE((is_class_v<int>));
337-
// TODO: Re-enable the test after
338-
// https://github.com/llvm/llvm-project/issues/132494 is fixed.
339-
// EXPECT_FALSE((is_class_v<EnumClass>));
337+
EXPECT_FALSE((is_class_v<EnumClass>));
340338
}
341339

342340
TYPED_TEST(LlvmLibcTypeTraitsTest, is_const, UnqualObjectTypes) {

0 commit comments

Comments
 (0)