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@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@-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@lists.llvm.org > https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits