Message ID | 663f6565.630a0220.1889a.cb64@mx.google.com |
---|---|
State | New |
Headers | show |
Series | c++: Strengthen checks on 'main' | expand |
On 5/11/24 08:32, Nathaniel Shead wrote: > I wasn't entirely sure what to do with the 'abi/main.C' testcase here; > is this OK, or should I e.g. lower the linkage error to a pedwarn for > the purposes of this test? I think it should be a pedwarn anyway, since it's harmless. The others can still be errors. > Bootstrapped and regtested on x86_64-pc-linux-gnu, and lightly checked > with a MinGW32 cross. OK for trunk? > > -- >8 -- > > This patch adds some missing requirements for legal main declarations, > as according to [basic.start.main] p2. > > gcc/cp/ChangeLog: > > * decl.cc (grokfndecl): Check for main functions with language > linkage or module attachment. > (grokvardecl): Check for extern 'C' entities named main. > > gcc/testsuite/ChangeLog: > > * g++.dg/abi/main.C: Rework to avoid declaring main with > language linkage. > * g++.dg/modules/contracts-1_b.C: Don't declare main in named > module. > * g++.dg/modules/contracts-3_b.C: Likewise. > * g++.dg/modules/contracts-4_d.C: Likewise. > * g++.dg/modules/horcrux-1_a.C: Export declarations, so that... > * g++.dg/modules/horcrux-1_b.C: Don't declare main in named > module. > * g++.dg/modules/main-1.C: New test. > * g++.dg/parse/linkage5.C: New test. > * g++.dg/parse/linkage6.C: New test. > > Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com> > --- > gcc/cp/decl.cc | 19 ++++++++++--- > gcc/testsuite/g++.dg/abi/main.C | 29 ++++++++------------ > gcc/testsuite/g++.dg/modules/contracts-1_b.C | 4 --- > gcc/testsuite/g++.dg/modules/contracts-3_b.C | 4 --- > gcc/testsuite/g++.dg/modules/contracts-4_d.C | 2 -- > gcc/testsuite/g++.dg/modules/horcrux-1_a.C | 3 ++ > gcc/testsuite/g++.dg/modules/horcrux-1_b.C | 2 +- > gcc/testsuite/g++.dg/modules/main-1.C | 5 ++++ > gcc/testsuite/g++.dg/parse/linkage5.C | 14 ++++++++++ > gcc/testsuite/g++.dg/parse/linkage6.C | 13 +++++++++ > 10 files changed, 63 insertions(+), 32 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/modules/main-1.C > create mode 100644 gcc/testsuite/g++.dg/parse/linkage5.C > create mode 100644 gcc/testsuite/g++.dg/parse/linkage6.C > > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc > index e02562466a7..5ab3b787d6f 100644 > --- a/gcc/cp/decl.cc > +++ b/gcc/cp/decl.cc > @@ -10781,6 +10781,11 @@ grokfndecl (tree ctype, > "cannot declare %<::main%> to be %qs", "consteval"); > if (!publicp) > error_at (location, "cannot declare %<::main%> to be static"); > + if (current_lang_depth () != 0) > + error_at (location, "cannot declare %<::main%> with a" > + " linkage specification"); > + if (module_attach_p ()) > + error_at (location, "cannot attach %<::main%> to a named module"); > inlinep = 0; > publicp = 1; > } > @@ -11280,10 +11285,16 @@ grokvardecl (tree type, > DECL_INTERFACE_KNOWN (decl) = 1; > > if (DECL_NAME (decl) > - && MAIN_NAME_P (DECL_NAME (decl)) > - && scope == global_namespace) > - error_at (DECL_SOURCE_LOCATION (decl), > - "cannot declare %<::main%> to be a global variable"); > + && MAIN_NAME_P (DECL_NAME (decl))) > + { > + if (scope == global_namespace) > + error_at (DECL_SOURCE_LOCATION (decl), > + "cannot declare %<::main%> to be a global variable"); > + else if (DECL_EXTERN_C_P (decl)) > + error_at (DECL_SOURCE_LOCATION (decl), > + "an entity named %<main%> cannot be declared with " > + "C language linkage"); > + } > > /* Check that the variable can be safely declared as a concept. > Note that this also forbids explicit specializations. */ > diff --git a/gcc/testsuite/g++.dg/abi/main.C b/gcc/testsuite/g++.dg/abi/main.C > index 4c5f1ea213c..f3882d70612 100644 > --- a/gcc/testsuite/g++.dg/abi/main.C > +++ b/gcc/testsuite/g++.dg/abi/main.C > @@ -1,24 +1,19 @@ > /* { dg-do compile } */ > > -/* Check if entry points get implicit C linkage. If they don't, compiler will > - * error on incompatible declarations */ > +/* Check if entry points get implicit C linkage. Determined by checking that > + the names are unmangled */ > > -int main(); > -extern "C" int main(); > +int main() {} > > #ifdef __MINGW32__ > - > -int wmain(); > -extern "C" int wmain(); > - > -int DllMain(); > -extern "C" int DllMain(); > - > -int WinMain(); > -extern "C" int WinMain(); > - > -int wWinMain(); > -extern "C" int wWinMain(); > - > +int wmain() {} > +int DllMain() {} > +int WinMain() {} > +int wWinMain() {} > #endif > > +// { dg-final { scan-assembler-not "_Z4mainv" } } > +// { dg-final { scan-assembler-not "_Z5wmainv" { target *-*-mingw32 } } } > +// { dg-final { scan-assembler-not "_Z7DllMainv" { target *-*-mingw32 } } } > +// { dg-final { scan-assembler-not "_Z7WinMainv" { target *-*-mingw32 } } } > +// { dg-final { scan-assembler-not "_Z8wWinMainv" { target *-*-mingw32 } } } > diff --git a/gcc/testsuite/g++.dg/modules/contracts-1_b.C b/gcc/testsuite/g++.dg/modules/contracts-1_b.C > index 30c15f6928b..aa36c8d6b1b 100644 > --- a/gcc/testsuite/g++.dg/modules/contracts-1_b.C > +++ b/gcc/testsuite/g++.dg/modules/contracts-1_b.C > @@ -1,15 +1,11 @@ > // { dg-module-do run } > // { dg-additional-options "-fmodules-ts -fcontracts -fcontract-continuation-mode=on" } > -module; > #include <cstdio> > -export module bar; > -// { dg-module-cmi bar } > import foo; > > template<typename T> > bool bar_fn_pre(T n) { printf("bar fn pre(%d)\n", n); return true; } > > -export > template<typename T> > T bar_fn(T n) > [[ pre: bar_fn_pre(n) && n > 0 ]] > diff --git a/gcc/testsuite/g++.dg/modules/contracts-3_b.C b/gcc/testsuite/g++.dg/modules/contracts-3_b.C > index b1d6375391b..1a29e2c3e5d 100644 > --- a/gcc/testsuite/g++.dg/modules/contracts-3_b.C > +++ b/gcc/testsuite/g++.dg/modules/contracts-3_b.C > @@ -1,15 +1,11 @@ > // { dg-module-do run } > // { dg-additional-options "-fmodules-ts -fcontracts -fcontract-role=default:ignore,ignore,ignore" } > -module; > #include <cstdio> > -export module bar; > -// { dg-module-cmi bar } > import foo; > > template<typename T> > bool bar_fn_pre(T n) { printf("bar fn pre(%d)\n", n); return true; } > > -export > template<typename T> > T bar_fn(T n) > [[ pre: bar_fn_pre(n) && n > 0 ]] > diff --git a/gcc/testsuite/g++.dg/modules/contracts-4_d.C b/gcc/testsuite/g++.dg/modules/contracts-4_d.C > index dc56251d1d8..9e6b7c3d4de 100644 > --- a/gcc/testsuite/g++.dg/modules/contracts-4_d.C > +++ b/gcc/testsuite/g++.dg/modules/contracts-4_d.C > @@ -1,8 +1,6 @@ > // { dg-module-do run } > // { dg-additional-options "-fmodules-ts -fcontracts" } > -module; > #include <cstdio> > -export module baz; > import foo; > import bar; > > diff --git a/gcc/testsuite/g++.dg/modules/horcrux-1_a.C b/gcc/testsuite/g++.dg/modules/horcrux-1_a.C > index ff548d039ea..c115bd2965b 100644 > --- a/gcc/testsuite/g++.dg/modules/horcrux-1_a.C > +++ b/gcc/testsuite/g++.dg/modules/horcrux-1_a.C > @@ -3,13 +3,16 @@ > export module foo; > // { dg-module-cmi foo } > > +export > template<typename _Tp, _Tp __v> > struct integral_constant > {}; > > +export > template<bool __v> > using __bool_constant = integral_constant<bool, __v>; > > +export > template<typename _Tp, typename... _Args> > struct __is_constructible_impl > : public __bool_constant<__is_constructible(_Tp, _Args...)> > diff --git a/gcc/testsuite/g++.dg/modules/horcrux-1_b.C b/gcc/testsuite/g++.dg/modules/horcrux-1_b.C > index 842bf413585..54aa069436a 100644 > --- a/gcc/testsuite/g++.dg/modules/horcrux-1_b.C > +++ b/gcc/testsuite/g++.dg/modules/horcrux-1_b.C > @@ -1,6 +1,6 @@ > // { dg-additional-options -fmodules-ts } > > -module foo; > +import foo; > > int main () > { > diff --git a/gcc/testsuite/g++.dg/modules/main-1.C b/gcc/testsuite/g++.dg/modules/main-1.C > new file mode 100644 > index 00000000000..0d79edddb75 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/modules/main-1.C > @@ -0,0 +1,5 @@ > +// { dg-additional-options "-fmodules-ts" } > +// { dg-prune-output "not writing module" } > + > +export module M; > +int main() {} // { dg-error "attach" } > diff --git a/gcc/testsuite/g++.dg/parse/linkage5.C b/gcc/testsuite/g++.dg/parse/linkage5.C > new file mode 100644 > index 00000000000..451406de69b > --- /dev/null > +++ b/gcc/testsuite/g++.dg/parse/linkage5.C > @@ -0,0 +1,14 @@ > +// { dg-do compile } > +// The main function shall not be declared with a linkage-specification. > + > +extern "C" { > + int main(); // { dg-error "linkage" } > +} > + > +namespace foo { > + extern "C" int main(); // { dg-error "linkage" } > +} > + > +extern "C++" int main(); // { dg-error "linkage" } > + > +extern "C" struct S { int main(); }; // OK > diff --git a/gcc/testsuite/g++.dg/parse/linkage6.C b/gcc/testsuite/g++.dg/parse/linkage6.C > new file mode 100644 > index 00000000000..44081c1544c > --- /dev/null > +++ b/gcc/testsuite/g++.dg/parse/linkage6.C > @@ -0,0 +1,13 @@ > +// { dg-do compile } > +// A program that declares an entity named main with C language linkage > +// (in any namespace) is ill-formed. > + > +namespace foo { > + extern "C" int main; // { dg-error "linkage" } > + extern "C" struct A { > + int main; // OK > + }; > + extern "C" struct B { > + int main(); // OK > + }; > +}
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index e02562466a7..5ab3b787d6f 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -10781,6 +10781,11 @@ grokfndecl (tree ctype, "cannot declare %<::main%> to be %qs", "consteval"); if (!publicp) error_at (location, "cannot declare %<::main%> to be static"); + if (current_lang_depth () != 0) + error_at (location, "cannot declare %<::main%> with a" + " linkage specification"); + if (module_attach_p ()) + error_at (location, "cannot attach %<::main%> to a named module"); inlinep = 0; publicp = 1; } @@ -11280,10 +11285,16 @@ grokvardecl (tree type, DECL_INTERFACE_KNOWN (decl) = 1; if (DECL_NAME (decl) - && MAIN_NAME_P (DECL_NAME (decl)) - && scope == global_namespace) - error_at (DECL_SOURCE_LOCATION (decl), - "cannot declare %<::main%> to be a global variable"); + && MAIN_NAME_P (DECL_NAME (decl))) + { + if (scope == global_namespace) + error_at (DECL_SOURCE_LOCATION (decl), + "cannot declare %<::main%> to be a global variable"); + else if (DECL_EXTERN_C_P (decl)) + error_at (DECL_SOURCE_LOCATION (decl), + "an entity named %<main%> cannot be declared with " + "C language linkage"); + } /* Check that the variable can be safely declared as a concept. Note that this also forbids explicit specializations. */ diff --git a/gcc/testsuite/g++.dg/abi/main.C b/gcc/testsuite/g++.dg/abi/main.C index 4c5f1ea213c..f3882d70612 100644 --- a/gcc/testsuite/g++.dg/abi/main.C +++ b/gcc/testsuite/g++.dg/abi/main.C @@ -1,24 +1,19 @@ /* { dg-do compile } */ -/* Check if entry points get implicit C linkage. If they don't, compiler will - * error on incompatible declarations */ +/* Check if entry points get implicit C linkage. Determined by checking that + the names are unmangled */ -int main(); -extern "C" int main(); +int main() {} #ifdef __MINGW32__ - -int wmain(); -extern "C" int wmain(); - -int DllMain(); -extern "C" int DllMain(); - -int WinMain(); -extern "C" int WinMain(); - -int wWinMain(); -extern "C" int wWinMain(); - +int wmain() {} +int DllMain() {} +int WinMain() {} +int wWinMain() {} #endif +// { dg-final { scan-assembler-not "_Z4mainv" } } +// { dg-final { scan-assembler-not "_Z5wmainv" { target *-*-mingw32 } } } +// { dg-final { scan-assembler-not "_Z7DllMainv" { target *-*-mingw32 } } } +// { dg-final { scan-assembler-not "_Z7WinMainv" { target *-*-mingw32 } } } +// { dg-final { scan-assembler-not "_Z8wWinMainv" { target *-*-mingw32 } } } diff --git a/gcc/testsuite/g++.dg/modules/contracts-1_b.C b/gcc/testsuite/g++.dg/modules/contracts-1_b.C index 30c15f6928b..aa36c8d6b1b 100644 --- a/gcc/testsuite/g++.dg/modules/contracts-1_b.C +++ b/gcc/testsuite/g++.dg/modules/contracts-1_b.C @@ -1,15 +1,11 @@ // { dg-module-do run } // { dg-additional-options "-fmodules-ts -fcontracts -fcontract-continuation-mode=on" } -module; #include <cstdio> -export module bar; -// { dg-module-cmi bar } import foo; template<typename T> bool bar_fn_pre(T n) { printf("bar fn pre(%d)\n", n); return true; } -export template<typename T> T bar_fn(T n) [[ pre: bar_fn_pre(n) && n > 0 ]] diff --git a/gcc/testsuite/g++.dg/modules/contracts-3_b.C b/gcc/testsuite/g++.dg/modules/contracts-3_b.C index b1d6375391b..1a29e2c3e5d 100644 --- a/gcc/testsuite/g++.dg/modules/contracts-3_b.C +++ b/gcc/testsuite/g++.dg/modules/contracts-3_b.C @@ -1,15 +1,11 @@ // { dg-module-do run } // { dg-additional-options "-fmodules-ts -fcontracts -fcontract-role=default:ignore,ignore,ignore" } -module; #include <cstdio> -export module bar; -// { dg-module-cmi bar } import foo; template<typename T> bool bar_fn_pre(T n) { printf("bar fn pre(%d)\n", n); return true; } -export template<typename T> T bar_fn(T n) [[ pre: bar_fn_pre(n) && n > 0 ]] diff --git a/gcc/testsuite/g++.dg/modules/contracts-4_d.C b/gcc/testsuite/g++.dg/modules/contracts-4_d.C index dc56251d1d8..9e6b7c3d4de 100644 --- a/gcc/testsuite/g++.dg/modules/contracts-4_d.C +++ b/gcc/testsuite/g++.dg/modules/contracts-4_d.C @@ -1,8 +1,6 @@ // { dg-module-do run } // { dg-additional-options "-fmodules-ts -fcontracts" } -module; #include <cstdio> -export module baz; import foo; import bar; diff --git a/gcc/testsuite/g++.dg/modules/horcrux-1_a.C b/gcc/testsuite/g++.dg/modules/horcrux-1_a.C index ff548d039ea..c115bd2965b 100644 --- a/gcc/testsuite/g++.dg/modules/horcrux-1_a.C +++ b/gcc/testsuite/g++.dg/modules/horcrux-1_a.C @@ -3,13 +3,16 @@ export module foo; // { dg-module-cmi foo } +export template<typename _Tp, _Tp __v> struct integral_constant {}; +export template<bool __v> using __bool_constant = integral_constant<bool, __v>; +export template<typename _Tp, typename... _Args> struct __is_constructible_impl : public __bool_constant<__is_constructible(_Tp, _Args...)> diff --git a/gcc/testsuite/g++.dg/modules/horcrux-1_b.C b/gcc/testsuite/g++.dg/modules/horcrux-1_b.C index 842bf413585..54aa069436a 100644 --- a/gcc/testsuite/g++.dg/modules/horcrux-1_b.C +++ b/gcc/testsuite/g++.dg/modules/horcrux-1_b.C @@ -1,6 +1,6 @@ // { dg-additional-options -fmodules-ts } -module foo; +import foo; int main () { diff --git a/gcc/testsuite/g++.dg/modules/main-1.C b/gcc/testsuite/g++.dg/modules/main-1.C new file mode 100644 index 00000000000..0d79edddb75 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/main-1.C @@ -0,0 +1,5 @@ +// { dg-additional-options "-fmodules-ts" } +// { dg-prune-output "not writing module" } + +export module M; +int main() {} // { dg-error "attach" } diff --git a/gcc/testsuite/g++.dg/parse/linkage5.C b/gcc/testsuite/g++.dg/parse/linkage5.C new file mode 100644 index 00000000000..451406de69b --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/linkage5.C @@ -0,0 +1,14 @@ +// { dg-do compile } +// The main function shall not be declared with a linkage-specification. + +extern "C" { + int main(); // { dg-error "linkage" } +} + +namespace foo { + extern "C" int main(); // { dg-error "linkage" } +} + +extern "C++" int main(); // { dg-error "linkage" } + +extern "C" struct S { int main(); }; // OK diff --git a/gcc/testsuite/g++.dg/parse/linkage6.C b/gcc/testsuite/g++.dg/parse/linkage6.C new file mode 100644 index 00000000000..44081c1544c --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/linkage6.C @@ -0,0 +1,13 @@ +// { dg-do compile } +// A program that declares an entity named main with C language linkage +// (in any namespace) is ill-formed. + +namespace foo { + extern "C" int main; // { dg-error "linkage" } + extern "C" struct A { + int main; // OK + }; + extern "C" struct B { + int main(); // OK + }; +}
I wasn't entirely sure what to do with the 'abi/main.C' testcase here; is this OK, or should I e.g. lower the linkage error to a pedwarn for the purposes of this test? Bootstrapped and regtested on x86_64-pc-linux-gnu, and lightly checked with a MinGW32 cross. OK for trunk? -- >8 -- This patch adds some missing requirements for legal main declarations, as according to [basic.start.main] p2. gcc/cp/ChangeLog: * decl.cc (grokfndecl): Check for main functions with language linkage or module attachment. (grokvardecl): Check for extern 'C' entities named main. gcc/testsuite/ChangeLog: * g++.dg/abi/main.C: Rework to avoid declaring main with language linkage. * g++.dg/modules/contracts-1_b.C: Don't declare main in named module. * g++.dg/modules/contracts-3_b.C: Likewise. * g++.dg/modules/contracts-4_d.C: Likewise. * g++.dg/modules/horcrux-1_a.C: Export declarations, so that... * g++.dg/modules/horcrux-1_b.C: Don't declare main in named module. * g++.dg/modules/main-1.C: New test. * g++.dg/parse/linkage5.C: New test. * g++.dg/parse/linkage6.C: New test. Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com> --- gcc/cp/decl.cc | 19 ++++++++++--- gcc/testsuite/g++.dg/abi/main.C | 29 ++++++++------------ gcc/testsuite/g++.dg/modules/contracts-1_b.C | 4 --- gcc/testsuite/g++.dg/modules/contracts-3_b.C | 4 --- gcc/testsuite/g++.dg/modules/contracts-4_d.C | 2 -- gcc/testsuite/g++.dg/modules/horcrux-1_a.C | 3 ++ gcc/testsuite/g++.dg/modules/horcrux-1_b.C | 2 +- gcc/testsuite/g++.dg/modules/main-1.C | 5 ++++ gcc/testsuite/g++.dg/parse/linkage5.C | 14 ++++++++++ gcc/testsuite/g++.dg/parse/linkage6.C | 13 +++++++++ 10 files changed, 63 insertions(+), 32 deletions(-) create mode 100644 gcc/testsuite/g++.dg/modules/main-1.C create mode 100644 gcc/testsuite/g++.dg/parse/linkage5.C create mode 100644 gcc/testsuite/g++.dg/parse/linkage6.C