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 <tha...@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@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