diff --git a/gcc/testsuite/g++.dg/modules/atom-preamble-2_a.C b/gcc/testsuite/g++.dg/modules/atom-preamble-2_a.C index 02fbd84afffa..46c4592411a6 100644 --- a/gcc/testsuite/g++.dg/modules/atom-preamble-2_a.C +++ b/gcc/testsuite/g++.dg/modules/atom-preamble-2_a.C @@ -1,6 +1,5 @@ // { dg-additional-options "-fmodules-ts" } -#define malcolm kevin -export module malcolm; +export module kevin; // { dg-module-cmi kevin } export class X; diff --git a/gcc/testsuite/g++.dg/modules/atom-preamble-4.C b/gcc/testsuite/g++.dg/modules/atom-preamble-4.C index 21a8d57da652..ada583932467 100644 --- a/gcc/testsuite/g++.dg/modules/atom-preamble-4.C +++ b/gcc/testsuite/g++.dg/modules/atom-preamble-4.C @@ -3,3 +3,5 @@ export module NAME(bob) +// { dg-error "module name followed by '\\\('" "" { target *-*-* } .-2 } +// { dg-error "expected ';' before '\\\(' token" "" { target *-*-* } .-3 } diff --git a/gcc/testsuite/g++.dg/modules/atom-preamble-5.C b/gcc/testsuite/g++.dg/modules/atom-preamble-5.C new file mode 100644 index 000000000000..5cd520aa855e --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/atom-preamble-5.C @@ -0,0 +1,5 @@ +// { dg-additional-options "-fmodules-ts" } +#define NAME(X) ; + +export module bob NAME(bob) + diff --git a/gcc/testsuite/g++.dg/modules/cpp-10.C b/gcc/testsuite/g++.dg/modules/cpp-10.C new file mode 100644 index 000000000000..43a492270190 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/cpp-10.C @@ -0,0 +1,7 @@ +// { dg-do preprocess } +// { dg-additional-options "-fmodules-ts" } + +#define bob fred; +export module foo:bob; // { dg-error "module partition 'bob' cannot be an object-like macro" } + +int i; diff --git a/gcc/testsuite/g++.dg/modules/cpp-11.C b/gcc/testsuite/g++.dg/modules/cpp-11.C new file mode 100644 index 000000000000..194593545652 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/cpp-11.C @@ -0,0 +1,7 @@ +// { dg-do preprocess } +// { dg-additional-options "-fmodules-ts" } + +#define bob fred; +export module foo:bar.bob; // { dg-error "module partition 'bob' cannot be an object-like macro" } + +int i; diff --git a/gcc/testsuite/g++.dg/modules/cpp-12.C b/gcc/testsuite/g++.dg/modules/cpp-12.C new file mode 100644 index 000000000000..7ba44e3807ab --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/cpp-12.C @@ -0,0 +1,7 @@ +// { dg-do preprocess } +// { dg-additional-options "-fmodules-ts" } + +#define baz .qux // { dg-error "'\\\.' in module name or partition comes from or after macro expansion" } +export module foo:bar baz; + +int i; diff --git a/gcc/testsuite/g++.dg/modules/cpp-13.C b/gcc/testsuite/g++.dg/modules/cpp-13.C new file mode 100644 index 000000000000..bd78ef489bee --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/cpp-13.C @@ -0,0 +1,7 @@ +// { dg-do preprocess } +// { dg-additional-options "-fmodules-ts" } + +#define baz :qux.garply // { dg-error "':' in module name or partition comes from or after macro expansion" } +export module foo.bar baz; + +int i; diff --git a/gcc/testsuite/g++.dg/modules/cpp-14.C b/gcc/testsuite/g++.dg/modules/cpp-14.C new file mode 100644 index 000000000000..2f4e06081844 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/cpp-14.C @@ -0,0 +1,7 @@ +// { dg-do preprocess } +// { dg-additional-options "-fmodules-ts" } + +#define baz [[]] +export module foo.bar baz; + +int i; diff --git a/gcc/testsuite/g++.dg/modules/cpp-15.C b/gcc/testsuite/g++.dg/modules/cpp-15.C new file mode 100644 index 000000000000..9249210319e0 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/cpp-15.C @@ -0,0 +1,8 @@ +// { dg-do preprocess } +// { dg-additional-options "-fmodules-ts" } + +#define baz +#define qux +export module foo.bar baz . garply qux; // { dg-error "'\\\.' in module name or partition comes from or after macro expansion" } + +int i; diff --git a/gcc/testsuite/g++.dg/modules/cpp-16.C b/gcc/testsuite/g++.dg/modules/cpp-16.C new file mode 100644 index 000000000000..c6c77313b78a --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/cpp-16.C @@ -0,0 +1,8 @@ +// { dg-do preprocess } +// { dg-additional-options "-fmodules-ts" } + +#define baz +#define qux +export module foo.bar baz : garply qux; // { dg-error "':' in module name or partition comes from or after macro expansion" } + +int i; diff --git a/gcc/testsuite/g++.dg/modules/cpp-17.C b/gcc/testsuite/g++.dg/modules/cpp-17.C new file mode 100644 index 000000000000..183c4fb79133 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/cpp-17.C @@ -0,0 +1,7 @@ +// { dg-do preprocess } +// { dg-additional-options "-fmodules-ts" } + +#define baz(x) x qux +export module foo:bar baz(.); // { dg-error "'\\\.' in module name or partition comes from or after macro expansion" } + +int i; diff --git a/gcc/testsuite/g++.dg/modules/cpp-18.C b/gcc/testsuite/g++.dg/modules/cpp-18.C new file mode 100644 index 000000000000..0efe331372e9 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/cpp-18.C @@ -0,0 +1,7 @@ +// { dg-do preprocess } +// { dg-additional-options "-fmodules-ts" } + +#define baz(x) x qux.garply +export module foo.bar baz(:); // { dg-error "':' in module name or partition comes from or after macro expansion" } + +int i; diff --git a/gcc/testsuite/g++.dg/modules/cpp-19.C b/gcc/testsuite/g++.dg/modules/cpp-19.C new file mode 100644 index 000000000000..57241b64bdd5 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/cpp-19.C @@ -0,0 +1,8 @@ +// { dg-do preprocess } +// { dg-additional-options "-fmodules-ts" } + +#define baz(x) +#define qux(x) +export module foo.bar baz(.) . garply qux(:); // { dg-error "'\\\.' in module name or partition comes from or after macro expansion" } + +int i; diff --git a/gcc/testsuite/g++.dg/modules/cpp-20.C b/gcc/testsuite/g++.dg/modules/cpp-20.C new file mode 100644 index 000000000000..acb2a2a69a2c --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/cpp-20.C @@ -0,0 +1,8 @@ +// { dg-do preprocess } +// { dg-additional-options "-fmodules-ts" } + +#define baz(x) +#define qux(x) +export module foo.bar baz(:) : garply qux(.); // { dg-error "':' in module name or partition comes from or after macro expansion" } + +int i; diff --git a/gcc/testsuite/g++.dg/modules/cpp-7.C b/gcc/testsuite/g++.dg/modules/cpp-7.C new file mode 100644 index 000000000000..48ea4d852671 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/cpp-7.C @@ -0,0 +1,8 @@ +// { dg-do preprocess } +// { dg-additional-options "-fmodules-ts" } + +#define NAME(X) X; + +export module NAME(bob) // { dg-error "module name followed by '\\\('" } + +int i; diff --git a/gcc/testsuite/g++.dg/modules/cpp-8.C b/gcc/testsuite/g++.dg/modules/cpp-8.C new file mode 100644 index 000000000000..2f533bcf7352 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/cpp-8.C @@ -0,0 +1,7 @@ +// { dg-do preprocess } +// { dg-additional-options "-fmodules-ts" } + +#define bob fred; +export module bob; // { dg-error "module name 'bob' cannot be an object-like macro" } + +int i; diff --git a/gcc/testsuite/g++.dg/modules/cpp-9.C b/gcc/testsuite/g++.dg/modules/cpp-9.C new file mode 100644 index 000000000000..c1849238e9cb --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/cpp-9.C @@ -0,0 +1,7 @@ +// { dg-do preprocess } +// { dg-additional-options "-fmodules-ts" } + +#define bob fred; +export module foo.bob; // { dg-error "module name 'bob' cannot be an object-like macro" } + +int i; diff --git a/gcc/testsuite/g++.dg/modules/dir-only-3.C b/gcc/testsuite/g++.dg/modules/dir-only-3.C index 6e3af8da45d1..40e02bf448fa 100644 --- a/gcc/testsuite/g++.dg/modules/dir-only-3.C +++ b/gcc/testsuite/g++.dg/modules/dir-only-3.C @@ -7,10 +7,12 @@ # 32 "" 2 # 1 "dir-only-3.C" // { dg-additional-options {-fmodules-ts -fpreprocessed -fdirectives-only} } -// { dg-module-cmi foo } +// { dg-module-cmi !foo } module; #define foo baz export module foo; +// { dg-error "module name 'foo' cannot be an object-like macro" "" { target *-*-* } 5 } +// { dg-prune-output "not writing module" } class import {}; diff --git a/gcc/testsuite/g++.dg/modules/dir-only-4.C b/gcc/testsuite/g++.dg/modules/dir-only-4.C index 9cb0587c0aa1..6859a74d2276 100644 --- a/gcc/testsuite/g++.dg/modules/dir-only-4.C +++ b/gcc/testsuite/g++.dg/modules/dir-only-4.C @@ -2,7 +2,7 @@ // { dg-module-cmi !foo } module; #define foo baz -export module foo; +export module foo; // { dg-error "module name 'foo' cannot be an object-like macro" } class import {}; diff --git a/gcc/testsuite/g++.dg/modules/dir-only-5.C b/gcc/testsuite/g++.dg/modules/dir-only-5.C new file mode 100644 index 000000000000..cbbfe2090562 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/dir-only-5.C @@ -0,0 +1,9 @@ +// { dg-additional-options {-fmodules-ts -fpreprocessed -fdirectives-only} } +// { dg-module-cmi !baz } +module; +#define foo baz +export module baz; + +class import {}; + +import x; // { dg-error "post-module-declaration" } diff --git a/gcc/testsuite/g++.dg/modules/pmp-4.C b/gcc/testsuite/g++.dg/modules/pmp-4.C new file mode 100644 index 000000000000..1244f3bd3513 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pmp-4.C @@ -0,0 +1,9 @@ +// { dg-additional-options -fmodules-ts } + +export module bob; +// { dg-module-cmi bob } + +#define PRIVATE private + +module :PRIVATE; // { dg-message "sorry, unimplemented: private module fragment" } +int i; diff --git a/gcc/testsuite/g++.dg/modules/pmp-5.C b/gcc/testsuite/g++.dg/modules/pmp-5.C new file mode 100644 index 000000000000..eb57d19d3eb1 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pmp-5.C @@ -0,0 +1,9 @@ +// { dg-additional-options -fmodules-ts } + +export module bob; +// { dg-module-cmi bob } + +#define PRIVATE_SEMI private ; + +module :PRIVATE_SEMI // { dg-message "sorry, unimplemented: private module fragment" } +int i; diff --git a/gcc/testsuite/g++.dg/modules/pmp-6.C b/gcc/testsuite/g++.dg/modules/pmp-6.C new file mode 100644 index 000000000000..87045872b04c --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pmp-6.C @@ -0,0 +1,9 @@ +// { dg-additional-options -fmodules-ts } + +export module bob; +// { dg-module-cmi bob } + +#define SEMI ; + +module :private SEMI // { dg-message "sorry, unimplemented: private module fragment" } +int i; diff --git a/gcc/testsuite/g++.dg/modules/token-10.C b/gcc/testsuite/g++.dg/modules/token-10.C new file mode 100644 index 000000000000..a6ad94bc9acd --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/token-10.C @@ -0,0 +1,6 @@ +// { dg-additional-options "-fmodules-ts" } + +#define semi ; +export module foo.bar:baz.bob semi + +// { dg-module-cmi foo.bar:baz.bob } diff --git a/gcc/testsuite/g++.dg/modules/token-11.C b/gcc/testsuite/g++.dg/modules/token-11.C new file mode 100644 index 000000000000..ec5004ba39ee --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/token-11.C @@ -0,0 +1,6 @@ +// { dg-additional-options "-fmodules-ts" } + +#define attr [[]] +export module foo.bar:baz.bob attr ; + +// { dg-module-cmi foo.bar:baz.bob } diff --git a/gcc/testsuite/g++.dg/modules/token-12.C b/gcc/testsuite/g++.dg/modules/token-12.C new file mode 100644 index 000000000000..76b028bb73fc --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/token-12.C @@ -0,0 +1,6 @@ +// { dg-additional-options "-fmodules-ts" } + +#define bob() fred +export module bob; + +// { dg-module-cmi bob } diff --git a/gcc/testsuite/g++.dg/modules/token-13.C b/gcc/testsuite/g++.dg/modules/token-13.C new file mode 100644 index 000000000000..79e306f3872c --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/token-13.C @@ -0,0 +1,6 @@ +// { dg-additional-options "-fmodules-ts" } + +#define bob() fred +export module foo.bar.bob; + +// { dg-module-cmi foo.bar.bob } diff --git a/gcc/testsuite/g++.dg/modules/token-14.C b/gcc/testsuite/g++.dg/modules/token-14.C new file mode 100644 index 000000000000..e8bef6fe8e85 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/token-14.C @@ -0,0 +1,6 @@ +// { dg-additional-options "-fmodules-ts" } + +#define bob(n) fred +export module foo.bar:bob; + +// { dg-module-cmi foo.bar:bob } diff --git a/gcc/testsuite/g++.dg/modules/token-15.C b/gcc/testsuite/g++.dg/modules/token-15.C new file mode 100644 index 000000000000..484973d70140 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/token-15.C @@ -0,0 +1,6 @@ +// { dg-additional-options "-fmodules-ts" } + +#define bob() fred +export module foo.bar:baz.bob; + +// { dg-module-cmi foo.bar:baz.bob } diff --git a/gcc/testsuite/g++.dg/modules/token-16.C b/gcc/testsuite/g++.dg/modules/token-16.C new file mode 100644 index 000000000000..7ed524c40b0f --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/token-16.C @@ -0,0 +1,9 @@ +// { dg-additional-options "-fmodules-ts" } + +#define bob() fred +export module foo.bar:baz.bob (); +// { dg-error "module partition followed by '\\\('" "" { target *-*-* } .-1 } +// { dg-error "expected" "" { target *-*-* } .-2 } + +// { dg-module-cmi !foo.bar:baz.bob } +// { dg-module-cmi !foo.bar:baz.fred } diff --git a/gcc/testsuite/g++.dg/modules/token-6.C b/gcc/testsuite/g++.dg/modules/token-6.C new file mode 100644 index 000000000000..22394037c630 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/token-6.C @@ -0,0 +1,9 @@ +// { dg-additional-options "-fmodules-ts" } + +#define bob fred +export module bob; +// { dg-error "module name 'bob' cannot be an object-like macro" "" { target *-*-* } .-1 } + +// { dg-module-cmi !bob } +// { dg-module-cmi !fred } +// { dg-prune-output "not writing module" } diff --git a/gcc/testsuite/g++.dg/modules/token-7.C b/gcc/testsuite/g++.dg/modules/token-7.C new file mode 100644 index 000000000000..165e2c1a8273 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/token-7.C @@ -0,0 +1,9 @@ +// { dg-additional-options "-fmodules-ts" } + +#define bob fred +export module foo.bar.bob; +// { dg-error "module name 'bob' cannot be an object-like macro" "" { target *-*-* } .-1 } + +// { dg-module-cmi !foo.bar.bob } +// { dg-module-cmi !foo.bar.fred } +// { dg-prune-output "not writing module" } diff --git a/gcc/testsuite/g++.dg/modules/token-8.C b/gcc/testsuite/g++.dg/modules/token-8.C new file mode 100644 index 000000000000..1316933a6976 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/token-8.C @@ -0,0 +1,9 @@ +// { dg-additional-options "-fmodules-ts" } + +#define bob fred +export module foo.bar:bob; +// { dg-error "module partition 'bob' cannot be an object-like macro" "" { target *-*-* } .-1 } + +// { dg-module-cmi !foo.bar:bob } +// { dg-module-cmi !foo.bar:fred } +// { dg-prune-output "not writing module" } diff --git a/gcc/testsuite/g++.dg/modules/token-9.C b/gcc/testsuite/g++.dg/modules/token-9.C new file mode 100644 index 000000000000..39eff81a1af2 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/token-9.C @@ -0,0 +1,9 @@ +// { dg-additional-options "-fmodules-ts" } + +#define garply fred +export module foo.bar:baz.garply; +// { dg-error "module partition 'garply' cannot be an object-like macro" "" { target *-*-* } .-1 } + +// { dg-module-cmi !foo.bar:baz.garply } +// { dg-module-cmi !foo.bar:baz.fred } +// { dg-prune-output "not writing module" } diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h index f2ed0877c647..267d28147abb 100644 --- a/libcpp/include/cpplib.h +++ b/libcpp/include/cpplib.h @@ -204,6 +204,9 @@ struct GTY(()) cpp_string { #define PURE_ZERO (1 << 7) /* Single 0 digit, used by the C++ frontend, set in c-lex.cc. */ #define COLON_SCOPE PURE_ZERO /* Adjacent colons in C < 23. */ +#define NO_DOT_COLON PURE_ZERO /* Set on CPP_NAME tokens whose expansion + shouldn't start with CPP_DOT or CPP_COLON + after optional CPP_PADDING. */ #define SP_DIGRAPH (1 << 8) /* # or ## token was a digraph. */ #define SP_PREV_WHITE (1 << 9) /* If whitespace before a ## operator, or before this token diff --git a/libcpp/internal.h b/libcpp/internal.h index 9ded9a77d5b3..e65198e89daa 100644 --- a/libcpp/internal.h +++ b/libcpp/internal.h @@ -468,6 +468,10 @@ struct cpp_reader one. */ bool about_to_expand_macro_p; + /* True if the preprocessor should diagnose CPP_DOT or CPP_COLON + tokens as the first ones coming from macro expansion. */ + bool diagnose_dot_colon_from_macro_p; + /* Search paths for include files. */ struct cpp_dir *quote_include; /* "" */ struct cpp_dir *bracket_include; /* <> */ diff --git a/libcpp/lex.cc b/libcpp/lex.cc index 4bd463093914..849447eb4d79 100644 --- a/libcpp/lex.cc +++ b/libcpp/lex.cc @@ -3604,6 +3604,78 @@ cpp_maybe_module_directive (cpp_reader *pfile, cpp_token *result) /* Maybe tell the tokenizer we expect a header-name down the road. */ pfile->state.directive_file_token = header_count; + + /* According to P3034R1, pp-module-name and pp-module-partition tokens + if any shouldn't be macro expanded and identifiers shouldn't be + defined as object-like macro. */ + if (!header_count && peek->type == CPP_NAME) + { + int state = 0; + do + { + cpp_token *tok = peek; + if (tok->type == CPP_NAME) + { + cpp_hashnode *node = tok->val.node.node; + /* Don't attempt to expand the token. */ + tok->flags |= NO_EXPAND; + if (_cpp_defined_macro_p (node) + && _cpp_maybe_notify_macro_use (pfile, node, + tok->src_loc) + && !cpp_fun_like_macro_p (node)) + { + if (state == 0) + cpp_error_with_line (pfile, CPP_DL_ERROR, + tok->src_loc, 0, + "module name %qs cannot " + "be an object-like macro", + NODE_NAME (node)); + else + cpp_error_with_line (pfile, CPP_DL_ERROR, + tok->src_loc, 0, + "module partition %qs cannot " + "be an object-like macro", + NODE_NAME (node)); + } + } + peek = _cpp_lex_direct (pfile); + backup++; + if (tok->type == CPP_NAME) + { + if (peek->type == CPP_DOT) + continue; + else if (peek->type == CPP_COLON && state == 0) + { + ++state; + continue; + } + else if (peek->type == CPP_OPEN_PAREN) + { + if (state == 0) + cpp_error_with_line (pfile, CPP_DL_ERROR, + peek->src_loc, 0, + "module name followed by %<(%>"); + else + cpp_error_with_line (pfile, CPP_DL_ERROR, + peek->src_loc, 0, + "module partition followed by " + "%<(%>"); + break; + } + else if (peek->type == CPP_NAME + && _cpp_defined_macro_p (peek->val.node.node)) + { + peek->flags |= NO_DOT_COLON; + break; + } + else + break; + } + else if (peek->type != CPP_NAME) + break; + } + while (true); + } } else { diff --git a/libcpp/macro.cc b/libcpp/macro.cc index 3ad1eb705417..907af873df16 100644 --- a/libcpp/macro.cc +++ b/libcpp/macro.cc @@ -3076,6 +3076,9 @@ cpp_get_token_1 (cpp_reader *pfile, location_t *location) if (pfile->state.prevent_expansion) break; + if ((result->flags & NO_DOT_COLON) != 0) + pfile->diagnose_dot_colon_from_macro_p = true; + /* Conditional macros require that a predicate be evaluated first. */ if ((node->flags & NODE_CONDITIONAL) != 0) @@ -3226,6 +3229,20 @@ cpp_get_token_1 (cpp_reader *pfile, location_t *location) } } + if (pfile->diagnose_dot_colon_from_macro_p + && !pfile->about_to_expand_macro_p + && result->type != CPP_PADDING + && result->type != CPP_COMMENT) + { + if (result->type == CPP_DOT || result->type == CPP_COLON) + cpp_error_with_line (pfile, CPP_DL_ERROR, + result->src_loc, 0, + "%qc in module name or partition " + "comes from or after macro expansion", + result->type == CPP_DOT ? '.' : ':'); + pfile->diagnose_dot_colon_from_macro_p = false; + } + return result; }