<div dir="ltr">Have you tried to check if varDecl is in a dependent context before calling the CheckConstantExpression?<div><br></div><div><span style="color:rgb(80,0,80);font-size:12.8px">varDecl-></span>getDeclContext()-><wbr>isDependentContext()</div><div><br></div><div>Thank you,</div><div class="gmail_extra"><br><div class="gmail_quote">2017-07-06 5:48 GMT+01:00 Serge Preis via cfe-dev <span dir="ltr"><<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hello,<br>
<br>
thank you for you prompt reply.<br>
<br>
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:<br>
<span><br>
>>                         varDecl->ensureEvaluatedStmt() != nullptr &&<br>
>>                         varDecl->ensureEvaluatedStmt()<wbr>->Value != nullptr)<br>
</span>>>                         !init->isValueDependent() &&<br>
<br>
Against following code in Decl.cpp:<br>
<br>
....<br>
APValue *VarDecl::evaluateValue(<br>
    SmallVectorImpl<PartialDiagnos<wbr>ticAt> &Notes) const {<br>
  EvaluatedStmt *Eval = ensureEvaluatedStmt();<br>
... // .... skipped comment ...<br>
  if (Eval->WasEvaluated)              ///             <<<<< Here non-NULL pointer is blindly assumed<br>
    return Eval->Evaluated.isUninit() ? nullptr : &Eval->Evaluated;<br>
<br>
  const auto *Init = cast<Expr>(Eval->Value);<br>
  assert(!Init->isValueDependent<wbr>());   ///     <<<< Here is just assert which only fires in debug mode<br>
<br>
  if (Eval->IsEvaluating) {<br>
...<br>
<br>
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.<br>
<br>
Now for the simple varDecl->evaluateValue() we have at least (+ maybe something else?)<br>
                       (varDecl->getAnyInitializer() != nullptr)        /// This<br>
                        !init->getType().isNull() &&                          /// and this<br>
                        !init->isValueDependent() &&<br>
                        !init->isTypeDependent() &&<br>
                        !varDecl->getType().isNull() &&                   /// and this   ---  seem reasonable to have outside the call, but I am not that sure about all others<br>
                        !varDecl->getType()->isDepende<wbr>ntType() &&<br>
<span>                        varDecl->ensureEvaluatedStmt() != nullptr &&<br>
                        varDecl->ensureEvaluatedStmt()<wbr>->Value != nullptr)<br>
<br>
</span>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.<br>
<br>
I am ready to prepare patch for review based on agreed decision.<br>
<br>
Regards,<br>
Serge.<br>
<br>
<br>
05.07.2017, 22:47, "Alex L" <<a href="mailto:arphaman@gmail.com" target="_blank">arphaman@gmail.com</a>>:<br>
<div class="m_5363470265474088868HOEnZb"><div class="m_5363470265474088868h5">> 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.<br>
><br>
> On 5 July 2017 at 09:42, Serge Preis via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>> wrote:<br>
>> Hello,<br>
>><br>
>> I encountered the following issue in lib/AST/ExprConstant.cpp:<br>
>><br>
>> In function CheckConstantExpr there is a code:<br>
>><br>
>>   if (Value.isUnion() && Value.getUnionField()) {<br>
>>     return CheckConstantExpression(Info, DiagLoc,<br>
>>                                    Value.getUnionField()->getTyp<wbr>e(),<br>
>>                                    Value.getUnionValue());<br>
>>   }<br>
>>   if (Value.isStruct()) {<br>
>>     RecordDecl *RD = Type->castAs<RecordType>()->ge<wbr>tDecl();           ////      <<<<<<    The problematic line<br>
>>     if (const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) {<br>
>>       unsigned BaseIndex = 0;<br>
>>       for (CXXRecordDecl::base_class_con<wbr>st_iterator I = CD->bases_begin(),<br>
>>              End = CD->bases_end(); I != End; ++I, ++BaseIndex) {<br>
>>         if (!CheckConstantExpression(Info<wbr>, DiagLoc, I->getType(),<br>
>>                                      Value.getStructBase(BaseIndex<wbr>)))<br>
>>           return false;<br>
>><br>
>> The problematic line causes a crash because Type cannot be cast to RecordType.<br>
>><br>
>> 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.<br>
>> I will definitely impelement workaround in my code, but I would also like to investingate and fix this issue in clang.<br>
>><br>
>> Regards,<br>
>> Serge.<br>
>><br>
>> ----- useful info ----<br>
>><br>
>> The code which triggering this behavior looks like the following:<br>
>> ...<br>
>>     template<class T><br>
>>     void DoTestMax() {<br>
>>         const T max = Max();<br>
>> ...<br>
>><br>
>> I am trying to access and print constant initializer for 'max' variable under following checks:<br>
>>             } else if (auto* varDecl = llvm::dyn_cast<clang::VarDecl><wbr>(decl)) {<br>
>>                 if (!clang::isa<clang::ParmVarDec<wbr>l>(varDecl) && (varDecl->isConstexpr() || varDecl->getType().isConstQual<wbr>ified())) {<br>
>>                     const clang::Expr* init = varDecl->getAnyInitializer();<br>
>>                     if (init != nullptr &&<br>
>>                         !init->getType().isNull() &&<br>
>>                         !init->isValueDependent() &&<br>
>>                         varDecl->ensureEvaluatedStmt() != nullptr &&<br>
>>                         varDecl->ensureEvaluatedStmt()<wbr>->Value != nullptr)<br>
>>                     {<br>
>>                         const clang::APValue* val = varDecl->evaluateValue();  ///  <<< Problem is here<br>
>><br>
>> The relevant stack for debug clang (trunk) looks like below:<br>
>> #3  0x00007ffff6bb2ca2 in __GI___assert_fail (assertion=0x2661ae0 "isa<X>(Val) && \"cast<Ty>() argument of incompatible type!\"",  file=0x2661aa0 "/home/spreis/LLVM/latest/llvm<wbr>/include/llvm/Support/Casting.<wbr>h", line=241,<br>
>>     function=0x2663de0 <std::enable_if<!llvm::is_simp<wbr>le_type<clang::QualType>::valu<wbr>e, llvm::cast_retty<clang::Record<wbr>Type, clang::QualType const>::ret_type>::type llvm::cast<clang::RecordType, clang::QualType>(clang::QualTy<wbr>pe const&)::__PRETTY_FUNCTION__> "typename std::enable_if<(! llvm::is_simple_type<Y>::value<wbr>), typename llvm::cast_retty<X, const Y>::ret_type>::type llvm::cast(const Y&) [with X = clang::RecordType; Y = clang::QualType; typename std::"...)<br>
>>     at assert.c:101<br>
>> #4  0x00000000010cf75e in llvm::cast<clang::RecordType, clang::QualType> (Val=...)<br>
>>     at /home/spreis/LLVM/latest/llvm/<wbr>include/llvm/Support/Casting.h<wbr>:241<br>
>> #5  0x00000000010ce4fa in clang::Type::castAs<clang::Rec<wbr>ordType> (this=0x554a880)<br>
>>     at /home/spreis/LLVM/latest/llvm/<wbr>tools/clang/include/clang/AST/<wbr>TypeNodes.def:122<br>
>> #6  0x0000000001c0b810 in CheckConstantExpression (Info=..., DiagLoc=...,   Type=..., Value=...)<br>
>>     at /home/spreis/LLVM/latest/llvm/<wbr>tools/clang/lib/AST/ExprConsta<wbr>nt.cpp:1737<br>
>> #7  0x0000000001c2f1b0 in clang::Expr::EvaluateAsInitial<wbr>izer (this=0x554ab50, Value=..., Ctx=..., VD=0x554a9d8, Notes=...)<br>
>>     at /home/spreis/LLVM/latest/llvm/<wbr>tools/clang/lib/AST/ExprConsta<wbr>nt.cpp:10079<br>
>> #8  0x0000000001b923fa in clang::VarDecl::evaluateValue (this=0x554a9d8, Notes=...)<br>
>>     at /home/spreis/LLVM/latest/llvm/<wbr>tools/clang/lib/AST/Decl.cpp:2<wbr>172<br>
>> #9  0x0000000001b9229c in clang::VarDecl::evaluateValue (this=0x554a9d8)<br>
>>     at /home/spreis/LLVM/latest/llvm/<wbr>tools/clang/lib/AST/Decl.cpp:2<wbr>146<br>
>><br>
>> The var:<br>
>> (gdb) frame 9<br>
>> 2146      return evaluateValue(Notes);<br>
>> (gdb) call this->dump()<br>
>> VarDecl 0x554a9d8 <..snip..snip> referenced max 'const T' cinit<br>
>> `-CallExpr 0x554ab50 <col:23, col:27> '::NPrivate::TMax':'struct NPrivate::TMax'<br>
>>   `-ImplicitCastExpr 0x554ab38 <col:23> '::NPrivate::TMax (*)(void) noexcept' <FunctionToPointerDecay><br>
>>     `-DeclRefExpr 0x554aab8 <col:23> '::NPrivate::TMax (void) noexcept' lvalue Function 0x3f82c28 'Max' '::NPrivate::TMax (void) noexcept'<br>
>><br>
>> The type:<br>
>> (gdb) frame 6<br>
>> 1737        RecordDecl *RD = Type->castAs<RecordType>()->ge<wbr>tDecl();<br>
>> (gdb) call Type.dump()<br>
>> QualType 0x554a881 'const T' const<br>
>> `-TemplateTypeParmType 0x554a880 'T' dependent depth 0 index 0<br>
>>   `-TemplateTypeParm 0x554a840 'T'<br>
>><br>
>> ______________________________<wbr>_________________<br>
>> cfe-dev mailing list<br>
>> <a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a><br>
>> <a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-dev</a><br>
______________________________<wbr>_________________<br>
cfe-dev mailing list<br>
<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-dev</a><br>
</div></div></blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="m_5363470265474088868gmail_signature" data-smartmail="gmail_signature"><div dir="ltr"><div><br></div><div>Mikhail Ramalho.</div></div></div>
</div></div>