Skip to content

Commit cd95b66

Browse files
martinboehmearsenm
authored andcommitted
[clang][dataflow] Teach AnalysisASTVisitor that typeid() can be evaluated. (#96731)
We were previously treating the operand of `typeid()` as being definitely unevaluated, but it can be evaluated if it is a glvalue of polymorphic type. This patch includes a test that fails without the fix.
1 parent 87de497 commit cd95b66

File tree

2 files changed

+48
-1
lines changed

2 files changed

+48
-1
lines changed

clang/include/clang/Analysis/FlowSensitive/ASTOps.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,11 @@ class AnalysisASTVisitor : public RecursiveASTVisitor<Derived> {
113113
// nevertheless it appears in the Clang CFG, so we don't exclude it here.
114114
bool TraverseDecltypeTypeLoc(DecltypeTypeLoc) { return true; }
115115
bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc) { return true; }
116-
bool TraverseCXXTypeidExpr(CXXTypeidExpr *) { return true; }
116+
bool TraverseCXXTypeidExpr(CXXTypeidExpr *TIE) {
117+
if (TIE->isPotentiallyEvaluated())
118+
return RecursiveASTVisitor<Derived>::TraverseCXXTypeidExpr(TIE);
119+
return true;
120+
}
117121
bool TraverseUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *) {
118122
return true;
119123
}

clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,6 +1637,49 @@ TEST(TransferTest, StructModeledFieldsWithAccessor) {
16371637
});
16381638
}
16391639

1640+
TEST(TransferTest, StructModeledFieldsInTypeid) {
1641+
// Test that we model fields mentioned inside a `typeid()` expression only if
1642+
// that expression is potentially evaluated -- i.e. if the expression inside
1643+
// `typeid()` is a glvalue of polymorphic type (see
1644+
// `CXXTypeidExpr::isPotentiallyEvaluated()` and [expr.typeid]p3).
1645+
std::string Code = R"(
1646+
// Definitions needed for `typeid`.
1647+
namespace std {
1648+
class type_info {};
1649+
class bad_typeid {};
1650+
} // namespace std
1651+
1652+
struct NonPolymorphic {};
1653+
1654+
struct Polymorphic {
1655+
virtual ~Polymorphic() = default;
1656+
};
1657+
1658+
struct S {
1659+
NonPolymorphic *NonPoly;
1660+
Polymorphic *Poly;
1661+
};
1662+
1663+
void target(S &s) {
1664+
typeid(*s.NonPoly);
1665+
typeid(*s.Poly);
1666+
// [[p]]
1667+
}
1668+
)";
1669+
runDataflow(
1670+
Code,
1671+
[](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1672+
ASTContext &ASTCtx) {
1673+
const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1674+
auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s");
1675+
std::vector<const ValueDecl *> Fields;
1676+
for (auto [Field, _] : SLoc.children())
1677+
Fields.push_back(Field);
1678+
EXPECT_THAT(Fields,
1679+
UnorderedElementsAre(findValueDecl(ASTCtx, "Poly")));
1680+
});
1681+
}
1682+
16401683
TEST(TransferTest, StructModeledFieldsWithComplicatedInheritance) {
16411684
std::string Code = R"(
16421685
struct Base1 {

0 commit comments

Comments
 (0)