[cfe-commits] r109984 - in /cfe/trunk: include/clang/Basic/DiagnosticGroups.td include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp test/SemaCXX/warn-global-constructors.cpp
John McCall
rjmccall at apple.com
Sun Aug 1 13:20:59 PDT 2010
Author: rjmccall
Date: Sun Aug 1 15:20:59 2010
New Revision: 109984
URL: http://llvm.org/viewvc/llvm-project?rev=109984&view=rev
Log:
Make a first pass at implementing -Wglobal-constructors. I'm worried that this
will end up bizarrely mirroring CGExprConstant, but that might be the hazard of
this feature.
Added:
cfe/trunk/test/SemaCXX/warn-global-constructors.cpp
Modified:
cfe/trunk/include/clang/Basic/DiagnosticGroups.td
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=109984&r1=109983&r2=109984&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Sun Aug 1 15:20:59 2010
@@ -52,6 +52,7 @@
def : DiagGroup<"c++0x-compat", [CXXHexFloats]>;
def : DiagGroup<"effc++">;
def FourByteMultiChar : DiagGroup<"four-char-constants">;
+def GlobalConstructors : DiagGroup<"global-constructors">;
def : DiagGroup<"idiomatic-parentheses">;
def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">;
def : DiagGroup<"import">;
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=109984&r1=109983&r2=109984&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sun Aug 1 15:20:59 2010
@@ -168,6 +168,13 @@
"access declarations are deprecated; use using declarations instead">,
InGroup<Deprecated>;
+def warn_global_constructor : Warning<
+ "declaration requires a global constructor">,
+ InGroup<GlobalConstructors>, DefaultIgnore;
+def warn_global_destructor : Warning<
+ "declaration requires a global destructor">,
+ InGroup<GlobalConstructors>, DefaultIgnore;
+
def err_invalid_thread : Error<
"'__thread' is only allowed on variable declarations">;
def err_thread_non_global : Error<
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=109984&r1=109983&r2=109984&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sun Aug 1 15:20:59 2010
@@ -3866,6 +3866,57 @@
AddInitializerToDecl(dcl, move(init), /*DirectInit=*/false);
}
+/// Make a reasonable guess at whether the given initializer will
+/// require a global constructor.
+static bool RequiresGlobalConstructor(Sema &S, Expr *Init) {
+ // FIXME: reproducing the logic of CGExprConstant is kindof dumb.
+ // Maybe this should be integrated into the constant-evaluator?
+ // We'd need array and struct value types.
+ //
+ // It's probably okay to still warn in the theoretical cases where
+ // IR gen can eliminate a global constructor based on
+ // initialization order (not that it actually does that
+ // optimization at the moment).
+ if (Init->isEvaluatable(S.Context)) return false;
+
+ Init = Init->IgnoreParenNoopCasts(S.Context);
+
+ // Look through reference-bindings.
+ if (CXXBindReferenceExpr *BE = dyn_cast<CXXBindReferenceExpr>(Init))
+ return RequiresGlobalConstructor(S, BE);
+
+ // A constructor call needs a global constructor if:
+ if (CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(Init)) {
+ // - the constructor is non-trivial
+ if (!CE->getConstructor()->isTrivial()) return true;
+
+ // - any of the argument expressions needs a global constructor
+ for (CXXConstructExpr::arg_iterator
+ I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I)
+ if (RequiresGlobalConstructor(S, *I))
+ return true;
+
+ // We don't have to worry about building temporaries with
+ // non-trivial destructors because we should never have walked
+ // through the CXXExprWithTemporaries.
+
+ // So it should be emitted as a constant expression.
+ return false;
+ }
+
+ /// An initializer list requires a global constructor if any of the
+ /// components do.
+ if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
+ for (unsigned I = 0, E = ILE->getNumInits(); I != E; ++I)
+ if (RequiresGlobalConstructor(S, ILE->getInit(I)))
+ return true;
+ return false;
+ }
+
+ // Assume everything else does.
+ return true;
+}
+
/// AddInitializerToDecl - Adds the initializer Init to the
/// declaration dcl. If DirectInit is true, this is C++ direct
/// initialization rather than copy initialization.
@@ -4065,6 +4116,11 @@
VDecl->setInit(Init);
if (getLangOptions().CPlusPlus) {
+ if (!VDecl->isInvalidDecl() &&
+ !VDecl->getDeclContext()->isDependentContext() &&
+ VDecl->hasGlobalStorage() && RequiresGlobalConstructor(*this, Init))
+ Diag(VDecl->getLocation(), diag::warn_global_constructor);
+
// Make sure we mark the destructor as used if necessary.
QualType InitType = VDecl->getType();
while (const ArrayType *Array = Context.getAsArrayType(InitType))
@@ -4270,8 +4326,15 @@
MultiExprArg(*this, 0, 0));
if (Init.isInvalid())
Var->setInvalidDecl();
- else if (Init.get())
+ else if (Init.get()) {
Var->setInit(MaybeCreateCXXExprWithTemporaries(Init.takeAs<Expr>()));
+
+ if (getLangOptions().CPlusPlus && !Var->isInvalidDecl() &&
+ Var->hasGlobalStorage() &&
+ !Var->getDeclContext()->isDependentContext() &&
+ RequiresGlobalConstructor(*this, Var->getInit()))
+ Diag(Var->getLocation(), diag::warn_global_constructor);
+ }
}
if (!Var->isInvalidDecl() && getLangOptions().CPlusPlus && Record)
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=109984&r1=109983&r2=109984&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sun Aug 1 15:20:59 2010
@@ -5358,6 +5358,9 @@
PDiag(diag::err_access_dtor_var)
<< VD->getDeclName()
<< VD->getType());
+
+ if (!VD->isInvalidDecl() && VD->hasGlobalStorage())
+ Diag(VD->getLocation(), diag::warn_global_destructor);
}
}
Added: cfe/trunk/test/SemaCXX/warn-global-constructors.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-global-constructors.cpp?rev=109984&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-global-constructors.cpp (added)
+++ cfe/trunk/test/SemaCXX/warn-global-constructors.cpp Sun Aug 1 15:20:59 2010
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -fsyntax-only -Wglobal-constructors %s -verify
+
+int opaque_int();
+
+namespace test0 {
+ // These should never require global constructors.
+ int a;
+ int b = 20;
+ float c = 5.0f;
+
+ // This global constructor is avoidable based on initialization order.
+ int d = b; // expected-warning {{global constructor}}
+
+ // These global constructors are unavoidable.
+ int e = opaque_int(); // expected-warning {{global constructor}}
+ int f = b; // expected-warning {{global constructor}}
+}
+
+namespace test1 {
+ struct A { int x; };
+ A a;
+ A b = A();
+ A c = { 10 };
+ A d = { opaque_int() }; // expected-warning {{global constructor}}
+}
+
+namespace test2 {
+ struct A { A(); };
+ A a; // expected-warning {{global constructor}}
+ A b[10]; // expected-warning {{global constructor}}
+ A c[10][10]; // expected-warning {{global constructor}}
+}
+
+namespace test3 {
+ struct A { ~A(); };
+ A a; // expected-warning {{global destructor}}
+ A b[10]; // expected-warning {{global destructor}}
+ A c[10][10]; // expected-warning {{global destructor}}
+}
More information about the cfe-commits
mailing list