Ответ 1
Хорошо, я вырыл через Clang исходный код, чтобы найти этот метод:
/// isAlwaysNull - Return whether the result of the dynamic_cast is proven
/// to always be null. For example:
///
/// struct A { };
/// struct B final : A { };
/// struct C { };
///
/// C *f(B* b) { return dynamic_cast<C*>(b); }
bool CXXDynamicCastExpr::isAlwaysNull() const
{
QualType SrcType = getSubExpr()->getType();
QualType DestType = getType();
if (const PointerType *SrcPTy = SrcType->getAs<PointerType>()) {
SrcType = SrcPTy->getPointeeType();
DestType = DestType->castAs<PointerType>()->getPointeeType();
}
if (DestType->isVoidType()) // always allow cast to void*
return false;
const CXXRecordDecl *SrcRD =
cast<CXXRecordDecl>(SrcType->castAs<RecordType>()->getDecl());
//********************************************************************
if (!SrcRD->hasAttr<FinalAttr>()) // here we check for Final Attribute
return false; // returns false for Cat
//********************************************************************
const CXXRecordDecl *DestRD =
cast<CXXRecordDecl>(DestType->castAs<RecordType>()->getDecl());
return !DestRD->isDerivedFrom(SrcRD); // search ancestor types
}
Я немного устаю от кода синтаксического анализа, но мне не кажется, что ваш from_final
не всегда всегда является нулевым из-за конечного атрибута, но, кроме того, поскольку <<22 > не находится в Dog
производная цепочка записей. Если бы у него не было атрибута final
, он бы вышел раньше (как это делает, когда Cat
является Src), но он не обязательно всегда был бы нулевым.
Я предполагаю, что для этого есть несколько причин. Первый заключается в том, что dynamic_cast использует как вверх, так и вниз цепочку записей. Когда исходная запись имеет конечный атрибут, вы можете просто проверить цепочку, если Dest является предком (потому что из исходного кода не могут быть производные классы).
Но что, если класс не является окончательным? Я подозреваю, что может быть и больше. Может быть, многократное наследование делает поиск бросков сложнее, чем прикладывание? Не останавливая код в отладчике, я могу только предположить.
Этого я знаю: isAlwaysNull
- это ранняя функция выхода. Это разумное утверждение, что оно пытается доказать, что результат всегда равен нулю. Вы не можете доказать отрицательный (как говорится), но вы можете опровергнуть позитив.
Возможно, вы можете проверить историю Git для файла и отправить письмо человеку, который написал эту функцию. (или, по крайней мере, добавил проверку final
).