diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index ad366821f3cbff1153654f2bcad21381fa14313c..690acb72e076544c5d50870dcd8819bf75c788af 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -156,6 +156,7 @@ LANGOPT(Coroutines , 1, 0, "C++20 coroutines") LANGOPT(DllExportInlines , 1, 1, "dllexported classes dllexport inline methods") LANGOPT(RelaxedTemplateTemplateArgs, 1, 0, "C++17 relaxed matching of template template arguments") LANGOPT(ExperimentalLibrary, 1, 0, "enable unstable and experimental library features") +LANGOPT(NonConstantGlobalInitializers, 1, 1, "allow use of non-constant static storage variables in global initializers, to enhance compatibility with gcc.") LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes") diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 3cab37b21aaf3f4bee4daecb21bd90d3cb5cf069..9f7842647cde34267463f4bcf883bc4808a5c914 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -6129,6 +6129,10 @@ def fallow_half_arguments_and_returns : Flag<["-"], "fallow-half-arguments-and-r HelpText<"Allow function arguments and returns of type half">, MarshallingInfoFlag>, ImpliedByAnyOf<[fnative_half_arguments_and_returns.KeyPath]>; +defm allow_non_const_global_init : BoolFOption<"allow-non-const-global-init", + LangOpts<"NonConstantGlobalInitializers">, DefaultTrue, + PosFlag, NegFlag, + BothFlags<[], " use of non-constant static storage variables in global initializers.">>; def fdefault_calling_conv_EQ : Joined<["-"], "fdefault-calling-conv=">, HelpText<"Set default calling convention">, Values<"cdecl,fastcall,stdcall,vectorcall,regcall">, diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 83081bbf0aa0c34e9cc1304c90110d44d89cc565..e1178919705a1f0b161b0b464b9c5dc60f1e8e13 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -7290,9 +7290,15 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, if (isFileScope) { if (!LiteralExpr->isTypeDependent() && !LiteralExpr->isValueDependent() && - !literalType->isDependentType()) // C99 6.5.2.5p3 - if (CheckForConstantInitializer(LiteralExpr, literalType)) - return ExprError(); + !literalType->isDependentType()) { // C99 6.5.2.5p3 + // Try to behave like gcc and ignore this check by default + // while compiling CPP files. + bool ignoreCheck = getLangOpts().CPlusPlus && + getLangOpts().NonConstantGlobalInitializers; + if (!ignoreCheck && + CheckForConstantInitializer(LiteralExpr, literalType)) + return ExprError(); + } } else if (literalType.getAddressSpace() != LangAS::opencl_private && literalType.getAddressSpace() != LangAS::Default) { // Embedded-C extensions to C99 6.5.2.5: diff --git a/clang/test/SemaCXX/compound-literal.cpp b/clang/test/SemaCXX/compound-literal.cpp index 353be2cf48e4f57848593e2a035b4439b3f9ae4e..9b1c2df77352a2594b8298167523ebc295b9449b 100644 --- a/clang/test/SemaCXX/compound-literal.cpp +++ b/clang/test/SemaCXX/compound-literal.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -fsyntax-only -std=c++03 -verify -ast-dump %s > %t-03 +// RUN: %clang_cc1 -fsyntax-only -fno-allow-non-const-global-init -std=c++03 -verify -ast-dump %s > %t-03 // RUN: FileCheck --input-file=%t-03 %s -// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify -ast-dump %s > %t-11 +// RUN: %clang_cc1 -fsyntax-only -fno-allow-non-const-global-init -std=c++11 -verify -ast-dump %s > %t-11 // RUN: FileCheck --input-file=%t-11 %s // RUN: FileCheck --input-file=%t-11 %s --check-prefix=CHECK-CXX11 diff --git a/clang/test/SemaCXX/non-constant-global-initializers-disabled.cpp b/clang/test/SemaCXX/non-constant-global-initializers-disabled.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3527f0922968bf90db0aab780f36f055717e34d5 --- /dev/null +++ b/clang/test/SemaCXX/non-constant-global-initializers-disabled.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -x c -fsyntax-only -fno-allow-non-const-global-init %s -verify +// RUN: %clang_cc1 -x c++ -fsyntax-only -fno-allow-non-const-global-init %s -verify + +int* f(int *); +struct DT { int * el;}; +int * pa = 0; +struct DT va = (struct DT){pa}; // expected-error {{initializer element is not a compile-time constant}} +struct DT vb = (struct DT){pa + 1}; // expected-error {{initializer element is not a compile-time constant}} +struct DT vc = (struct DT){f(pa) + 1}; // expected-error {{initializer element is not a compile-time constant}} diff --git a/clang/test/SemaCXX/non-constant-global-initializers.cpp b/clang/test/SemaCXX/non-constant-global-initializers.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cb35656e1ce1268541cb3b868fb1f4c937c655b3 --- /dev/null +++ b/clang/test/SemaCXX/non-constant-global-initializers.cpp @@ -0,0 +1,20 @@ +// The first and second runs check that nothing has been changed for C +// RUN: not %clang_cc1 -x c -fsyntax-only %s 2> %t +// RUN: FileCheck %s < %t +// RUN: not %clang_cc1 -x c -fsyntax-only -fallow-non-const-global-init %s 2> %t +// RUN: FileCheck %s < %t + +// The third and fourth runs check that it works for C++ both by default and by enabling the option +// RUN: %clang_cc1 -x c++ -fsyntax-only %s -verify +// RUN: %clang_cc1 -x c++ -fsyntax-only -fallow-non-const-global-init %s -verify +// expected-no-diagnostics + +int* f(int *); +struct DT { int * el;}; +int * pa = 0; +struct DT va = (struct DT){pa}; +// CHECK:[[@LINE-1]]:28: error: initializer element is not a compile-time constant +struct DT vb = (struct DT){pa + 1}; +// CHECK:[[@LINE-1]]:31: error: initializer element is not a compile-time constant +struct DT vc = (struct DT){f(pa) + 1}; +// CHECK:[[@LINE-1]]:34: error: initializer element is not a compile-time constant