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