Skip to content

[NFC] Add implicit cast kinds for function pointer conversions #110047

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

Closed
wants to merge 1 commit into from
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ void SwappedArgumentsCheck::registerMatchers(MatchFinder *Finder) {
static const Expr *ignoreNoOpCasts(const Expr *E) {
if (auto *Cast = dyn_cast<CastExpr>(E))
if (Cast->getCastKind() == CK_LValueToRValue ||
Cast->getCastKind() == CK_FunctionPointerConversion ||
Cast->getCastKind() == CK_MemberFunctionPointerConversion ||
Cast->getCastKind() == CK_NoOp)
return ignoreNoOpCasts(Cast->getSubExpr());
return E;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ void ProTypeCstyleCastCheck::check(const MatchFinder::MatchResult &Result) {
return;
}

if (MatchedCast->getCastKind() == CK_NoOp &&
if ((MatchedCast->getCastKind() == CK_NoOp ||
MatchedCast->getCastKind() == CK_FunctionPointerConversion ||
MatchedCast->getCastKind() == CK_MemberFunctionPointerConversion) &&
needsConstCast(SourceType, MatchedCast->getType())) {
diag(MatchedCast->getBeginLoc(),
"do not use C-style cast to cast away constness");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,10 @@ void AvoidCStyleCastsCheck::check(const MatchFinder::MatchResult &Result) {
DestTypeAsWritten->isRecordType() &&
!DestTypeAsWritten->isElaboratedTypeSpecifier();

if (CastExpr->getCastKind() == CK_NoOp && !FnToFnCast) {
if ((CastExpr->getCastKind() == CK_NoOp ||
CastExpr->getCastKind() == CK_FunctionPointerConversion ||
CastExpr->getCastKind() == CK_MemberFunctionPointerConversion) &&
!FnToFnCast) {
// Function pointer/reference casts may be needed to resolve ambiguities in
// case of overloaded functions, so detection of redundant casts is trickier
// in this case. Don't emit "redundant cast" warnings for function
Expand Down Expand Up @@ -201,6 +204,8 @@ void AvoidCStyleCastsCheck::check(const MatchFinder::MatchResult &Result) {
}
return;
case CK_NoOp:
case CK_FunctionPointerConversion:
case CK_MemberFunctionPointerConversion:
if (FnToFnCast) {
ReplaceWithNamedCast("static_cast");
return;
Expand Down
4 changes: 3 additions & 1 deletion clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,9 @@ static bool canBeModified(ASTContext *Context, const Expr *E) {
if (Parents.size() != 1)
return true;
if (const auto *Cast = Parents[0].get<ImplicitCastExpr>()) {
if ((Cast->getCastKind() == CK_NoOp &&
if (((Cast->getCastKind() == CK_NoOp ||
Cast->getCastKind() == CK_FunctionPointerConversion ||
Cast->getCastKind() == CK_MemberFunctionPointerConversion) &&
Context->hasSameType(Cast->getType(), E->getType().withConst())) ||
(Cast->getCastKind() == CK_LValueToRValue &&
!Cast->getType().isNull() && Cast->getType()->isFundamentalType()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ namespace clang::tidy::performance {
// case we skip the first cast expr.
static bool isNonTrivialImplicitCast(const Stmt *ST) {
if (const auto *ICE = dyn_cast<ImplicitCastExpr>(ST)) {
return (ICE->getCastKind() != CK_NoOp) ||
return (ICE->getCastKind() != CK_NoOp &&
ICE->getCastKind() != CK_FunctionPointerConversion &&
ICE->getCastKind() != CK_MemberFunctionPointerConversion) ||
isNonTrivialImplicitCast(ICE->getSubExpr());
}
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,9 @@ class FindUsageOfThis : public RecursiveASTVisitor<FindUsageOfThis> {
// (possibly `-UnaryOperator Deref)
// `-CXXThisExpr 'S *' this
bool visitUser(const ImplicitCastExpr *Cast) {
if (Cast->getCastKind() != CK_NoOp)
if (Cast->getCastKind() != CK_NoOp &&
Cast->getCastKind() != CK_FunctionPointerConversion &&
Cast->getCastKind() != CK_MemberFunctionPointerConversion)
return false; // Stop traversal.

// Only allow NoOp cast to 'const S' or 'const S *'.
Expand Down Expand Up @@ -159,7 +161,10 @@ class FindUsageOfThis : public RecursiveASTVisitor<FindUsageOfThis> {
if (Cast->getCastKind() == CK_LValueToRValue)
return true;

if (Cast->getCastKind() == CK_NoOp && Cast->getType().isConstQualified())
if ((Cast->getCastKind() == CK_NoOp ||
Cast->getCastKind() == CK_FunctionPointerConversion ||
Cast->getCastKind() == CK_MemberFunctionPointerConversion) &&
Cast->getType().isConstQualified())
return true;
}

Expand Down
2 changes: 2 additions & 0 deletions clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ AST_MATCHER_P(DeclRefExpr, doesNotMutateObject, int, Indirections) {
case CK_BaseToDerived:
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase:
case CK_FunctionPointerConversion:
case CK_MemberFunctionPointerConversion:
case CK_Dynamic:
case CK_BaseToDerivedMemberPointer:
case CK_DerivedToBaseMemberPointer:
Expand Down
2 changes: 2 additions & 0 deletions clang-tools-extra/clangd/Hover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1122,6 +1122,8 @@ void maybeAddCalleeArgInfo(const SelectionTree::Node *N, HoverInfo &HI,
if (const auto *ImplicitCast = CastNode->ASTNode.get<ImplicitCastExpr>()) {
switch (ImplicitCast->getCastKind()) {
case CK_NoOp:
case CK_FunctionPointerConversion:
case CK_MemberFunctionPointerConversion:
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase:
// If it was a reference before, it's still a reference.
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/AST/IgnoreExpr.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ inline Expr *IgnoreBaseCastsSingleStep(Expr *E) {
if (auto *CE = dyn_cast<CastExpr>(E))
if (CE->getCastKind() == CK_DerivedToBase ||
CE->getCastKind() == CK_UncheckedDerivedToBase ||
CE->getCastKind() == CK_NoOp)
CE->getCastKind() == CK_NoOp ||
CE->getCastKind() == CK_FunctionPointerConversion ||
CE->getCastKind() == CK_MemberFunctionPointerConversion)
return CE->getSubExpr();

return E;
Expand Down
8 changes: 8 additions & 0 deletions clang/include/clang/AST/OperationKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ CAST_OPERATION(LValueToRValue)
/// void () noexcept -> void ()
CAST_OPERATION(NoOp)

/// CK_FunctionPointerConversion - A conversion from pointer/reference to
/// noexcept function to pointer/reference to function.
CAST_OPERATION(FunctionPointerConversion)

/// CK_MemberFunctionPointerConversion - A conversion from pointer to noexcept
/// member function to pointer to member function.
CAST_OPERATION(MemberFunctionPointerConversion)

/// CK_BaseToDerived - A conversion from a C++ class pointer/reference
/// to a derived class pointer/reference.
/// B *b = static_cast<B*>(a);
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/ARCMigrate/TransBlockObjCVariable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@ class RootBlockObjCVarRewriter :
if (ref->getDecl() == Var) {
if (castE->getCastKind() == CK_LValueToRValue)
return true; // Using the value of the variable.
if (castE->getCastKind() == CK_NoOp && castE->isLValue() &&
Var->getASTContext().getLangOpts().CPlusPlus)
if ((castE->getCastKind() == CK_NoOp ||
castE->getCastKind() == CK_FunctionPointerConversion ||
castE->getCastKind() == CK_MemberFunctionPointerConversion) &&
castE->isLValue() && Var->getASTContext().getLangOpts().CPlusPlus)
return true; // Binding to const C++ reference.
}
}
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,8 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
case CK_FunctionToPointerDecay:
case CK_NonAtomicToAtomic:
case CK_NoOp:
case CK_FunctionPointerConversion:
case CK_MemberFunctionPointerConversion:
case CK_UserDefinedConversion:
case CK_AddressSpaceConversion:
return this->delegate(SubExpr);
Expand Down Expand Up @@ -3067,6 +3069,8 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) {
for (; auto *ICE = dyn_cast<ImplicitCastExpr>(Stripped);
Stripped = ICE->getSubExpr())
if (ICE->getCastKind() != CK_NoOp &&
ICE->getCastKind() != CK_FunctionPointerConversion &&
ICE->getCastKind() != CK_MemberFunctionPointerConversion &&
ICE->getCastKind() != CK_IntegralCast)
break;

Expand Down
28 changes: 23 additions & 5 deletions clang/lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,9 @@ const Expr *Expr::skipRValueSubobjectAdjustments(
continue;
}

if (CE->getCastKind() == CK_NoOp) {
if (CE->getCastKind() == CK_NoOp ||
CE->getCastKind() == CK_FunctionPointerConversion ||
CE->getCastKind() == CK_MemberFunctionPointerConversion) {
E = CE->getSubExpr();
continue;
}
Expand Down Expand Up @@ -1926,6 +1928,8 @@ bool CastExpr::CastConsistency() const {
case CK_Dependent:
case CK_LValueToRValue:
case CK_NoOp:
case CK_FunctionPointerConversion:
case CK_MemberFunctionPointerConversion:
case CK_AtomicToNonAtomic:
case CK_NonAtomicToAtomic:
case CK_PointerToBoolean:
Expand Down Expand Up @@ -3188,7 +3192,9 @@ static const Expr *skipTemporaryBindingsNoOpCastsAndParens(const Expr *E) {
E = M->getSubExpr();

while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
if (ICE->getCastKind() == CK_NoOp)
if (ICE->getCastKind() == CK_NoOp ||
ICE->getCastKind() == CK_FunctionPointerConversion ||
ICE->getCastKind() == CK_MemberFunctionPointerConversion)
E = ICE->getSubExpr();
else
break;
Expand All @@ -3198,7 +3204,9 @@ static const Expr *skipTemporaryBindingsNoOpCastsAndParens(const Expr *E) {
E = BE->getSubExpr();

while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
if (ICE->getCastKind() == CK_NoOp)
if (ICE->getCastKind() == CK_NoOp ||
ICE->getCastKind() == CK_FunctionPointerConversion ||
ICE->getCastKind() == CK_MemberFunctionPointerConversion)
E = ICE->getSubExpr();
else
break;
Expand Down Expand Up @@ -3263,6 +3271,8 @@ bool Expr::isImplicitCXXThis() const {

if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
if (ICE->getCastKind() == CK_NoOp ||
ICE->getCastKind() == CK_FunctionPointerConversion ||
ICE->getCastKind() == CK_MemberFunctionPointerConversion ||
ICE->getCastKind() == CK_LValueToRValue ||
ICE->getCastKind() == CK_DerivedToBase ||
ICE->getCastKind() == CK_UncheckedDerivedToBase) {
Expand Down Expand Up @@ -3478,6 +3488,8 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,

// Handle misc casts we want to ignore.
if (CE->getCastKind() == CK_NoOp ||
CE->getCastKind() == CK_FunctionPointerConversion ||
CE->getCastKind() == CK_MemberFunctionPointerConversion ||
CE->getCastKind() == CK_LValueToRValue ||
CE->getCastKind() == CK_ToUnion ||
CE->getCastKind() == CK_ConstructorConversion ||
Expand Down Expand Up @@ -4113,7 +4125,10 @@ FieldDecl *Expr::getSourceBitField() {

while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
if (ICE->getCastKind() == CK_LValueToRValue ||
(ICE->isGLValue() && ICE->getCastKind() == CK_NoOp))
(ICE->isGLValue() &&
(ICE->getCastKind() == CK_NoOp ||
ICE->getCastKind() == CK_FunctionPointerConversion ||
ICE->getCastKind() == CK_MemberFunctionPointerConversion)))
E = ICE->getSubExpr()->IgnoreParens();
else
break;
Expand Down Expand Up @@ -4167,7 +4182,10 @@ bool Expr::refersToVectorElement() const {
const Expr *E = this->IgnoreParens();

while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
if (ICE->isGLValue() && ICE->getCastKind() == CK_NoOp)
if (ICE->isGLValue() &&
(ICE->getCastKind() == CK_NoOp ||
ICE->getCastKind() == CK_FunctionPointerConversion ||
ICE->getCastKind() == CK_MemberFunctionPointerConversion))
E = ICE->getSubExpr()->IgnoreParens();
else
break;
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/AST/ExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -344,8 +344,12 @@ QualType CXXDeleteExpr::getDestroyedType() const {
while (const auto *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
if (ICE->getCastKind() == CK_DerivedToBase ||
ICE->getCastKind() == CK_UncheckedDerivedToBase ||
ICE->getCastKind() == CK_NoOp) {
ICE->getCastKind() == CK_NoOp ||
ICE->getCastKind() == CK_FunctionPointerConversion ||
ICE->getCastKind() == CK_MemberFunctionPointerConversion) {
assert((ICE->getCastKind() == CK_NoOp ||
ICE->getCastKind() == CK_FunctionPointerConversion ||
ICE->getCastKind() == CK_MemberFunctionPointerConversion ||
getOperatorDelete()->isDestroyingOperatorDelete()) &&
"only a destroying operator delete can have a converted arg");
Arg = ICE->getSubExpr();
Expand Down
17 changes: 14 additions & 3 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6247,7 +6247,9 @@ static bool MaybeHandleUnionActiveMemberChange(EvalInfo &Info,
} else if (auto *ICE = dyn_cast<ImplicitCastExpr>(E)) {
// Step over a derived-to-base conversion.
E = ICE->getSubExpr();
if (ICE->getCastKind() == CK_NoOp)
if (ICE->getCastKind() == CK_NoOp ||
ICE->getCastKind() == CK_FunctionPointerConversion ||
ICE->getCastKind() == CK_MemberFunctionPointerConversion)
continue;
if (ICE->getCastKind() != CK_DerivedToBase &&
ICE->getCastKind() != CK_UncheckedDerivedToBase)
Expand Down Expand Up @@ -8301,6 +8303,8 @@ class ExprEvaluatorBase
}

case CK_NoOp:
case CK_FunctionPointerConversion:
case CK_MemberFunctionPointerConversion:
case CK_UserDefinedConversion:
return StmtVisitorTy::Visit(E->getSubExpr());

Expand Down Expand Up @@ -10074,6 +10078,8 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
for (; auto *ICE = dyn_cast<ImplicitCastExpr>(Stripped);
Stripped = ICE->getSubExpr())
if (ICE->getCastKind() != CK_NoOp &&
ICE->getCastKind() != CK_FunctionPointerConversion &&
ICE->getCastKind() != CK_MemberFunctionPointerConversion &&
ICE->getCastKind() != CK_IntegralCast)
break;

Expand Down Expand Up @@ -12210,8 +12216,9 @@ static const Expr *ignorePointerCastsAndParens(const Expr *E) {
// We only conservatively allow a few kinds of casts, because this code is
// inherently a simple solution that seeks to support the common case.
auto CastKind = Cast->getCastKind();
if (CastKind != CK_NoOp && CastKind != CK_BitCast &&
CastKind != CK_AddressSpaceConversion)
if (CastKind != CK_NoOp && CastKind != CK_FunctionPointerConversion &&
CastKind != CK_MemberFunctionPointerConversion &&
CastKind != CK_BitCast && CastKind != CK_AddressSpaceConversion)
return NoParens;

const auto *SubExpr = Cast->getSubExpr();
Expand Down Expand Up @@ -14448,6 +14455,8 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
QualType SrcType = SubExpr->getType();

switch (E->getCastKind()) {
case CK_FunctionPointerConversion:
case CK_MemberFunctionPointerConversion:
case CK_BaseToDerived:
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase:
Expand Down Expand Up @@ -15288,6 +15297,8 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_BaseToDerived:
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase:
case CK_FunctionPointerConversion:
case CK_MemberFunctionPointerConversion:
case CK_Dynamic:
case CK_ToUnion:
case CK_ArrayToPointerDecay:
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Analysis/CFG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1491,6 +1491,8 @@ void CFGBuilder::findConstructionContexts(
// Should we support other implicit cast kinds?
switch (Cast->getCastKind()) {
case CK_NoOp:
case CK_FunctionPointerConversion:
case CK_MemberFunctionPointerConversion:
case CK_ConstructorConversion:
findConstructionContexts(Layer, Cast->getSubExpr());
break;
Expand Down
12 changes: 7 additions & 5 deletions clang/lib/Analysis/ExprMutationAnalyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -377,11 +377,13 @@ ExprMutationAnalyzer::Analyzer::findDirectMutation(const Expr *Exp) {
// We're assuming 'Exp' is mutated as soon as its address is taken, though in
// theory we can follow the pointer and see whether it escaped `Stm` or is
// dereferenced and then mutated. This is left for future improvements.
const auto AsAmpersandOperand =
unaryOperator(hasOperatorName("&"),
// A NoOp implicit cast is adding const.
unless(hasParent(implicitCastExpr(hasCastKind(CK_NoOp)))),
hasUnaryOperand(canResolveToExpr(Exp)));
const auto AsAmpersandOperand = unaryOperator(
hasOperatorName("&"),
// A NoOp implicit cast is adding const.
unless(hasParent(implicitCastExpr(
anyOf(hasCastKind(CK_NoOp), hasCastKind(CK_FunctionPointerConversion),
hasCastKind(CK_MemberFunctionPointerConversion))))),
hasUnaryOperand(canResolveToExpr(Exp)));
const auto AsPointerFromArrayDecay = castExpr(
hasCastKind(CK_ArrayToPointerDecay),
unless(hasParent(arraySubscriptExpr())), has(canResolveToExpr(Exp)));
Expand Down
8 changes: 6 additions & 2 deletions clang/lib/Analysis/FlowSensitive/Transfer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,9 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
case CK_UserDefinedConversion:
// FIXME: Add tests that excercise CK_UncheckedDerivedToBase,
// CK_ConstructorConversion, and CK_UserDefinedConversion.
case CK_NoOp: {
case CK_NoOp:
case CK_FunctionPointerConversion:
case CK_MemberFunctionPointerConversion: {
// FIXME: Consider making `Environment::getStorageLocation` skip noop
// expressions (this and other similar expressions in the file) instead
// of assigning them storage locations.
Expand Down Expand Up @@ -679,7 +681,9 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
}

void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) {
if (S->getCastKind() == CK_NoOp) {
if (S->getCastKind() == CK_NoOp ||
S->getCastKind() == CK_FunctionPointerConversion ||
S->getCastKind() == CK_MemberFunctionPointerConversion) {
const Expr *SubExpr = S->getSubExpr();
assert(SubExpr != nullptr);

Expand Down
6 changes: 4 additions & 2 deletions clang/lib/Analysis/ThreadSafety.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2103,8 +2103,10 @@ void BuildLockset::VisitCXXConstructExpr(const CXXConstructExpr *Exp) {

static const Expr *UnpackConstruction(const Expr *E) {
if (auto *CE = dyn_cast<CastExpr>(E))
if (CE->getCastKind() == CK_NoOp)
E = CE->getSubExpr()->IgnoreParens();
if (CE->getCastKind() == CK_NoOp ||
CE->getCastKind() == CK_FunctionPointerConversion ||
CE->getCastKind() == CK_MemberFunctionPointerConversion)
E = CE->getSubExpr()->IgnoreParens();
if (auto *CE = dyn_cast<CastExpr>(E))
if (CE->getCastKind() == CK_ConstructorConversion ||
CE->getCastKind() == CK_UserDefinedConversion)
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Analysis/ThreadSafetyCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,8 @@ til::SExpr *SExprBuilder::translateCastExpr(const CastExpr *CE,
// return new (Arena) til::Load(E0);
}
case CK_NoOp:
case CK_FunctionPointerConversion:
case CK_MemberFunctionPointerConversion:
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase:
case CK_ArrayToPointerDecay:
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CGDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,8 @@ static bool tryEmitARCCopyWeakInit(CodeGenFunction &CGF,
switch (castExpr->getCastKind()) {
// Look through casts that don't require representation changes.
case CK_NoOp:
case CK_FunctionPointerConversion:
case CK_MemberFunctionPointerConversion:
case CK_BitCast:
case CK_BlockPointerToObjCPointerCast:
needsCast = true;
Expand Down
Loading