[cfe-dev] CheckConstantExpression issue

Alex L via cfe-dev cfe-dev at lists.llvm.org
Wed Jul 5 08:47:55 PDT 2017


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_
> simple_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/
> ExprConstant.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/
> ExprConstant.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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20170705/e2213216/attachment.html>


More information about the cfe-dev mailing list