[clang] 76c0092 - Ensure that checkInitIsICE is called exactly once for every variable

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Mon Oct 26 17:00:09 PDT 2020


Fixed in a5c7b46862ec0531964eb52329cdf009862abecf.

On Mon, 26 Oct 2020 at 15:59, Richard Smith <richard at metafoo.co.uk> wrote:

> Reduces to:
>
> int d;
> int &h = d;
> double e = h;
>
> ... but only fails under -fms-compatibility.
>
> On Mon, 26 Oct 2020 at 13:46, Nico Weber <thakis at chromium.org> wrote:
>
>> The original snippet:
>>
>>   const int64_t& kGraceMs =
>>       AffiliationFetchThrottler::kGracePeriodAfterReconnectMs;
>>   ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween(
>>       true, kGraceMs * (1 - kPolicy.jitter_factor), kGraceMs));
>>
>> kGracePeriod is declared here
>> https://source.chromium.org/chromium/chromium/src/+/master:components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler.h;l=109?q=kGracePeriodAfterReconnectMs&ss=chromium
>> as a class-level
>>
>>   static const int64_t kGracePeriodAfterReconnectMs;
>>
>> which is then defined in some .cc file where the snippet above can't see
>> the value.
>>
>> On Mon, Oct 26, 2020 at 4:40 PM Nico Weber <thakis at chromium.org> wrote:
>>
>>> Hi Richard,
>>>
>>> this makes clang assert when building chromium/win.
>>> https://bugs.chromium.org/p/chromium/issues/detail?id=1142009#c4 has a
>>> reduced repro. Could you take a look?
>>>
>>> Thanks,
>>> Nico
>>>
>>> On Mon, Oct 19, 2020 at 10:04 PM Richard Smith via cfe-commits <
>>> cfe-commits at lists.llvm.org> wrote:
>>>
>>>>
>>>> Author: Richard Smith
>>>> Date: 2020-10-19T19:04:04-07:00
>>>> New Revision: 76c0092665867a6defcd328ba0d0d976eb65d991
>>>>
>>>> URL:
>>>> https://github.com/llvm/llvm-project/commit/76c0092665867a6defcd328ba0d0d976eb65d991
>>>> DIFF:
>>>> https://github.com/llvm/llvm-project/commit/76c0092665867a6defcd328ba0d0d976eb65d991.diff
>>>>
>>>> LOG: Ensure that checkInitIsICE is called exactly once for every
>>>> variable
>>>> for which it matters.
>>>>
>>>> This is a step towards separating checking for a constant initializer
>>>> (in which std::is_constant_evaluated returns true) and any other
>>>> evaluation of a variable initializer (in which it returns false).
>>>>
>>>> Added:
>>>>
>>>>
>>>> Modified:
>>>>     clang/include/clang/AST/Decl.h
>>>>     clang/include/clang/Serialization/ASTRecordWriter.h
>>>>     clang/lib/AST/ComparisonCategories.cpp
>>>>     clang/lib/AST/Decl.cpp
>>>>     clang/lib/AST/ExprConstant.cpp
>>>>     clang/lib/CodeGen/ItaniumCXXABI.cpp
>>>>     clang/lib/Sema/SemaDecl.cpp
>>>>     clang/lib/Sema/SemaDeclCXX.cpp
>>>>     clang/lib/Serialization/ASTReaderDecl.cpp
>>>>     clang/lib/Serialization/ASTWriter.cpp
>>>>     clang/lib/Serialization/ASTWriterDecl.cpp
>>>>     clang/test/CodeGen/enable_if.c
>>>>     clang/test/OpenMP/threadprivate_codegen.cpp
>>>>     clang/test/Sema/enable_if.c
>>>>     clang/test/SemaCXX/constant-expression.cpp
>>>>     clang/test/SemaCXX/i-c-e-cxx.cpp
>>>>
>>>> Removed:
>>>>
>>>>
>>>>
>>>>
>>>> ################################################################################
>>>> diff  --git a/clang/include/clang/AST/Decl.h
>>>> b/clang/include/clang/AST/Decl.h
>>>> index eae09832160d..e309819400f1 100644
>>>> --- a/clang/include/clang/AST/Decl.h
>>>> +++ b/clang/include/clang/AST/Decl.h
>>>> @@ -807,10 +807,6 @@ struct EvaluatedStmt {
>>>>    /// integral constant expression.
>>>>    bool CheckedICE : 1;
>>>>
>>>> -  /// Whether we are checking whether this statement is an
>>>> -  /// integral constant expression.
>>>> -  bool CheckingICE : 1;
>>>> -
>>>>    /// Whether this statement is an integral constant expression,
>>>>    /// or in C++11, whether the statement is a constant expression. Only
>>>>    /// valid if CheckedICE is true.
>>>> @@ -828,7 +824,7 @@ struct EvaluatedStmt {
>>>>
>>>>    EvaluatedStmt()
>>>>        : WasEvaluated(false), IsEvaluating(false), CheckedICE(false),
>>>> -        CheckingICE(false), IsICE(false),
>>>> HasConstantDestruction(false) {}
>>>> +        IsICE(false), HasConstantDestruction(false) {}
>>>>  };
>>>>
>>>>  /// Represents a variable declaration or definition.
>>>> @@ -1263,14 +1259,15 @@ class VarDecl : public DeclaratorDecl, public
>>>> Redeclarable<VarDecl> {
>>>>    /// constant expression, according to the relevant language standard.
>>>>    /// This only checks properties of the declaration, and does not
>>>> check
>>>>    /// whether the initializer is in fact a constant expression.
>>>> -  bool mightBeUsableInConstantExpressions(ASTContext &C) const;
>>>> +  bool mightBeUsableInConstantExpressions(const ASTContext &C) const;
>>>>
>>>>    /// Determine whether this variable's value can be used in a
>>>>    /// constant expression, according to the relevant language standard,
>>>>    /// including checking whether it was initialized by a constant
>>>> expression.
>>>> -  bool isUsableInConstantExpressions(ASTContext &C) const;
>>>> +  bool isUsableInConstantExpressions(const ASTContext &C) const;
>>>>
>>>>    EvaluatedStmt *ensureEvaluatedStmt() const;
>>>> +  EvaluatedStmt *getEvaluatedStmt() const;
>>>>
>>>>    /// Attempt to evaluate the value of the initializer attached to this
>>>>    /// declaration, and produce notes explaining why it cannot be
>>>> evaluated or is
>>>> @@ -1305,7 +1302,7 @@ class VarDecl : public DeclaratorDecl, public
>>>> Redeclarable<VarDecl> {
>>>>
>>>>    /// Determine whether the value of the initializer attached to this
>>>>    /// declaration is an integral constant expression.
>>>> -  bool checkInitIsICE() const;
>>>> +  bool checkInitIsICE(SmallVectorImpl<PartialDiagnosticAt> &Notes)
>>>> const;
>>>>
>>>>    void setInitStyle(InitializationStyle Style) {
>>>>      VarDeclBits.InitStyle = Style;
>>>>
>>>> diff  --git a/clang/include/clang/Serialization/ASTRecordWriter.h
>>>> b/clang/include/clang/Serialization/ASTRecordWriter.h
>>>> index edfcd9c52e2e..e362463b2309 100644
>>>> --- a/clang/include/clang/Serialization/ASTRecordWriter.h
>>>> +++ b/clang/include/clang/Serialization/ASTRecordWriter.h
>>>> @@ -266,6 +266,9 @@ class ASTRecordWriter
>>>>
>>>>    void AddCXXDefinitionData(const CXXRecordDecl *D);
>>>>
>>>> +  /// Emit information about the initializer of a VarDecl.
>>>> +  void AddVarDeclInit(const VarDecl *VD);
>>>> +
>>>>    /// Write an OMPTraitInfo object.
>>>>    void writeOMPTraitInfo(const OMPTraitInfo *TI);
>>>>
>>>>
>>>> diff  --git a/clang/lib/AST/ComparisonCategories.cpp
>>>> b/clang/lib/AST/ComparisonCategories.cpp
>>>> index 6b6826c02a12..896050482644 100644
>>>> --- a/clang/lib/AST/ComparisonCategories.cpp
>>>> +++ b/clang/lib/AST/ComparisonCategories.cpp
>>>> @@ -42,7 +42,7 @@ clang::getComparisonCategoryForBuiltinCmp(QualType T)
>>>> {
>>>>
>>>>  bool ComparisonCategoryInfo::ValueInfo::hasValidIntValue() const {
>>>>    assert(VD && "must have var decl");
>>>> -  if (!VD->checkInitIsICE())
>>>> +  if (!VD->isUsableInConstantExpressions(VD->getASTContext()))
>>>>      return false;
>>>>
>>>>    // Before we attempt to get the value of the first field, ensure
>>>> that we
>>>>
>>>> diff  --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
>>>> index a6c7f30528eb..ee7f51c5218e 100644
>>>> --- a/clang/lib/AST/Decl.cpp
>>>> +++ b/clang/lib/AST/Decl.cpp
>>>> @@ -2277,7 +2277,7 @@ void VarDecl::setInit(Expr *I) {
>>>>    Init = I;
>>>>  }
>>>>
>>>> -bool VarDecl::mightBeUsableInConstantExpressions(ASTContext &C) const {
>>>> +bool VarDecl::mightBeUsableInConstantExpressions(const ASTContext &C)
>>>> const {
>>>>    const LangOptions &Lang = C.getLangOpts();
>>>>
>>>>    if (!Lang.CPlusPlus)
>>>> @@ -2312,7 +2312,7 @@ bool
>>>> VarDecl::mightBeUsableInConstantExpressions(ASTContext &C) const {
>>>>    return Lang.CPlusPlus11 && isConstexpr();
>>>>  }
>>>>
>>>> -bool VarDecl::isUsableInConstantExpressions(ASTContext &Context) const
>>>> {
>>>> +bool VarDecl::isUsableInConstantExpressions(const ASTContext &Context)
>>>> const {
>>>>    // C++2a [expr.const]p3:
>>>>    //   A variable is usable in constant expressions after its
>>>> initializing
>>>>    //   declaration is encountered...
>>>> @@ -2325,7 +2325,7 @@ bool
>>>> VarDecl::isUsableInConstantExpressions(ASTContext &Context) const {
>>>>    if (!DefVD->mightBeUsableInConstantExpressions(Context))
>>>>      return false;
>>>>    //   ... and its initializer is a constant initializer.
>>>> -  return DefVD->checkInitIsICE();
>>>> +  return DefVD->isInitKnownICE() && DefVD->isInitICE();
>>>>  }
>>>>
>>>>  /// Convert the initializer for this declaration to the elaborated
>>>> EvaluatedStmt
>>>> @@ -2345,6 +2345,10 @@ EvaluatedStmt *VarDecl::ensureEvaluatedStmt()
>>>> const {
>>>>    return Eval;
>>>>  }
>>>>
>>>> +EvaluatedStmt *VarDecl::getEvaluatedStmt() const {
>>>> +  return Init.dyn_cast<EvaluatedStmt *>();
>>>> +}
>>>> +
>>>>  APValue *VarDecl::evaluateValue() const {
>>>>    SmallVector<PartialDiagnosticAt, 8> Notes;
>>>>    return evaluateValue(Notes);
>>>> @@ -2354,19 +2358,17 @@ APValue *VarDecl::evaluateValue(
>>>>      SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
>>>>    EvaluatedStmt *Eval = ensureEvaluatedStmt();
>>>>
>>>> +  const auto *Init = cast<Expr>(Eval->Value);
>>>> +  assert(!Init->isValueDependent());
>>>> +
>>>>    // We only produce notes indicating why an initializer is
>>>> non-constant the
>>>>    // first time it is evaluated. FIXME: The notes won't always be
>>>> emitted the
>>>>    // first time we try evaluation, so might not be produced at all.
>>>>    if (Eval->WasEvaluated)
>>>>      return Eval->Evaluated.isAbsent() ? nullptr : &Eval->Evaluated;
>>>>
>>>> -  const auto *Init = cast<Expr>(Eval->Value);
>>>> -  assert(!Init->isValueDependent());
>>>> -
>>>>    if (Eval->IsEvaluating) {
>>>>      // FIXME: Produce a diagnostic for self-initialization.
>>>> -    Eval->CheckedICE = true;
>>>> -    Eval->IsICE = false;
>>>>      return nullptr;
>>>>    }
>>>>
>>>> @@ -2386,18 +2388,11 @@ APValue *VarDecl::evaluateValue(
>>>>    Eval->IsEvaluating = false;
>>>>    Eval->WasEvaluated = true;
>>>>
>>>> -  // In C++11, we have determined whether the initializer was a
>>>> constant
>>>> -  // expression as a side-effect.
>>>> -  if (getASTContext().getLangOpts().CPlusPlus11 && !Eval->CheckedICE) {
>>>> -    Eval->CheckedICE = true;
>>>> -    Eval->IsICE = Result && Notes.empty();
>>>> -  }
>>>> -
>>>>    return Result ? &Eval->Evaluated : nullptr;
>>>>  }
>>>>
>>>>  APValue *VarDecl::getEvaluatedValue() const {
>>>> -  if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>())
>>>> +  if (EvaluatedStmt *Eval = getEvaluatedStmt())
>>>>      if (Eval->WasEvaluated)
>>>>        return &Eval->Evaluated;
>>>>
>>>> @@ -2405,7 +2400,7 @@ APValue *VarDecl::getEvaluatedValue() const {
>>>>  }
>>>>
>>>>  bool VarDecl::isInitKnownICE() const {
>>>> -  if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>())
>>>> +  if (EvaluatedStmt *Eval = getEvaluatedStmt())
>>>>      return Eval->CheckedICE;
>>>>
>>>>    return false;
>>>> @@ -2417,12 +2412,16 @@ bool VarDecl::isInitICE() const {
>>>>    return Init.get<EvaluatedStmt *>()->IsICE;
>>>>  }
>>>>
>>>> -bool VarDecl::checkInitIsICE() const {
>>>> +bool VarDecl::checkInitIsICE(
>>>> +    SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
>>>>    EvaluatedStmt *Eval = ensureEvaluatedStmt();
>>>> -  if (Eval->CheckedICE)
>>>> -    // We have already checked whether this subexpression is an
>>>> -    // integral constant expression.
>>>> -    return Eval->IsICE;
>>>> +  assert(!Eval->CheckedICE &&
>>>> +         "should check whether var has constant init at most once");
>>>> +  // If we ask for the value before we know whether we have a constant
>>>> +  // initializer, we can compute the wrong value (for example, due to
>>>> +  // std::is_constant_evaluated()).
>>>> +  assert(!Eval->WasEvaluated &&
>>>> +         "already evaluated var value before checking for constant
>>>> init");
>>>>
>>>>    const auto *Init = cast<Expr>(Eval->Value);
>>>>    assert(!Init->isValueDependent());
>>>> @@ -2430,8 +2429,8 @@ bool VarDecl::checkInitIsICE() const {
>>>>    // In C++11, evaluate the initializer to check whether it's a
>>>> constant
>>>>    // expression.
>>>>    if (getASTContext().getLangOpts().CPlusPlus11) {
>>>> -    SmallVector<PartialDiagnosticAt, 8> Notes;
>>>> -    evaluateValue(Notes);
>>>> +    Eval->IsICE = evaluateValue(Notes) && Notes.empty();
>>>> +    Eval->CheckedICE = true;
>>>>      return Eval->IsICE;
>>>>    }
>>>>
>>>> @@ -2439,12 +2438,8 @@ bool VarDecl::checkInitIsICE() const {
>>>>    // out-of-line.  See DR 721 and the discussion in Clang PR
>>>>    // 6206 for details.
>>>>
>>>> -  if (Eval->CheckingICE)
>>>> -    return false;
>>>> -  Eval->CheckingICE = true;
>>>> -
>>>> -  Eval->IsICE = Init->isIntegerConstantExpr(getASTContext());
>>>> -  Eval->CheckingICE = false;
>>>> +  Eval->IsICE = getType()->isIntegralOrEnumerationType() &&
>>>> +                Init->isIntegerConstantExpr(getASTContext());
>>>>    Eval->CheckedICE = true;
>>>>    return Eval->IsICE;
>>>>  }
>>>> @@ -2599,7 +2594,7 @@ bool VarDecl::isNoDestroy(const ASTContext &Ctx)
>>>> const {
>>>>
>>>>  QualType::DestructionKind
>>>>  VarDecl::needsDestruction(const ASTContext &Ctx) const {
>>>> -  if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>())
>>>> +  if (EvaluatedStmt *Eval = getEvaluatedStmt())
>>>>      if (Eval->HasConstantDestruction)
>>>>        return QualType::DK_none;
>>>>
>>>>
>>>> diff  --git a/clang/lib/AST/ExprConstant.cpp
>>>> b/clang/lib/AST/ExprConstant.cpp
>>>> index 7afc44dffffe..3014f948f9b1 100644
>>>> --- a/clang/lib/AST/ExprConstant.cpp
>>>> +++ b/clang/lib/AST/ExprConstant.cpp
>>>> @@ -3278,12 +3278,17 @@ static bool evaluateVarDeclInit(EvalInfo &Info,
>>>> const Expr *E,
>>>>      return false;
>>>>    }
>>>>
>>>> -  // Check that the variable is actually usable in constant
>>>> expressions.
>>>> -  if (!VD->checkInitIsICE()) {
>>>> -    Info.CCEDiag(E, diag::note_constexpr_var_init_non_constant,
>>>> -                 Notes.size() + 1) << VD;
>>>> +  // Check that the variable is actually usable in constant
>>>> expressions. For a
>>>> +  // const integral variable or a reference, we might have a
>>>> non-constant
>>>> +  // initializer that we can nonetheless evaluate the initializer for.
>>>> Such
>>>> +  // variables are not usable in constant expressions.
>>>> +  //
>>>> +  // FIXME: It would be cleaner to check
>>>> VD->isUsableInConstantExpressions
>>>> +  // here, but that regresses diagnostics for things like reading from
>>>> a
>>>> +  // volatile constexpr variable.
>>>> +  if (VD->isInitKnownICE() && !VD->isInitICE()) {
>>>> +    Info.CCEDiag(E, diag::note_constexpr_var_init_non_constant, 1) <<
>>>> VD;
>>>>      NoteLValueLocation(Info, Base);
>>>> -    Info.addNotes(Notes);
>>>>    }
>>>>
>>>>    // Never use the initializer of a weak variable, not even for
>>>> constant
>>>> @@ -3298,11 +3303,6 @@ static bool evaluateVarDeclInit(EvalInfo &Info,
>>>> const Expr *E,
>>>>    return true;
>>>>  }
>>>>
>>>> -static bool IsConstNonVolatile(QualType T) {
>>>> -  Qualifiers Quals = T.getQualifiers();
>>>> -  return Quals.hasConst() && !Quals.hasVolatile();
>>>> -}
>>>> -
>>>>  /// Get the base index of the given base class within an APValue
>>>> representing
>>>>  /// the given derived class.
>>>>  static unsigned getBaseIndex(const CXXRecordDecl *Derived,
>>>> @@ -8114,6 +8114,12 @@ bool LValueExprEvaluator::VisitVarDecl(const
>>>> Expr *E, const VarDecl *VD) {
>>>>      return Success(VD);
>>>>    }
>>>>
>>>> +  if (!Info.getLangOpts().CPlusPlus11) {
>>>> +    Info.CCEDiag(E, diag::note_constexpr_ltor_non_integral, 1)
>>>> +        << VD << VD->getType();
>>>> +    Info.Note(VD->getLocation(), diag::note_declared_at);
>>>> +  }
>>>> +
>>>>    APValue *V;
>>>>    if (!evaluateVarDeclInit(Info, E, VD, Frame, Version, V))
>>>>      return false;
>>>> @@ -15030,30 +15036,12 @@ static ICEDiag CheckICE(const Expr* E, const
>>>> ASTContext &Ctx) {
>>>>    case Expr::DeclRefExprClass: {
>>>>      if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl()))
>>>>        return NoDiag();
>>>> -    const ValueDecl *D = cast<DeclRefExpr>(E)->getDecl();
>>>> -    if (Ctx.getLangOpts().CPlusPlus &&
>>>> -        D && IsConstNonVolatile(D->getType())) {
>>>> -      // Parameter variables are never constants.  Without this check,
>>>> -      // getAnyInitializer() can find a default argument, which leads
>>>> -      // to chaos.
>>>> -      if (isa<ParmVarDecl>(D))
>>>> -        return ICEDiag(IK_NotICE, cast<DeclRefExpr>(E)->getLocation());
>>>> -
>>>> +    const VarDecl *VD =
>>>> dyn_cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
>>>> +    if (VD && VD->isUsableInConstantExpressions(Ctx)) {
>>>>        // C++ 7.1.5.1p2
>>>>        //   A variable of non-volatile const-qualified integral or
>>>> enumeration
>>>>        //   type initialized by an ICE can be used in ICEs.
>>>> -      if (const VarDecl *Dcl = dyn_cast<VarDecl>(D)) {
>>>> -        if (!Dcl->getType()->isIntegralOrEnumerationType())
>>>> -          return ICEDiag(IK_NotICE,
>>>> cast<DeclRefExpr>(E)->getLocation());
>>>> -
>>>> -        const VarDecl *VD;
>>>> -        // Look for a declaration of this variable that has an
>>>> initializer, and
>>>> -        // check whether it is an ICE.
>>>> -        if (Dcl->getAnyInitializer(VD) && !VD->isWeak() &&
>>>> VD->checkInitIsICE())
>>>> -          return NoDiag();
>>>> -        else
>>>> -          return ICEDiag(IK_NotICE,
>>>> cast<DeclRefExpr>(E)->getLocation());
>>>> -      }
>>>> +      return NoDiag();
>>>>      }
>>>>      return ICEDiag(IK_NotICE, E->getBeginLoc());
>>>>    }
>>>>
>>>> diff  --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp
>>>> b/clang/lib/CodeGen/ItaniumCXXABI.cpp
>>>> index cfb736ce0ff1..40cd5c54185f 100644
>>>> --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
>>>> +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
>>>> @@ -361,8 +361,9 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
>>>>        return !VD->needsDestruction(getContext()) &&
>>>> InitDecl->evaluateValue();
>>>>
>>>>      // Otherwise, we need a thread wrapper unless we know that every
>>>> -    // translation unit will emit the value as a constant. We rely on
>>>> -    // ICE-ness not varying between translation units, which isn't
>>>> actually
>>>> +    // translation unit will emit the value as a constant. We rely on
>>>> the
>>>> +    // variable being constant-initialized in every translation unit
>>>> if it's
>>>> +    // constant-initialized in any translation unit, which isn't
>>>> actually
>>>>      // guaranteed by the standard but is necessary for sanity.
>>>>      return InitDecl->isInitKnownICE() && InitDecl->isInitICE();
>>>>    }
>>>>
>>>> diff  --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
>>>> index 481b48e21942..1a27667fc106 100644
>>>> --- a/clang/lib/Sema/SemaDecl.cpp
>>>> +++ b/clang/lib/Sema/SemaDecl.cpp
>>>> @@ -12958,18 +12958,14 @@ void
>>>> Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
>>>>
>>>>    // All the following checks are C++ only.
>>>>    if (!getLangOpts().CPlusPlus) {
>>>> -      // If this variable must be emitted, add it as an initializer
>>>> for the
>>>> -      // current module.
>>>> -     if (Context.DeclMustBeEmitted(var) && !ModuleScopes.empty())
>>>> -       Context.addModuleInitializer(ModuleScopes.back().Module, var);
>>>> -     return;
>>>> +    // If this variable must be emitted, add it as an initializer for
>>>> the
>>>> +    // current module.
>>>> +    if (Context.DeclMustBeEmitted(var) && !ModuleScopes.empty())
>>>> +      Context.addModuleInitializer(ModuleScopes.back().Module, var);
>>>> +    return;
>>>>    }
>>>>
>>>> -  if (auto *DD = dyn_cast<DecompositionDecl>(var))
>>>> -    CheckCompleteDecompositionDeclaration(DD);
>>>> -
>>>>    QualType type = var->getType();
>>>> -  if (type->isDependentType()) return;
>>>>
>>>>    if (var->hasAttr<BlocksAttr>())
>>>>      getCurFunction()->addByrefBlockVar(var);
>>>> @@ -12978,79 +12974,86 @@ void
>>>> Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
>>>>    bool IsGlobal = GlobalStorage && !var->isStaticLocal();
>>>>    QualType baseType = Context.getBaseElementType(type);
>>>>
>>>> -  if (Init && !Init->isValueDependent()) {
>>>> -    if (var->isConstexpr()) {
>>>> -      SmallVector<PartialDiagnosticAt, 8> Notes;
>>>> -      if (!var->evaluateValue(Notes) || !var->isInitICE()) {
>>>> -        SourceLocation DiagLoc = var->getLocation();
>>>> -        // If the note doesn't add any useful information other than a
>>>> source
>>>> -        // location, fold it into the primary diagnostic.
>>>> -        if (Notes.size() == 1 && Notes[0].second.getDiagID() ==
>>>> -              diag::note_invalid_subexpr_in_const_expr) {
>>>> -          DiagLoc = Notes[0].first;
>>>> -          Notes.clear();
>>>> -        }
>>>> -        Diag(DiagLoc, diag::err_constexpr_var_requires_const_init)
>>>> -          << var << Init->getSourceRange();
>>>> -        for (unsigned I = 0, N = Notes.size(); I != N; ++I)
>>>> -          Diag(Notes[I].first, Notes[I].second);
>>>> -      }
>>>> -    } else if (var->mightBeUsableInConstantExpressions(Context)) {
>>>> -      // Check whether the initializer of a const variable of integral
>>>> or
>>>> -      // enumeration type is an ICE now, since we can't tell whether
>>>> it was
>>>> -      // initialized by a constant expression if we check later.
>>>> -      var->checkInitIsICE();
>>>> -    }
>>>> -
>>>> -    // Don't emit further diagnostics about constexpr globals since
>>>> they
>>>> -    // were just diagnosed.
>>>> -    if (!var->isConstexpr() && GlobalStorage &&
>>>> var->hasAttr<ConstInitAttr>()) {
>>>> -      // FIXME: Need strict checking in C++03 here.
>>>> -      bool DiagErr = getLangOpts().CPlusPlus11
>>>> -          ? !var->checkInitIsICE() : !checkConstInit();
>>>> -      if (DiagErr) {
>>>> -        auto *Attr = var->getAttr<ConstInitAttr>();
>>>> -        Diag(var->getLocation(),
>>>> diag::err_require_constant_init_failed)
>>>> -          << Init->getSourceRange();
>>>> -        Diag(Attr->getLocation(),
>>>> -             diag::note_declared_required_constant_init_here)
>>>> -            << Attr->getRange() << Attr->isConstinit();
>>>> -        if (getLangOpts().CPlusPlus11) {
>>>> -          APValue Value;
>>>> -          SmallVector<PartialDiagnosticAt, 8> Notes;
>>>> -          Init->EvaluateAsInitializer(Value, getASTContext(), var,
>>>> Notes);
>>>> -          for (auto &it : Notes)
>>>> -            Diag(it.first, it.second);
>>>> -        } else {
>>>> -          Diag(CacheCulprit->getExprLoc(),
>>>> -               diag::note_invalid_subexpr_in_const_expr)
>>>> -              << CacheCulprit->getSourceRange();
>>>> -        }
>>>> +  // Check whether the initializer is sufficiently constant.
>>>> +  if (!type->isDependentType() && Init && !Init->isValueDependent() &&
>>>> +      (GlobalStorage || var->isConstexpr() ||
>>>> +       var->mightBeUsableInConstantExpressions(Context))) {
>>>> +    // If this variable might have a constant initializer or might be
>>>> usable in
>>>> +    // constant expressions, check whether or not it actually is now.
>>>> We can't
>>>> +    // do this lazily, because the result might depend on things that
>>>> change
>>>> +    // later, such as which constexpr functions happen to be defined.
>>>> +    SmallVector<PartialDiagnosticAt, 8> Notes;
>>>> +    bool HasConstInit = var->checkInitIsICE(Notes);
>>>> +
>>>> +    // Prior to C++11, in contexts where a constant initializer is
>>>> required,
>>>> +    // additional kinds of constant expression are permitted beyond
>>>> ICEs, as
>>>> +    // described in [expr.const]p2-6.
>>>> +    // FIXME: Stricter checking for these rules would be useful for
>>>> constinit /
>>>> +    // -Wglobal-constructors.
>>>> +    if (!getLangOpts().CPlusPlus11 && !HasConstInit) {
>>>> +      HasConstInit = checkConstInit();
>>>> +      Notes.clear();
>>>> +      if (CacheCulprit) {
>>>> +        Notes.emplace_back(CacheCulprit->getExprLoc(),
>>>> +
>>>>  PDiag(diag::note_invalid_subexpr_in_const_expr));
>>>> +        Notes.back().second << CacheCulprit->getSourceRange();
>>>>        }
>>>>      }
>>>> -    else if (!var->isConstexpr() && IsGlobal &&
>>>> -             !getDiagnostics().isIgnored(diag::warn_global_constructor,
>>>> -                                    var->getLocation())) {
>>>> +
>>>> +    if (HasConstInit) {
>>>> +      // FIXME: Consider replacing the initializer with a ConstantExpr.
>>>> +    } else if (var->isConstexpr()) {
>>>> +      SourceLocation DiagLoc = var->getLocation();
>>>> +      // If the note doesn't add any useful information other than a
>>>> source
>>>> +      // location, fold it into the primary diagnostic.
>>>> +      if (Notes.size() == 1 && Notes[0].second.getDiagID() ==
>>>> +
>>>>  diag::note_invalid_subexpr_in_const_expr) {
>>>> +        DiagLoc = Notes[0].first;
>>>> +        Notes.clear();
>>>> +      }
>>>> +      Diag(DiagLoc, diag::err_constexpr_var_requires_const_init)
>>>> +          << var << Init->getSourceRange();
>>>> +      for (unsigned I = 0, N = Notes.size(); I != N; ++I)
>>>> +        Diag(Notes[I].first, Notes[I].second);
>>>> +    } else if (GlobalStorage && var->hasAttr<ConstInitAttr>()) {
>>>> +      auto *Attr = var->getAttr<ConstInitAttr>();
>>>> +      Diag(var->getLocation(), diag::err_require_constant_init_failed)
>>>> +          << Init->getSourceRange();
>>>> +      Diag(Attr->getLocation(),
>>>> diag::note_declared_required_constant_init_here)
>>>> +          << Attr->getRange() << Attr->isConstinit();
>>>> +      for (auto &it : Notes)
>>>> +        Diag(it.first, it.second);
>>>> +    } else if (IsGlobal &&
>>>> +
>>>>  !getDiagnostics().isIgnored(diag::warn_global_constructor,
>>>> +                                           var->getLocation())) {
>>>>        // Warn about globals which don't have a constant initializer.
>>>> Don't
>>>>        // warn about globals with a non-trivial destructor because we
>>>> already
>>>>        // warned about them.
>>>>        CXXRecordDecl *RD = baseType->getAsCXXRecordDecl();
>>>>        if (!(RD && !RD->hasTrivialDestructor())) {
>>>> +        // checkConstInit() here permits trivial default
>>>> initialization even in
>>>> +        // C++11 onwards, where such an initializer is not a constant
>>>> initializer
>>>> +        // but nonetheless doesn't require a global constructor.
>>>>          if (!checkConstInit())
>>>>            Diag(var->getLocation(), diag::warn_global_constructor)
>>>> -            << Init->getSourceRange();
>>>> +              << Init->getSourceRange();
>>>>        }
>>>>      }
>>>>    }
>>>>
>>>>    // Require the destructor.
>>>> -  if (const RecordType *recordType = baseType->getAs<RecordType>())
>>>> -    FinalizeVarWithDestructor(var, recordType);
>>>> +  if (!type->isDependentType())
>>>> +    if (const RecordType *recordType = baseType->getAs<RecordType>())
>>>> +      FinalizeVarWithDestructor(var, recordType);
>>>>
>>>>    // If this variable must be emitted, add it as an initializer for
>>>> the current
>>>>    // module.
>>>>    if (Context.DeclMustBeEmitted(var) && !ModuleScopes.empty())
>>>>      Context.addModuleInitializer(ModuleScopes.back().Module, var);
>>>> +
>>>> +  // Build the bindings if this is a structured binding declaration.
>>>> +  if (auto *DD = dyn_cast<DecompositionDecl>(var))
>>>> +    CheckCompleteDecompositionDeclaration(DD);
>>>>  }
>>>>
>>>>  /// Determines if a variable's alignment is dependent.
>>>>
>>>> diff  --git a/clang/lib/Sema/SemaDeclCXX.cpp
>>>> b/clang/lib/Sema/SemaDeclCXX.cpp
>>>> index cbcaf3cc4360..72dfa37c321e 100644
>>>> --- a/clang/lib/Sema/SemaDeclCXX.cpp
>>>> +++ b/clang/lib/Sema/SemaDeclCXX.cpp
>>>> @@ -1250,8 +1250,7 @@ static bool checkTupleLikeDecomposition(Sema &S,
>>>>      if (E.isInvalid())
>>>>        return true;
>>>>      RefVD->setInit(E.get());
>>>> -    if (!E.get()->isValueDependent())
>>>> -      RefVD->checkInitIsICE();
>>>> +    S.CheckCompleteVariableDeclaration(RefVD);
>>>>
>>>>      E = S.BuildDeclarationNameExpr(CXXScopeSpec(),
>>>>
>>>> DeclarationNameInfo(B->getDeclName(), Loc),
>>>> @@ -11113,8 +11112,8 @@ QualType
>>>> Sema::CheckComparisonCategoryType(ComparisonCategoryType Kind,
>>>>      // Attempt to diagnose reasons why the STL definition of this type
>>>>      // might be foobar, including it failing to be a constant
>>>> expression.
>>>>      // TODO Handle more ways the lookup or result can be invalid.
>>>> -    if (!VD->isStaticDataMember() || !VD->isConstexpr() ||
>>>> !VD->hasInit() ||
>>>> -        VD->isWeak() || !VD->checkInitIsICE())
>>>> +    if (!VD->isStaticDataMember() ||
>>>> +        !VD->isUsableInConstantExpressions(Context))
>>>>        return UnsupportedSTLError(USS_InvalidMember, MemName, VD);
>>>>
>>>>      // Attempt to evaluate the var decl as a constant expression and
>>>> extract
>>>>
>>>> diff  --git a/clang/lib/Serialization/ASTReaderDecl.cpp
>>>> b/clang/lib/Serialization/ASTReaderDecl.cpp
>>>> index f5a66dc3c2d1..41f2db1ef5f0 100644
>>>> --- a/clang/lib/Serialization/ASTReaderDecl.cpp
>>>> +++ b/clang/lib/Serialization/ASTReaderDecl.cpp
>>>> @@ -1425,8 +1425,8 @@ ASTDeclReader::RedeclarableResult
>>>> ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
>>>>      VD->setInit(Record.readExpr());
>>>>      if (Val > 1) {
>>>>        EvaluatedStmt *Eval = VD->ensureEvaluatedStmt();
>>>> -      Eval->CheckedICE = true;
>>>> -      Eval->IsICE = (Val & 1) != 0;
>>>> +      Eval->CheckedICE = (Val & 2) != 0;
>>>> +      Eval->IsICE = (Val & 3) == 3;
>>>>        Eval->HasConstantDestruction = (Val & 4) != 0;
>>>>      }
>>>>    }
>>>> @@ -4438,10 +4438,11 @@ void ASTDeclReader::UpdateDecl(Decl *D,
>>>>        uint64_t Val = Record.readInt();
>>>>        if (Val && !VD->getInit()) {
>>>>          VD->setInit(Record.readExpr());
>>>> -        if (Val > 1) { // IsInitKnownICE = 1, IsInitNotICE = 2,
>>>> IsInitICE = 3
>>>> +        if (Val != 1) {
>>>>            EvaluatedStmt *Eval = VD->ensureEvaluatedStmt();
>>>> -          Eval->CheckedICE = true;
>>>> -          Eval->IsICE = Val == 3;
>>>> +          Eval->CheckedICE = (Val & 2) != 0;
>>>> +          Eval->IsICE = (Val & 3) == 3;
>>>> +          Eval->HasConstantDestruction = (Val & 4) != 0;
>>>>          }
>>>>        }
>>>>        break;
>>>>
>>>> diff  --git a/clang/lib/Serialization/ASTWriter.cpp
>>>> b/clang/lib/Serialization/ASTWriter.cpp
>>>> index e793e619381b..6056ed623c69 100644
>>>> --- a/clang/lib/Serialization/ASTWriter.cpp
>>>> +++ b/clang/lib/Serialization/ASTWriter.cpp
>>>> @@ -4980,13 +4980,7 @@ void
>>>> ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
>>>>          const VarDecl *VD = cast<VarDecl>(D);
>>>>          Record.push_back(VD->isInline());
>>>>          Record.push_back(VD->isInlineSpecified());
>>>> -        if (VD->getInit()) {
>>>> -          Record.push_back(!VD->isInitKnownICE() ? 1
>>>> -                                                 : (VD->isInitICE() ?
>>>> 3 : 2));
>>>> -          Record.AddStmt(const_cast<Expr*>(VD->getInit()));
>>>> -        } else {
>>>> -          Record.push_back(0);
>>>> -        }
>>>> +        Record.AddVarDeclInit(VD);
>>>>          break;
>>>>        }
>>>>
>>>> @@ -5746,6 +5740,27 @@ void ASTRecordWriter::AddCXXDefinitionData(const
>>>> CXXRecordDecl *D) {
>>>>    }
>>>>  }
>>>>
>>>> +void ASTRecordWriter::AddVarDeclInit(const VarDecl *VD) {
>>>> +  const Expr *Init = VD->getInit();
>>>> +  if (!Init) {
>>>> +    push_back(0);
>>>> +    return;
>>>> +  }
>>>> +
>>>> +  // Bottom two bits are as follows:
>>>> +  //  01 -- initializer not checked for ICE
>>>> +  //  10 -- initializer not ICE
>>>> +  //  11 -- initializer ICE
>>>> +  unsigned Val = 1;
>>>> +  if (EvaluatedStmt *ES = VD->getEvaluatedStmt()) {
>>>> +    if (ES->CheckedICE)
>>>> +      Val = 2 | ES->IsICE;
>>>> +    Val |= (ES->HasConstantDestruction ? 4 : 0);
>>>> +  }
>>>> +  push_back(Val);
>>>> +  writeStmtRef(Init);
>>>> +}
>>>> +
>>>>  void ASTWriter::ReaderInitialized(ASTReader *Reader) {
>>>>    assert(Reader && "Cannot remove chain");
>>>>    assert((!Chain || Chain == Reader) && "Cannot replace chain");
>>>>
>>>> diff  --git a/clang/lib/Serialization/ASTWriterDecl.cpp
>>>> b/clang/lib/Serialization/ASTWriterDecl.cpp
>>>> index 911fcb409547..8778f0c02671 100644
>>>> --- a/clang/lib/Serialization/ASTWriterDecl.cpp
>>>> +++ b/clang/lib/Serialization/ASTWriterDecl.cpp
>>>> @@ -1000,19 +1000,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
>>>>    }
>>>>    Record.push_back(D->getLinkageInternal());
>>>>
>>>> -  if (D->getInit()) {
>>>> -    if (!D->isInitKnownICE())
>>>> -      Record.push_back(1);
>>>> -    else {
>>>> -      Record.push_back(
>>>> -          2 |
>>>> -          (D->isInitICE() ? 1 : 0) |
>>>> -          (D->ensureEvaluatedStmt()->HasConstantDestruction ? 4 : 0));
>>>> -    }
>>>> -    Record.AddStmt(D->getInit());
>>>> -  } else {
>>>> -    Record.push_back(0);
>>>> -  }
>>>> +  Record.AddVarDeclInit(D);
>>>>
>>>>    if (D->hasAttr<BlocksAttr>() && D->getType()->getAsCXXRecordDecl()) {
>>>>      BlockVarCopyInit Init = Writer.Context->getBlockVarCopyInit(D);
>>>>
>>>> diff  --git a/clang/test/CodeGen/enable_if.c
>>>> b/clang/test/CodeGen/enable_if.c
>>>> index 5e9f904fdd3f..1d830ae68f54 100644
>>>> --- a/clang/test/CodeGen/enable_if.c
>>>> +++ b/clang/test/CodeGen/enable_if.c
>>>> @@ -65,19 +65,19 @@ void test3() {
>>>>  }
>>>>
>>>>
>>>> -const int TRUEFACTS = 1;
>>>> +enum { TRUEFACTS = 1 };
>>>>  void qux(int m) __attribute__((overloadable, enable_if(1, ""),
>>>>                                 enable_if(TRUEFACTS, "")));
>>>>  void qux(int m) __attribute__((overloadable, enable_if(1, "")));
>>>>  // CHECK-LABEL: define void @test4
>>>>  void test4() {
>>>> -  // CHECK: store void (i32)*
>>>> @_Z3quxUa9enable_ifIXLi1EEXL_Z9TRUEFACTSEEEi
>>>> +  // CHECK: store void (i32)* @_Z3quxUa9enable_ifIXLi1EEXLi1EEEi
>>>>    void (*p)(int) = qux;
>>>> -  // CHECK: store void (i32)*
>>>> @_Z3quxUa9enable_ifIXLi1EEXL_Z9TRUEFACTSEEEi
>>>> +  // CHECK: store void (i32)* @_Z3quxUa9enable_ifIXLi1EEXLi1EEEi
>>>>    void (*p2)(int) = &qux;
>>>> -  // CHECK: store void (i32)*
>>>> @_Z3quxUa9enable_ifIXLi1EEXL_Z9TRUEFACTSEEEi
>>>> +  // CHECK: store void (i32)* @_Z3quxUa9enable_ifIXLi1EEXLi1EEEi
>>>>    p = qux;
>>>> -  // CHECK: store void (i32)*
>>>> @_Z3quxUa9enable_ifIXLi1EEXL_Z9TRUEFACTSEEEi
>>>> +  // CHECK: store void (i32)* @_Z3quxUa9enable_ifIXLi1EEXLi1EEEi
>>>>    p = &qux;
>>>>  }
>>>>
>>>>
>>>> diff  --git a/clang/test/OpenMP/threadprivate_codegen.cpp
>>>> b/clang/test/OpenMP/threadprivate_codegen.cpp
>>>> index a46bb6907015..2ef6522760ab 100644
>>>> --- a/clang/test/OpenMP/threadprivate_codegen.cpp
>>>> +++ b/clang/test/OpenMP/threadprivate_codegen.cpp
>>>> @@ -598,8 +598,8 @@ int main() {
>>>>    // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]*
>>>> [[RES_ADDR]]
>>>>    // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]],
>>>> [[ST_INT_ST_VAL]]
>>>>    // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
>>>> -  // CHECK-TLS:       [[ST_INT_ST_ADDR:%.*]] = call i32*
>>>> [[ST_INT_ST_TLS_INITD:[^,]+]]
>>>> -  // CHECK-TLS-NEXT:  [[ST_INT_ST_VAL:%.*]] = load i32, i32*
>>>> [[ST_INT_ST_ADDR]]
>>>> +  //
>>>> +  // CHECK-TLS:       [[ST_INT_ST_VAL:%.*]] = load i32, i32*
>>>> [[ST_INT_ST_ADDR:[^,]+]]
>>>>    // CHECK-TLS-NEXT:  [[RES:%.*]] = load i32, i32* [[RES_ADDR]]
>>>>    // CHECK-TLS-NEXT:  [[ADD:%.*]] = add {{.*}} i32 [[RES]],
>>>> [[ST_INT_ST_VAL]]
>>>>    // CHECK-TLS-NEXT:  store i32 [[ADD]], i32* [[RES_ADDR]]
>>>> @@ -620,8 +620,8 @@ int main() {
>>>>    // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]*
>>>> [[RES_ADDR]]
>>>>    // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]],
>>>> [[FLOAT_TO_INT_CONV]]
>>>>    // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
>>>> -  // CHECK-TLS: [[ST_FLOAT_ST_ADDR:%.*]]  = call float*
>>>> [[ST_FLOAT_ST_TLS_INITD:[^,]+]]
>>>> -  // CHECK-TLS-NEXT: [[ST_FLOAT_ST_VAL:%.*]]  = load float, float*
>>>> [[ST_FLOAT_ST_ADDR]]
>>>> +  //
>>>> +  // CHECK-TLS:      [[ST_FLOAT_ST_VAL:%.*]]  = load float, float*
>>>> [[ST_FLOAT_ST_ADDR:[^,]+]]
>>>>    // CHECK-TLS-NEXT: [[FLOAT_TO_INT_CONV:%.*]] = fptosi float
>>>> [[ST_FLOAT_ST_VAL]]  to i32
>>>>    // CHECK-TLS-NEXT: [[RES:%.*]] = load i32, i32* [[RES_ADDR]]
>>>>    // CHECK-TLS-NEXT: [[ADD:%.*]] = add {{.*}} i32 [[RES]],
>>>> [[FLOAT_TO_INT_CONV]]
>>>> @@ -727,14 +727,14 @@ int main() {
>>>>  // CHECK-TLS:   call void [[ARR_X_TLS_INIT]]
>>>>  // CHECK-TLS:   ret [2 x [3 x [[S1]]]]* [[ARR_X]]
>>>>  // CHECK-TLS: }
>>>> -// CHECK-TLS: define {{.*}} i32* [[ST_INT_ST_TLS_INITD]] {{#[0-9]+}}
>>>> comdat {
>>>> -// CHECK-TLS-NOT:   call
>>>> -// CHECK-TLS:   ret i32* [[ST_INT_ST]]
>>>> -// CHECK-TLS: }
>>>> -// CHECK-TLS: define {{.*}} float* [[ST_FLOAT_ST_TLS_INITD]]
>>>> {{#[0-9]+}} comdat {
>>>> -// CHECK-TLS-NOT:   call
>>>> -// CHECK-TLS:   ret float* [[ST_FLOAT_ST]]
>>>> -// CHECK-TLS: }
>>>> +//
>>>> +//
>>>> +//
>>>> +//
>>>> +//
>>>> +//
>>>> +//
>>>> +//
>>>>  // CHECK-TLS: define {{.*}} [[S4]]* [[ST_S4_ST_TLS_INITD]] {{#[0-9]+}}
>>>> comdat {
>>>>  // CHECK-TLS:   call void [[ST_S4_ST_TLS_INIT]]
>>>>  // CHECK-TLS:   ret [[S4]]* [[ST_S4_ST]]
>>>> @@ -874,8 +874,8 @@ int foobar() {
>>>>    // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]*
>>>> [[RES_ADDR]]
>>>>    // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]],
>>>> [[ST_INT_ST_VAL]]
>>>>    // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
>>>> -  // OMP45-TLS:      [[ST_INT_ST_ADDR:%.*]] = call i32*
>>>> [[ST_INT_ST_TLS_INITD]]
>>>> -  // OMP45-TLS-NEXT: [[ST_INT_ST_VAL:%.*]] = load [[INT]], [[INT]]*
>>>> [[ST_INT_ST_ADDR]]
>>>> +  //
>>>> +  // OMP45-TLS:      [[ST_INT_ST_VAL:%.*]] = load [[INT]], [[INT]]*
>>>> [[ST_INT_ST_ADDR:[^,]+]]
>>>>    // OMP45-TLS-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]]
>>>>    // OMP45-TLS-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]],
>>>> [[ST_INT_ST_VAL]]
>>>>    // OMP45-TLS-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
>>>> @@ -896,8 +896,8 @@ int foobar() {
>>>>    // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]*
>>>> [[RES_ADDR]]
>>>>    // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]],
>>>> [[FLOAT_TO_INT_CONV]]
>>>>    // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
>>>> -  // OMP45-TLS:      [[ST_FLOAT_ST_ADDR:%.*]] = call float*
>>>> [[ST_FLOAT_ST_TLS_INITD]]
>>>> -  // OMP45-TLS-NEXT: [[ST_FLOAT_ST_VAL:%.*]] = load float, float*
>>>> [[ST_FLOAT_ST_ADDR]]
>>>> +  //
>>>> +  // OMP45-TLS:      [[ST_FLOAT_ST_VAL:%.*]] = load float, float*
>>>> [[ST_FLOAT_ST_ADDR:[^,]+]]
>>>>    // OMP45-TLS-NEXT: [[FLOAT_TO_INT_CONV:%.*]] = fptosi float
>>>> [[ST_FLOAT_ST_VAL]] to [[INT]]
>>>>    // OMP45-TLS-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]]
>>>>    // OMP45-TLS-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]],
>>>> [[FLOAT_TO_INT_CONV]]
>>>>
>>>> diff  --git a/clang/test/Sema/enable_if.c b/clang/test/Sema/enable_if.c
>>>> index b4bb2ecd0d20..d96a53d94e1e 100644
>>>> --- a/clang/test/Sema/enable_if.c
>>>> +++ b/clang/test/Sema/enable_if.c
>>>> @@ -5,7 +5,7 @@
>>>>  typedef int mode_t;
>>>>  typedef unsigned long size_t;
>>>>
>>>> -const int TRUE = 1;
>>>> +enum { TRUE = 1 };
>>>>
>>>>  int open(const char *pathname, int flags)
>>>> __attribute__((enable_if(!(flags & O_CREAT), "must specify mode when using
>>>> O_CREAT"))) __attribute__((overloadable));  // expected-note{{candidate
>>>> disabled: must specify mode when using O_CREAT}}
>>>>  int open(const char *pathname, int flags, mode_t mode)
>>>> __attribute__((overloadable));  // expected-note{{candidate function not
>>>> viable: requires 3 arguments, but 2 were provided}}
>>>> @@ -114,7 +114,7 @@ void f(int n)
>>>> __attribute__((enable_if(unresolvedid, "chosen when 'unresolvedid'
>>>>  int global;
>>>>  void f(int n) __attribute__((enable_if(global == 0, "chosen when
>>>> 'global' is zero")));  // expected-error{{'enable_if' attribute expression
>>>> never produces a constant expression}}  // expected-note{{subexpression not
>>>> valid in a constant expression}}
>>>>
>>>> -const int cst = 7;
>>>> +enum { cst = 7 };
>>>>  void return_cst(void) __attribute__((overloadable))
>>>> __attribute__((enable_if(cst == 7, "chosen when 'cst' is 7")));
>>>>  void test_return_cst() { return_cst(); }
>>>>
>>>>
>>>> diff  --git a/clang/test/SemaCXX/constant-expression.cpp
>>>> b/clang/test/SemaCXX/constant-expression.cpp
>>>> index 2bec62f46b66..a5e571a97eb2 100644
>>>> --- a/clang/test/SemaCXX/constant-expression.cpp
>>>> +++ b/clang/test/SemaCXX/constant-expression.cpp
>>>> @@ -98,9 +98,9 @@ void diags(int n) {
>>>>
>>>>  namespace IntOrEnum {
>>>>    const int k = 0;
>>>> -  const int &p = k;
>>>> +  const int &p = k; // expected-note {{declared here}}
>>>>    template<int n> struct S {};
>>>> -  S<p> s; // expected-error {{not an integral constant expression}}
>>>> +  S<p> s; // expected-error {{not an integral constant expression}}
>>>> expected-note {{read of variable 'p' of non-integral, non-enumeration type
>>>> 'const int &'}}
>>>>  }
>>>>
>>>>  extern const int recurse1;
>>>>
>>>> diff  --git a/clang/test/SemaCXX/i-c-e-cxx.cpp
>>>> b/clang/test/SemaCXX/i-c-e-cxx.cpp
>>>> index a09ff5ac8d9f..da9be1229a54 100644
>>>> --- a/clang/test/SemaCXX/i-c-e-cxx.cpp
>>>> +++ b/clang/test/SemaCXX/i-c-e-cxx.cpp
>>>> @@ -19,9 +19,6 @@ void f() {
>>>>
>>>>  int a() {
>>>>    const int t=t; // expected-note {{declared here}}
>>>> -#if __cplusplus <= 199711L
>>>> -  // expected-note at -2 {{read of object outside its lifetime}}
>>>> -#endif
>>>>
>>>>    switch(1) { // do not warn that 1 is not a case value;
>>>>                // 't' might have been expected to evalaute to 1
>>>>
>>>>
>>>>
>>>> _______________________________________________
>>>> cfe-commits mailing list
>>>> cfe-commits at lists.llvm.org
>>>> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>>>
>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20201026/e9cdaba7/attachment-0001.html>


More information about the cfe-commits mailing list