@@ -13436,6 +13436,53 @@ bool Sema::GloballyUniqueObjectMightBeAccidentallyDuplicated(
1343613436 return true;
1343713437}
1343813438
13439+ void Sema::DiagnoseDangerousUniqueObjectDuplication(const VarDecl* VD) {
13440+ // If this object has external linkage and hidden visibility, it might be
13441+ // duplicated when built into a shared library, which causes problems if it's
13442+ // mutable (since the copies won't be in sync) or its initialization has side
13443+ // effects (since it will run once per copy instead of once globally)
13444+ // FIXME: Windows uses dllexport/dllimport instead of visibility, and we don't
13445+ // handle that yet. Disable the warning on Windows for now.
13446+ // FIXME: Checking templates can cause false positives if the template in
13447+ // question is never instantiated (e.g. only specialized templates are used).
13448+ if (!Context.getTargetInfo().shouldDLLImportComdatSymbols() &&
13449+ !VD->isTemplated() &&
13450+ GloballyUniqueObjectMightBeAccidentallyDuplicated(VD)) {
13451+ // Check mutability. For pointers, ensure that both the pointer and the
13452+ // pointee are (recursively) const.
13453+ QualType Type = VD->getType().getNonReferenceType();
13454+ if (!Type.isConstant(VD->getASTContext())) {
13455+ Diag(VD->getLocation(), diag::warn_possible_object_duplication_mutable)
13456+ << VD;
13457+ } else {
13458+ while (Type->isPointerType()) {
13459+ Type = Type->getPointeeType();
13460+ if (Type->isFunctionType())
13461+ break;
13462+ if (!Type.isConstant(VD->getASTContext())) {
13463+ Diag(VD->getLocation(),
13464+ diag::warn_possible_object_duplication_mutable)
13465+ << VD;
13466+ break;
13467+ }
13468+ }
13469+ }
13470+
13471+ // To keep false positives low, only warn if we're certain that the
13472+ // initializer has side effects. Don't warn on operator new, since a mutable
13473+ // pointer will trigger the previous warning, and an immutable pointer
13474+ // getting duplicated just results in a little extra memory usage.
13475+ const Expr *Init = VD->getAnyInitializer();
13476+ if (Init &&
13477+ Init->HasSideEffects(VD->getASTContext(),
13478+ /*IncludePossibleEffects=*/false) &&
13479+ !isa<CXXNewExpr>(Init->IgnoreParenImpCasts())) {
13480+ Diag(Init->getExprLoc(), diag::warn_possible_object_duplication_init)
13481+ << VD;
13482+ }
13483+ }
13484+ }
13485+
1343913486void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
1344013487 // If there is no declaration, there was an error parsing it. Just ignore
1344113488 // the initializer.
@@ -14655,6 +14702,8 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
1465514702 return;
1465614703 }
1465714704
14705+ DiagnoseDangerousUniqueObjectDuplication(var);
14706+
1465814707 // Require the destructor.
1465914708 if (!type->isDependentType())
1466014709 if (const RecordType *recordType = baseType->getAs<RecordType>())
@@ -14842,51 +14891,6 @@ void Sema::FinalizeDeclaration(Decl *ThisDecl) {
1484214891 if (DC->getRedeclContext()->isFileContext() && VD->isExternallyVisible())
1484314892 AddPushedVisibilityAttribute(VD);
1484414893
14845- // If this object has external linkage and hidden visibility, it might be
14846- // duplicated when built into a shared library, which causes problems if it's
14847- // mutable (since the copies won't be in sync) or its initialization has side
14848- // effects (since it will run once per copy instead of once globally)
14849- // FIXME: Windows uses dllexport/dllimport instead of visibility, and we don't
14850- // handle that yet. Disable the warning on Windows for now.
14851- // FIXME: Checking templates can cause false positives if the template in
14852- // question is never instantiated (e.g. only specialized templates are used).
14853- if (!Context.getTargetInfo().shouldDLLImportComdatSymbols() &&
14854- !VD->isTemplated() &&
14855- GloballyUniqueObjectMightBeAccidentallyDuplicated(VD)) {
14856- // Check mutability. For pointers, ensure that both the pointer and the
14857- // pointee are (recursively) const.
14858- QualType Type = VD->getType().getNonReferenceType();
14859- if (!Type.isConstant(VD->getASTContext())) {
14860- Diag(VD->getLocation(), diag::warn_possible_object_duplication_mutable)
14861- << VD;
14862- } else {
14863- while (Type->isPointerType()) {
14864- Type = Type->getPointeeType();
14865- if (Type->isFunctionType())
14866- break;
14867- if (!Type.isConstant(VD->getASTContext())) {
14868- Diag(VD->getLocation(),
14869- diag::warn_possible_object_duplication_mutable)
14870- << VD;
14871- break;
14872- }
14873- }
14874- }
14875-
14876- // To keep false positives low, only warn if we're certain that the
14877- // initializer has side effects. Don't warn on operator new, since a mutable
14878- // pointer will trigger the previous warning, and an immutable pointer
14879- // getting duplicated just results in a little extra memory usage.
14880- const Expr *Init = VD->getAnyInitializer();
14881- if (Init &&
14882- Init->HasSideEffects(VD->getASTContext(),
14883- /*IncludePossibleEffects=*/false) &&
14884- !isa<CXXNewExpr>(Init->IgnoreParenImpCasts())) {
14885- Diag(Init->getExprLoc(), diag::warn_possible_object_duplication_init)
14886- << VD;
14887- }
14888- }
14889-
1489014894 // FIXME: Warn on unused var template partial specializations.
1489114895 if (VD->isFileVarDecl() && !isa<VarTemplatePartialSpecializationDecl>(VD))
1489214896 MarkUnusedFileScopedDecl(VD);
0 commit comments