[clang] diagnose invalid member pointer class on instantiation (#132516)

This commit is contained in:
Matheus Izvekov 2025-03-22 02:05:40 -03:00 committed by GitHub
parent b9180c5cc6
commit 4527085319
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 44 additions and 32 deletions

View File

@ -6976,7 +6976,7 @@ def err_illegal_decl_mempointer_to_reference : Error<
def err_illegal_decl_mempointer_to_void : Error<
"'%0' declared as a member pointer to void">;
def err_illegal_decl_mempointer_in_nonclass
: Error<"'%0' does not point into a class">;
: Error<"%0 does not point into a class">;
def err_reference_to_void : Error<"cannot form a reference to 'void'">;
def err_nonfunction_block_type : Error<
"block pointer to non-function type is invalid">;

View File

@ -14885,7 +14885,7 @@ public:
///
/// \returns a member pointer type, if successful, or a NULL type if there was
/// an error.
QualType BuildMemberPointerType(QualType T, NestedNameSpecifier *Qualifier,
QualType BuildMemberPointerType(QualType T, const CXXScopeSpec &SS,
CXXRecordDecl *Cls, SourceLocation Loc,
DeclarationName Entity);

View File

@ -2685,10 +2685,23 @@ QualType Sema::BuildFunctionType(QualType T,
return Context.getFunctionType(T, ParamTypes, EPI);
}
QualType Sema::BuildMemberPointerType(QualType T,
NestedNameSpecifier *Qualifier,
QualType Sema::BuildMemberPointerType(QualType T, const CXXScopeSpec &SS,
CXXRecordDecl *Cls, SourceLocation Loc,
DeclarationName Entity) {
if (!Cls && !isDependentScopeSpecifier(SS)) {
Cls = dyn_cast_or_null<CXXRecordDecl>(computeDeclContext(SS));
if (!Cls) {
auto D =
Diag(SS.getBeginLoc(), diag::err_illegal_decl_mempointer_in_nonclass)
<< SS.getRange();
if (const IdentifierInfo *II = Entity.getAsIdentifierInfo())
D << II;
else
D << "member pointer";
return QualType();
}
}
// Verify that we're not building a pointer to pointer to function with
// exception specification.
if (CheckDistantExceptionSpec(T)) {
@ -2730,7 +2743,7 @@ QualType Sema::BuildMemberPointerType(QualType T,
if (T->isFunctionType())
adjustMemberFunctionCC(T, /*HasThisPointer=*/true, IsCtorOrDtor, Loc);
return Context.getMemberPointerType(T, Qualifier, Cls);
return Context.getMemberPointerType(T, SS.getScopeRep(), Cls);
}
QualType Sema::BuildBlockPointerType(QualType T,
@ -5344,20 +5357,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Avoid emitting extra errors if we already errored on the scope.
D.setInvalidType(true);
AreDeclaratorChunksValid = false;
} else if (auto *RD =
dyn_cast_or_null<CXXRecordDecl>(S.computeDeclContext(SS));
RD || S.isDependentScopeSpecifier(SS)) {
T = S.BuildMemberPointerType(T, SS.getScopeRep(), RD, DeclType.Loc,
D.getIdentifier());
} else {
S.Diag(DeclType.Mem.Scope().getBeginLoc(),
diag::err_illegal_decl_mempointer_in_nonclass)
<< (D.getIdentifier() ? D.getIdentifier()->getName() : "type name")
<< DeclType.Mem.Scope().getRange();
D.setInvalidType(true);
AreDeclaratorChunksValid = false;
// FIXME: Maybe we could model these as as a MemberPointerType with a
// non-dependent, non-class qualifier anyway.
T = S.BuildMemberPointerType(T, SS, /*Cls=*/nullptr, DeclType.Loc,
D.getIdentifier());
}
if (T.isNull()) {
@ -9255,10 +9257,10 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
// "Can't ask whether a dependent type is complete");
if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>()) {
if (!MPTy->getQualifier()->isDependent()) {
QualType T = Context.getTypeDeclType(MPTy->getMostRecentCXXRecordDecl());
if (getLangOpts().CompleteMemberPointers &&
!MPTy->getMostRecentCXXRecordDecl()->isBeingDefined() &&
if (CXXRecordDecl *RD = MPTy->getMostRecentCXXRecordDecl();
RD && !RD->isDependentType()) {
QualType T = Context.getTypeDeclType(RD);
if (getLangOpts().CompleteMemberPointers && !RD->isBeingDefined() &&
RequireCompleteType(Loc, T, Kind, diag::err_memptr_incomplete))
return true;

View File

@ -864,8 +864,8 @@ public:
/// By default, performs semantic analysis when building the member pointer
/// type. Subclasses may override this routine to provide different behavior.
QualType RebuildMemberPointerType(QualType PointeeType,
NestedNameSpecifier *Qualifier,
CXXRecordDecl *Cls, SourceLocation Sigil);
const CXXScopeSpec &SS, CXXRecordDecl *Cls,
SourceLocation Sigil);
QualType RebuildObjCTypeParamType(const ObjCTypeParamDecl *Decl,
SourceLocation ProtocolLAngleLoc,
@ -5631,9 +5631,10 @@ TreeTransform<Derived>::TransformMemberPointerType(TypeLocBuilder &TLB,
NewQualifierLoc.getNestedNameSpecifier() !=
OldQualifierLoc.getNestedNameSpecifier() ||
NewCls != OldCls) {
Result = getDerived().RebuildMemberPointerType(
PointeeType, NewQualifierLoc.getNestedNameSpecifier(), NewCls,
TL.getStarLoc());
CXXScopeSpec SS;
SS.Adopt(NewQualifierLoc);
Result = getDerived().RebuildMemberPointerType(PointeeType, SS, NewCls,
TL.getStarLoc());
if (Result.isNull())
return QualType();
}
@ -17044,9 +17045,9 @@ TreeTransform<Derived>::RebuildReferenceType(QualType ReferentType,
template <typename Derived>
QualType TreeTransform<Derived>::RebuildMemberPointerType(
QualType PointeeType, NestedNameSpecifier *Qualifier, CXXRecordDecl *Cls,
QualType PointeeType, const CXXScopeSpec &SS, CXXRecordDecl *Cls,
SourceLocation Sigil) {
return SemaRef.BuildMemberPointerType(PointeeType, Qualifier, Cls, Sigil,
return SemaRef.BuildMemberPointerType(PointeeType, SS, Cls, Sigil,
getDerived().getBaseEntity());
}

View File

@ -333,3 +333,14 @@ namespace test9 {
struct C { int BAR::*mp; };
// expected-error@-1 {{'BAR' is not a class, namespace, or enumeration}}
} // namespace test9
namespace GH132494 {
enum E {};
void f(int E::*); // expected-error {{member pointer does not point into a class}}
template <class T> struct A {
int T::*foo; // expected-error {{'foo' does not point into a class}}
};
template struct A<E>; // expected-note {{requested here}}
} // namespace GH132494

View File

@ -334,9 +334,7 @@ TEST(LlvmLibcTypeTraitsTest, is_class) {
// Neither other types.
EXPECT_FALSE((is_class_v<Union>));
EXPECT_FALSE((is_class_v<int>));
// TODO: Re-enable the test after
// https://github.com/llvm/llvm-project/issues/132494 is fixed.
// EXPECT_FALSE((is_class_v<EnumClass>));
EXPECT_FALSE((is_class_v<EnumClass>));
}
TYPED_TEST(LlvmLibcTypeTraitsTest, is_const, UnqualObjectTypes) {