[cfe-dev] CheckConstantExpression issue
Mikhail Ramalho via cfe-dev
cfe-dev at lists.llvm.org
Thu Jul 6 07:34:04 PDT 2017
Have you tried to check if varDecl is in a dependent context before calling
the CheckConstantExpression?
varDecl->getDeclContext()->isDependentContext()
Thank you,
2017-07-06 5:48 GMT+01:00 Serge Preis via cfe-dev <cfe-dev at lists.llvm.org>:
> Hello,
>
> thank you for you prompt reply.
>
> I did exactly this in my code, but I am not sure asserts are enough. I
> already added checks to avoid some issues like this:
>
> >> varDecl->ensureEvaluatedStmt() != nullptr &&
> >> varDecl->ensureEvaluatedStmt()->Value !=
> nullptr)
> >> !init->isValueDependent() &&
>
> Against following code in Decl.cpp:
>
> ....
> APValue *VarDecl::evaluateValue(
> SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
> EvaluatedStmt *Eval = ensureEvaluatedStmt();
> ... // .... skipped comment ...
> if (Eval->WasEvaluated) /// <<<<< Here non-NULL
> pointer is blindly assumed
> return Eval->Evaluated.isUninit() ? nullptr : &Eval->Evaluated;
>
> const auto *Init = cast<Expr>(Eval->Value);
> assert(!Init->isValueDependent()); /// <<<< Here is just assert
> which only fires in debug mode
>
> if (Eval->IsEvaluating) {
> ...
>
> I think at least asserts should be added to VarDecl::evaluateValue() to
> ensure Eval is not NULL and the type of 'this' VarDecl is not
> DependentType. But in this case all prerequisites for evaluateValue are
> better to be somehow documented.
>
> Now for the simple varDecl->evaluateValue() we have at least (+ maybe
> something else?)
> (varDecl->getAnyInitializer() != nullptr)
> /// This
> !init->getType().isNull() &&
> /// and this
> !init->isValueDependent() &&
> !init->isTypeDependent() &&
> !varDecl->getType().isNull() &&
> /// and this --- seem reasonable to have outside the call, but I am not
> that sure about all others
> !varDecl->getType()->isDependentType() &&
> varDecl->ensureEvaluatedStmt() != nullptr &&
> varDecl->ensureEvaluatedStmt()->Value != nullptr)
>
> Alternatively let the function return NULL in all unsupported cases
> basically placing all required checks insde the function. This function
> already returns NULL on various occasions, so these additional checks seem
> to me natutal fit to the function's logic.
>
> I am ready to prepare patch for review based on agreed decision.
>
> Regards,
> Serge.
>
>
> 05.07.2017, 22:47, "Alex L" <arphaman at gmail.com>:
> > It looks like you're trying to evaluate a variable with a dependent
> type. I think that `evaluateValue` function is not intended for such
> variables. I think that it might be a good idea to put an assertion into
> that function that checks if the variables or its type is dependent, to
> complement the assertion for the dependent initializer in that function.
> >
> > On 5 July 2017 at 09:42, Serge Preis via cfe-dev <cfe-dev at lists.llvm.org>
> wrote:
> >> Hello,
> >>
> >> I encountered the following issue in lib/AST/ExprConstant.cpp:
> >>
> >> In function CheckConstantExpr there is a code:
> >>
> >> if (Value.isUnion() && Value.getUnionField()) {
> >> return CheckConstantExpression(Info, DiagLoc,
> >> Value.getUnionField()->getType(),
> >> Value.getUnionValue());
> >> }
> >> if (Value.isStruct()) {
> >> RecordDecl *RD = Type->castAs<RecordType>()->getDecl();
> //// <<<<<< The problematic line
> >> if (const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) {
> >> unsigned BaseIndex = 0;
> >> for (CXXRecordDecl::base_class_const_iterator I =
> CD->bases_begin(),
> >> End = CD->bases_end(); I != End; ++I, ++BaseIndex) {
> >> if (!CheckConstantExpression(Info, DiagLoc, I->getType(),
> >> Value.getStructBase(BaseIndex)))
> >> return false;
> >>
> >> The problematic line causes a crash because Type cannot be cast to
> RecordType.
> >>
> >> This looks like an issue in clang to me, but the question is what's
> wrong: Value.isStruct() returning true for constant of template parameter
> type (see below) or absence of check for Type to be RecordType.
> >> I will definitely impelement workaround in my code, but I would also
> like to investingate and fix this issue in clang.
> >>
> >> Regards,
> >> Serge.
> >>
> >> ----- useful info ----
> >>
> >> The code which triggering this behavior looks like the following:
> >> ...
> >> template<class T>
> >> void DoTestMax() {
> >> const T max = Max();
> >> ...
> >>
> >> I am trying to access and print constant initializer for 'max' variable
> under following checks:
> >> } else if (auto* varDecl = llvm::dyn_cast<clang::VarDecl>(decl))
> {
> >> if (!clang::isa<clang::ParmVarDecl>(varDecl) &&
> (varDecl->isConstexpr() || varDecl->getType().isConstQualified())) {
> >> const clang::Expr* init =
> varDecl->getAnyInitializer();
> >> if (init != nullptr &&
> >> !init->getType().isNull() &&
> >> !init->isValueDependent() &&
> >> varDecl->ensureEvaluatedStmt() != nullptr &&
> >> varDecl->ensureEvaluatedStmt()->Value !=
> nullptr)
> >> {
> >> const clang::APValue* val =
> varDecl->evaluateValue(); /// <<< Problem is here
> >>
> >> The relevant stack for debug clang (trunk) looks like below:
> >> #3 0x00007ffff6bb2ca2 in __GI___assert_fail (assertion=0x2661ae0
> "isa<X>(Val) && \"cast<Ty>() argument of incompatible type!\"",
> file=0x2661aa0 "/home/spreis/LLVM/latest/llvm
> /include/llvm/Support/Casting.h", line=241,
> >> function=0x2663de0 <std::enable_if<!llvm::is_simp
> le_type<clang::QualType>::value, llvm::cast_retty<clang::RecordType,
> clang::QualType const>::ret_type>::type llvm::cast<clang::RecordType,
> clang::QualType>(clang::QualType const&)::__PRETTY_FUNCTION__> "typename
> std::enable_if<(! llvm::is_simple_type<Y>::value), typename
> llvm::cast_retty<X, const Y>::ret_type>::type llvm::cast(const Y&) [with X
> = clang::RecordType; Y = clang::QualType; typename std::"...)
> >> at assert.c:101
> >> #4 0x00000000010cf75e in llvm::cast<clang::RecordType,
> clang::QualType> (Val=...)
> >> at /home/spreis/LLVM/latest/llvm/include/llvm/Support/Casting.h:241
> >> #5 0x00000000010ce4fa in clang::Type::castAs<clang::RecordType>
> (this=0x554a880)
> >> at /home/spreis/LLVM/latest/llvm/tools/clang/include/clang/AST/
> TypeNodes.def:122
> >> #6 0x0000000001c0b810 in CheckConstantExpression (Info=...,
> DiagLoc=..., Type=..., Value=...)
> >> at /home/spreis/LLVM/latest/llvm/tools/clang/lib/AST/ExprConsta
> nt.cpp:1737
> >> #7 0x0000000001c2f1b0 in clang::Expr::EvaluateAsInitializer
> (this=0x554ab50, Value=..., Ctx=..., VD=0x554a9d8, Notes=...)
> >> at /home/spreis/LLVM/latest/llvm/tools/clang/lib/AST/ExprConsta
> nt.cpp:10079
> >> #8 0x0000000001b923fa in clang::VarDecl::evaluateValue
> (this=0x554a9d8, Notes=...)
> >> at /home/spreis/LLVM/latest/llvm/tools/clang/lib/AST/Decl.cpp:2172
> >> #9 0x0000000001b9229c in clang::VarDecl::evaluateValue (this=0x554a9d8)
> >> at /home/spreis/LLVM/latest/llvm/tools/clang/lib/AST/Decl.cpp:2146
> >>
> >> The var:
> >> (gdb) frame 9
> >> 2146 return evaluateValue(Notes);
> >> (gdb) call this->dump()
> >> VarDecl 0x554a9d8 <..snip..snip> referenced max 'const T' cinit
> >> `-CallExpr 0x554ab50 <col:23, col:27> '::NPrivate::TMax':'struct
> NPrivate::TMax'
> >> `-ImplicitCastExpr 0x554ab38 <col:23> '::NPrivate::TMax (*)(void)
> noexcept' <FunctionToPointerDecay>
> >> `-DeclRefExpr 0x554aab8 <col:23> '::NPrivate::TMax (void) noexcept'
> lvalue Function 0x3f82c28 'Max' '::NPrivate::TMax (void) noexcept'
> >>
> >> The type:
> >> (gdb) frame 6
> >> 1737 RecordDecl *RD = Type->castAs<RecordType>()->getDecl();
> >> (gdb) call Type.dump()
> >> QualType 0x554a881 'const T' const
> >> `-TemplateTypeParmType 0x554a880 'T' dependent depth 0 index 0
> >> `-TemplateTypeParm 0x554a840 'T'
> >>
> >> _______________________________________________
> >> cfe-dev mailing list
> >> cfe-dev at lists.llvm.org
> >> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>
--
Mikhail Ramalho.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20170706/48369595/attachment.html>
More information about the cfe-dev
mailing list