Skip to content

[Sema] Refactor IsFunctionConversion #139172

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -10240,8 +10240,13 @@ class Sema final : public SemaBase {
/// Determine whether the conversion from FromType to ToType is a valid
/// conversion that strips "noexcept" or "noreturn" off the nested function
/// type.
bool IsFunctionConversion(QualType FromType, QualType ToType,
QualType &ResultTy);
bool IsFunctionConversion(QualType FromType, QualType ToType) const;

/// Same as `IsFunctionConversion`, but if this would return true, it sets
/// `ResultTy` to `ToType`.
bool TryFunctionConversion(QualType FromType, QualType ToType,
QualType &ResultTy) const;

bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType);
void DiagnoseUseOfDeletedFunction(SourceLocation Loc, SourceRange Range,
DeclarationName Name,
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Sema/SemaExceptionSpec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -700,12 +700,11 @@ bool Sema::handlerCanCatch(QualType HandlerType, QualType ExceptionType) {
// -- a qualification conversion
// -- a function pointer conversion
bool LifetimeConv;
QualType Result;
// FIXME: Should we treat the exception as catchable if a lifetime
// conversion is required?
if (IsQualificationConversion(ExceptionType, HandlerType, false,
LifetimeConv) ||
IsFunctionConversion(ExceptionType, HandlerType, Result))
IsFunctionConversion(ExceptionType, HandlerType))
return true;

// -- a standard pointer conversion [...]
Expand Down
5 changes: 2 additions & 3 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9124,7 +9124,7 @@ static AssignConvertType checkPointerTypesForAssignment(Sema &S,
diag::warn_typecheck_convert_incompatible_function_pointer_strict,
Loc) &&
RHSType->isFunctionPointerType() && LHSType->isFunctionPointerType() &&
!S.IsFunctionConversion(RHSType, LHSType, RHSType))
!S.TryFunctionConversion(RHSType, LHSType, RHSType))
return AssignConvertType::IncompatibleFunctionPointerStrict;

// C99 6.5.16.1p1 (constraint 3): both operands are pointers to qualified or
Expand Down Expand Up @@ -9188,8 +9188,7 @@ static AssignConvertType checkPointerTypesForAssignment(Sema &S,
return AssignConvertType::IncompatibleFunctionPointer;
return AssignConvertType::IncompatiblePointer;
}
if (!S.getLangOpts().CPlusPlus &&
S.IsFunctionConversion(ltrans, rtrans, ltrans))
if (!S.getLangOpts().CPlusPlus && S.IsFunctionConversion(ltrans, rtrans))
return AssignConvertType::IncompatibleFunctionPointer;
if (IsInvalidCmseNSCallConversion(S, ltrans, rtrans))
return AssignConvertType::IncompatibleFunctionPointer;
Expand Down
25 changes: 14 additions & 11 deletions clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1881,8 +1881,15 @@ ExprResult Sema::PerformImplicitConversion(Expr *From, QualType ToType,
return PerformImplicitConversion(From, ToType, ICS, Action);
}

bool Sema::IsFunctionConversion(QualType FromType, QualType ToType,
QualType &ResultTy) {
bool Sema::TryFunctionConversion(QualType FromType, QualType ToType,
QualType &ResultTy) const {
bool Changed = IsFunctionConversion(FromType, ToType);
if (Changed)
ResultTy = ToType;
return Changed;
}

bool Sema::IsFunctionConversion(QualType FromType, QualType ToType) const {
if (Context.hasSameUnqualifiedType(FromType, ToType))
return false;

Expand Down Expand Up @@ -1993,7 +2000,6 @@ bool Sema::IsFunctionConversion(QualType FromType, QualType ToType,
assert(QualType(FromFn, 0).isCanonical());
if (QualType(FromFn, 0) != CanTo) return false;

ResultTy = ToType;
return true;
}

Expand Down Expand Up @@ -2232,11 +2238,10 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// we can sometimes resolve &foo<int> regardless of ToType, so check
// if the type matches (identity) or we are converting to bool
if (!S.Context.hasSameUnqualifiedType(
S.ExtractUnqualifiedFunctionType(ToType), FromType)) {
QualType resultTy;
S.ExtractUnqualifiedFunctionType(ToType), FromType)) {
// if the function type matches except for [[noreturn]], it's ok
if (!S.IsFunctionConversion(FromType,
S.ExtractUnqualifiedFunctionType(ToType), resultTy))
S.ExtractUnqualifiedFunctionType(ToType)))
// otherwise, only a boolean conversion is standard
if (!ToType->isBooleanType())
return false;
Expand Down Expand Up @@ -2476,7 +2481,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// The third conversion can be a function pointer conversion or a
// qualification conversion (C++ [conv.fctptr], [conv.qual]).
bool ObjCLifetimeConversion;
if (S.IsFunctionConversion(FromType, ToType, FromType)) {
if (S.TryFunctionConversion(FromType, ToType, FromType)) {
// Function pointer conversions (removing 'noexcept') including removal of
// 'noreturn' (Clang extension).
SCS.Third = ICK_Function_Conversion;
Expand Down Expand Up @@ -5033,7 +5038,6 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
// Check for standard conversions we can apply to pointers: derived-to-base
// conversions, ObjC pointer conversions, and function pointer conversions.
// (Qualification conversions are checked last.)
QualType ConvertedT2;
if (UnqualT1 == UnqualT2) {
// Nothing to do.
} else if (isCompleteType(Loc, OrigT2) &&
Expand All @@ -5044,7 +5048,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
Context.canBindObjCObjectType(UnqualT1, UnqualT2))
Conv |= ReferenceConversions::ObjC;
else if (UnqualT2->isFunctionType() &&
IsFunctionConversion(UnqualT2, UnqualT1, ConvertedT2)) {
IsFunctionConversion(UnqualT2, UnqualT1)) {
Conv |= ReferenceConversions::Function;
// No need to check qualifiers; function types don't have them.
return Ref_Compatible;
Expand Down Expand Up @@ -13426,9 +13430,8 @@ class AddressOfFunctionResolver {

private:
bool candidateHasExactlyCorrectType(const FunctionDecl *FD) {
QualType Discard;
return Context.hasSameUnqualifiedType(TargetFunctionType, FD->getType()) ||
S.IsFunctionConversion(FD->getType(), TargetFunctionType, Discard);
S.IsFunctionConversion(FD->getType(), TargetFunctionType);
}

/// \return true if A is considered a better overload candidate for the
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7665,9 +7665,8 @@ ExprResult Sema::BuildExpressionFromDeclTemplateArgument(
QualType DestExprType = ParamType.getNonLValueExprType(Context);
if (!Context.hasSameType(RefExpr.get()->getType(), DestExprType)) {
CastKind CK;
QualType Ignored;
if (Context.hasSimilarType(RefExpr.get()->getType(), DestExprType) ||
IsFunctionConversion(RefExpr.get()->getType(), DestExprType, Ignored)) {
IsFunctionConversion(RefExpr.get()->getType(), DestExprType)) {
CK = CK_NoOp;
} else if (ParamType->isVoidPointerType() &&
RefExpr.get()->getType()->isPointerType()) {
Expand Down
8 changes: 3 additions & 5 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1333,7 +1333,7 @@ bool Sema::isSameOrCompatibleFunctionType(QualType P, QualType A) {
return Context.hasSameType(P, A);

// Noreturn and noexcept adjustment.
if (QualType AdjustedParam; IsFunctionConversion(P, A, AdjustedParam))
if (QualType AdjustedParam; TryFunctionConversion(P, A, AdjustedParam))
P = AdjustedParam;

// FIXME: Compatible calling conventions.
Expand Down Expand Up @@ -3732,8 +3732,7 @@ CheckOriginalCallArgDeduction(Sema &S, TemplateDeductionInfo &Info,
// FIXME: Resolve core issue (no number yet): if the original P is a
// reference type and the transformed A is function type "noexcept F",
// the deduced A can be F.
QualType Tmp;
if (A->isFunctionType() && S.IsFunctionConversion(A, DeducedA, Tmp))
if (A->isFunctionType() && S.IsFunctionConversion(A, DeducedA))
return TemplateDeductionResult::Success;

Qualifiers AQuals = A.getQualifiers();
Expand Down Expand Up @@ -3770,11 +3769,10 @@ CheckOriginalCallArgDeduction(Sema &S, TemplateDeductionInfo &Info,
// Also allow conversions which merely strip __attribute__((noreturn)) from
// function types (recursively).
bool ObjCLifetimeConversion = false;
QualType ResultTy;
if ((A->isAnyPointerType() || A->isMemberPointerType()) &&
(S.IsQualificationConversion(A, DeducedA, false,
ObjCLifetimeConversion) ||
S.IsFunctionConversion(A, DeducedA, ResultTy)))
S.IsFunctionConversion(A, DeducedA)))
return TemplateDeductionResult::Success;

// - If P is a class and P has the form simple-template-id, then the
Expand Down