-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[NFC] Add implicit cast kinds for function pointer conversions #110048
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
Conversation
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
The new cast kinds are needed to distinguish between no-op conversions and conversions from pointers to noexcept functions to pointers to functions without noexcept as the latter can cause function pointers to be re-signed on arm64e. See llvm#109056 for background.
75cd73e to
b9a8339
Compare
|
@llvm/pr-subscribers-clang-static-analyzer-1 @llvm/pr-subscribers-clang Author: Akira Hatanaka (ahatanak) ChangesThe new cast kinds are needed to distinguish between no-op conversions and conversions from pointers to noexcept functions to pointers to functions without noexcept as the latter can cause function pointers to be re-signed on arm64e. See #109056 for background. Patch is 37.94 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/110048.diff 40 Files Affected:
diff --git a/clang-tools-extra/clang-tidy/bugprone/SwappedArgumentsCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SwappedArgumentsCheck.cpp
index 8989444dde1300..acb7112fa2abed 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SwappedArgumentsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SwappedArgumentsCheck.cpp
@@ -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;
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp
index 5e255dcaacd262..bab08496e90e86 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp
@@ -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");
diff --git a/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp b/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp
index 3109bbb3724c79..888f7b122b82c3 100644
--- a/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp
@@ -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
@@ -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;
diff --git a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
index 1c6a1618ebbc4f..801d97ef2988ba 100644
--- a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
@@ -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()))
diff --git a/clang-tools-extra/clang-tidy/performance/ImplicitConversionInLoopCheck.cpp b/clang-tools-extra/clang-tidy/performance/ImplicitConversionInLoopCheck.cpp
index 86fca0722dcd82..4fc32e1d1572eb 100644
--- a/clang-tools-extra/clang-tidy/performance/ImplicitConversionInLoopCheck.cpp
+++ b/clang-tools-extra/clang-tidy/performance/ImplicitConversionInLoopCheck.cpp
@@ -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;
diff --git a/clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp b/clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
index d42fcba70e81b4..751cd637a02334 100644
--- a/clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
@@ -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 *'.
@@ -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;
}
diff --git a/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp b/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
index 106feb7fb41720..87e523eaaa7718 100644
--- a/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ b/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -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:
diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp
index 298fa79e3fd0ba..5cb2ecd1d55726 100644
--- a/clang-tools-extra/clangd/Hover.cpp
+++ b/clang-tools-extra/clangd/Hover.cpp
@@ -1118,6 +1118,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.
diff --git a/clang/include/clang/AST/IgnoreExpr.h b/clang/include/clang/AST/IgnoreExpr.h
index 917bada61fa6fd..967c381dfa9dc5 100644
--- a/clang/include/clang/AST/IgnoreExpr.h
+++ b/clang/include/clang/AST/IgnoreExpr.h
@@ -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;
diff --git a/clang/include/clang/AST/OperationKinds.def b/clang/include/clang/AST/OperationKinds.def
index 8788b8ff0ef0a4..25cd0dbb5e3a3b 100644
--- a/clang/include/clang/AST/OperationKinds.def
+++ b/clang/include/clang/AST/OperationKinds.def
@@ -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);
diff --git a/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp b/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp
index 1e4db33135b6a1..7295f064849ea6 100644
--- a/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp
+++ b/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp
@@ -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.
}
}
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index e54b6568d7060b..7d448d0e1cbeb2 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -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:
case CK_CPointerToObjCPointerCast:
@@ -3161,6 +3163,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;
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 2e463fc00c6b68..c62ffa9bf7df59 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -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;
}
@@ -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:
@@ -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;
@@ -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;
@@ -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) {
@@ -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 ||
@@ -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;
@@ -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;
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 83ce404add5f50..a3f09786960b1f 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -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();
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 6387e375dda79c..28f829e612be47 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -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)
@@ -8301,6 +8303,8 @@ class ExprEvaluatorBase
}
case CK_NoOp:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
case CK_UserDefinedConversion:
return StmtVisitorTy::Visit(E->getSubExpr());
@@ -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;
@@ -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();
@@ -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:
@@ -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:
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index f678ac6f2ff36a..baa5f96f8cbdbe 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -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;
diff --git a/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
index 6d726ae44104ed..8f19bd7e918706 100644
--- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp
+++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
@@ -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 AsPo...
[truncated]
|
|
@llvm/pr-subscribers-clangd Author: Akira Hatanaka (ahatanak) ChangesThe new cast kinds are needed to distinguish between no-op conversions and conversions from pointers to noexcept functions to pointers to functions without noexcept as the latter can cause function pointers to be re-signed on arm64e. See #109056 for background. Patch is 37.94 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/110048.diff 40 Files Affected:
diff --git a/clang-tools-extra/clang-tidy/bugprone/SwappedArgumentsCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SwappedArgumentsCheck.cpp
index 8989444dde1300..acb7112fa2abed 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SwappedArgumentsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SwappedArgumentsCheck.cpp
@@ -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;
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp
index 5e255dcaacd262..bab08496e90e86 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp
@@ -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");
diff --git a/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp b/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp
index 3109bbb3724c79..888f7b122b82c3 100644
--- a/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp
@@ -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
@@ -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;
diff --git a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
index 1c6a1618ebbc4f..801d97ef2988ba 100644
--- a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
@@ -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()))
diff --git a/clang-tools-extra/clang-tidy/performance/ImplicitConversionInLoopCheck.cpp b/clang-tools-extra/clang-tidy/performance/ImplicitConversionInLoopCheck.cpp
index 86fca0722dcd82..4fc32e1d1572eb 100644
--- a/clang-tools-extra/clang-tidy/performance/ImplicitConversionInLoopCheck.cpp
+++ b/clang-tools-extra/clang-tidy/performance/ImplicitConversionInLoopCheck.cpp
@@ -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;
diff --git a/clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp b/clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
index d42fcba70e81b4..751cd637a02334 100644
--- a/clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
@@ -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 *'.
@@ -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;
}
diff --git a/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp b/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
index 106feb7fb41720..87e523eaaa7718 100644
--- a/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ b/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -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:
diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp
index 298fa79e3fd0ba..5cb2ecd1d55726 100644
--- a/clang-tools-extra/clangd/Hover.cpp
+++ b/clang-tools-extra/clangd/Hover.cpp
@@ -1118,6 +1118,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.
diff --git a/clang/include/clang/AST/IgnoreExpr.h b/clang/include/clang/AST/IgnoreExpr.h
index 917bada61fa6fd..967c381dfa9dc5 100644
--- a/clang/include/clang/AST/IgnoreExpr.h
+++ b/clang/include/clang/AST/IgnoreExpr.h
@@ -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;
diff --git a/clang/include/clang/AST/OperationKinds.def b/clang/include/clang/AST/OperationKinds.def
index 8788b8ff0ef0a4..25cd0dbb5e3a3b 100644
--- a/clang/include/clang/AST/OperationKinds.def
+++ b/clang/include/clang/AST/OperationKinds.def
@@ -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);
diff --git a/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp b/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp
index 1e4db33135b6a1..7295f064849ea6 100644
--- a/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp
+++ b/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp
@@ -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.
}
}
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index e54b6568d7060b..7d448d0e1cbeb2 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -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:
case CK_CPointerToObjCPointerCast:
@@ -3161,6 +3163,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;
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 2e463fc00c6b68..c62ffa9bf7df59 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -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;
}
@@ -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:
@@ -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;
@@ -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;
@@ -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) {
@@ -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 ||
@@ -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;
@@ -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;
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 83ce404add5f50..a3f09786960b1f 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -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();
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 6387e375dda79c..28f829e612be47 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -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)
@@ -8301,6 +8303,8 @@ class ExprEvaluatorBase
}
case CK_NoOp:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
case CK_UserDefinedConversion:
return StmtVisitorTy::Visit(E->getSubExpr());
@@ -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;
@@ -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();
@@ -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:
@@ -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:
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index f678ac6f2ff36a..baa5f96f8cbdbe 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -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;
diff --git a/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
index 6d726ae44104ed..8f19bd7e918706 100644
--- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp
+++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
@@ -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 AsPo...
[truncated]
|
|
This change isn't needed anymore as it was decided that noexcept shouldn't be used to compute discriminators of function and member function pointers (see #106487 (comment)). |
The new cast kinds are needed to distinguish between no-op conversions and conversions from pointers to noexcept functions to pointers to functions without noexcept as the latter can cause function pointers to be re-signed on arm64e.
See #109056 for background.