diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 74 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 3 |
2 files changed, 53 insertions, 24 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 2a514ab1bd2..e6381fbe49f 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -10393,8 +10393,17 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { Diag(var->getLocation(), diag::warn_missing_variable_declarations) << var; } + // Cache the result of checking for constant initialization. + Optional<bool> CacheHasConstInit; + const Expr *CacheCulprit; + auto checkConstInit = [&]() mutable { + if (!CacheHasConstInit) + CacheHasConstInit = var->getInit()->isConstantInitializer( + Context, var->getType()->isReferenceType(), &CacheCulprit); + return *CacheHasConstInit; + }; + if (var->getTLSKind() == VarDecl::TLS_Static) { - const Expr *Culprit; if (var->getType().isDestructedType()) { // GNU C++98 edits for __thread, [basic.start.term]p3: // The type of an object with thread storage duration shall not @@ -10402,17 +10411,17 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { Diag(var->getLocation(), diag::err_thread_nontrivial_dtor); if (getLangOpts().CPlusPlus11) Diag(var->getLocation(), diag::note_use_thread_local); - } else if (getLangOpts().CPlusPlus && var->hasInit() && - !var->getInit()->isConstantInitializer( - Context, var->getType()->isReferenceType(), &Culprit)) { - // GNU C++98 edits for __thread, [basic.start.init]p4: - // An object of thread storage duration shall not require dynamic - // initialization. - // FIXME: Need strict checking here. - Diag(Culprit->getExprLoc(), diag::err_thread_dynamic_init) - << Culprit->getSourceRange(); - if (getLangOpts().CPlusPlus11) - Diag(var->getLocation(), diag::note_use_thread_local); + } else if (getLangOpts().CPlusPlus && var->hasInit()) { + if (!checkConstInit()) { + // GNU C++98 edits for __thread, [basic.start.init]p4: + // An object of thread storage duration shall not require dynamic + // initialization. + // FIXME: Need strict checking here. + Diag(CacheCulprit->getExprLoc(), diag::err_thread_dynamic_init) + << CacheCulprit->getSourceRange(); + if (getLangOpts().CPlusPlus11) + Diag(var->getLocation(), diag::note_use_thread_local); + } } } @@ -10486,18 +10495,6 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { if (!var->getDeclContext()->isDependentContext() && Init && !Init->isValueDependent()) { - if (IsGlobal && !var->isConstexpr() && - !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()) && - !Init->isConstantInitializer(Context, baseType->isReferenceType())) - Diag(var->getLocation(), diag::warn_global_constructor) - << Init->getSourceRange(); - } if (var->isConstexpr()) { SmallVector<PartialDiagnosticAt, 8> Notes; @@ -10521,6 +10518,35 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { // 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<RequireConstantInitAttr>()) { + // FIXME: Need strict checking in C++03 here. + bool DiagErr = getLangOpts().CPlusPlus11 + ? !var->checkInitIsICE() : !checkConstInit(); + if (DiagErr) { + auto attr = var->getAttr<RequireConstantInitAttr>(); + Diag(var->getLocation(), diag::err_require_constant_init_failed) + << Init->getSourceRange(); + Diag(attr->getLocation(), diag::note_declared_required_constant_init_here) + << attr->getRange(); + } + } + else if (!var->isConstexpr() && 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())) { + if (!checkConstInit()) + Diag(var->getLocation(), diag::warn_global_constructor) + << Init->getSourceRange(); + } + } } // Require the destructor. diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 0471f65cccd..824d68e838e 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5630,6 +5630,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_VecTypeHint: handleVecTypeHint(S, D, Attr); break; + case AttributeList::AT_RequireConstantInit: + handleSimpleAttribute<RequireConstantInitAttr>(S, D, Attr); + break; case AttributeList::AT_InitPriority: handleInitPriorityAttr(S, D, Attr); break; |