Skip to content

Commit df1d786

Browse files
authored
[C2y] Support WG14 N3457, the __COUNTER__ macro (llvm#162662)
This implements the parts of https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3457.htm which were adopted at the recent meeting in Brno. Clang already implemented `__COUNTER__`, but needed some changes for conformance. Specifically, we now diagnose when the macro is expanded more than 2147483647 times. Additionally, we now give the expected extension and pre-compat warnings for the feature. To support testing the limits, this also adds a -cc1-only option, `-finitial-counter-value=`, which lets you specify the initial value the `__COUNTER__` macro should expand to.
1 parent ef9ff15 commit df1d786

File tree

16 files changed

+132
-15
lines changed

16 files changed

+132
-15
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,9 @@ Builtin Macros
385385

386386
``__COUNTER__``
387387
Defined to an integer value that starts at zero and is incremented each time
388-
the ``__COUNTER__`` macro is expanded.
388+
the ``__COUNTER__`` macro is expanded. This is a standard feature in C2y but
389+
is an extension in earlier language modes and in C++. This macro can only be
390+
expanded 2147483647 times at most.
389391

390392
``__INCLUDE_LEVEL__``
391393
Defined to an integral value that is the include depth of the file currently
@@ -1821,6 +1823,7 @@ Octal literals prefixed with ``0o`` or ``0O`` C
18211823
``_Countof`` (N3369, N3469) C2y C89
18221824
``_Generic`` with a type operand (N3260) C2y C89, C++
18231825
``++``/``--`` on ``_Complex`` value (N3259) C2y C89, C++
1826+
``__COUNTER__`` (N3457) C2y C89, C++
18241827
============================================= ================================ ============= =============
18251828

18261829
Builtin type aliases

clang/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,11 @@ C2y Feature Support
196196
function or variable within an extern inline function is no longer a
197197
constraint per `WG14 N3622 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3622.txt>`_.
198198
- Clang now supports `N3355 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3355.htm>`_ Named Loops.
199+
- Clang's implementation of ``__COUNTER__`` was updated to conform to
200+
`WG14 N3457 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3457.htm>`_.
201+
This includes adding pedantic warnings for the feature being an extension in
202+
other language modes as well as an error when the counter is expanded more
203+
than 2147483647 times.
199204

200205
C23 Feature Support
201206
^^^^^^^^^^^^^^^^^^^

clang/include/clang/Basic/DiagnosticLexKinds.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,14 @@ def err_unterminated___pragma : Error<"missing terminating ')' character">;
9090

9191
def err_conflict_marker : Error<"version control conflict marker in file">;
9292

93+
def err_counter_overflow : Error<
94+
"'__COUNTER__' value cannot exceed 2'147'483'647">;
95+
def ext_counter : Extension<
96+
"'__COUNTER__' is a C2y extension">, InGroup<C2y>;
97+
def warn_counter : Warning<
98+
"'__COUNTER__' is incompatible with standards before C2y">,
99+
InGroup<CPre2yCompat>, DefaultIgnore;
100+
93101
def err_raw_delim_too_long : Error<
94102
"raw string delimiter longer than 16 characters"
95103
"; use PREFIX( )PREFIX to delimit raw string">;

clang/include/clang/Driver/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8445,6 +8445,10 @@ def aligned_alloc_unavailable : Flag<["-"], "faligned-alloc-unavailable">,
84458445
MarshallingInfoFlag<LangOpts<"AlignedAllocationUnavailable">>,
84468446
ShouldParseIf<faligned_allocation.KeyPath>;
84478447

8448+
def finitial_counter_value_EQ : Joined<["-"], "finitial-counter-value=">,
8449+
HelpText<"Sets the initial value for __COUNTER__, defaults to 0.">,
8450+
MarshallingInfoInt<PreprocessorOpts<"InitialCounterValue">, "0">;
8451+
84488452
} // let Visibility = [CC1Option]
84498453

84508454
//===----------------------------------------------------------------------===//

clang/include/clang/Lex/Preprocessor.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ class Preprocessor {
226226
LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine;
227227

228228
// Next __COUNTER__ value, starts at 0.
229-
unsigned CounterValue = 0;
229+
uint32_t CounterValue = 0;
230230

231231
enum {
232232
/// Maximum depth of \#includes.
@@ -2421,8 +2421,8 @@ class Preprocessor {
24212421
bool SawDateOrTime() const {
24222422
return DATELoc != SourceLocation() || TIMELoc != SourceLocation();
24232423
}
2424-
unsigned getCounterValue() const { return CounterValue; }
2425-
void setCounterValue(unsigned V) { CounterValue = V; }
2424+
uint32_t getCounterValue() const { return CounterValue; }
2425+
void setCounterValue(uint32_t V) { CounterValue = V; }
24262426

24272427
LangOptions::FPEvalMethodKind getCurrentFPEvalMethod() const {
24282428
assert(CurrentFPEvalMethod != LangOptions::FEM_UnsetOnCommandLine &&

clang/include/clang/Lex/PreprocessorOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,10 @@ class PreprocessorOptions {
198198
/// If set, the UNIX timestamp specified by SOURCE_DATE_EPOCH.
199199
std::optional<uint64_t> SourceDateEpoch;
200200

201+
/// The initial value for __COUNTER__; typically is zero but can be set via a
202+
/// -cc1 flag for testing purposes.
203+
uint32_t InitialCounterValue = 0;
204+
201205
public:
202206
PreprocessorOptions() : PrecompiledPreambleBytes(0, false) {}
203207

clang/include/clang/Serialization/ASTReader.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,8 @@ class ASTReaderListener {
220220
}
221221

222222
/// Receives __COUNTER__ value.
223-
virtual void ReadCounter(const serialization::ModuleFile &M,
224-
unsigned Value) {}
223+
virtual void ReadCounter(const serialization::ModuleFile &M, uint32_t Value) {
224+
}
225225

226226
/// This is called for each AST file loaded.
227227
virtual void visitModuleFile(StringRef Filename,
@@ -312,7 +312,7 @@ class ChainedASTReaderListener : public ASTReaderListener {
312312
bool Complain,
313313
std::string &SuggestedPredefines) override;
314314

315-
void ReadCounter(const serialization::ModuleFile &M, unsigned Value) override;
315+
void ReadCounter(const serialization::ModuleFile &M, uint32_t Value) override;
316316
bool needsInputFileVisitation() override;
317317
bool needsSystemInputFileVisitation() override;
318318
void visitModuleFile(StringRef Filename,
@@ -352,7 +352,7 @@ class PCHValidator : public ASTReaderListener {
352352
StringRef ModuleFilename,
353353
StringRef SpecificModuleCachePath,
354354
bool Complain) override;
355-
void ReadCounter(const serialization::ModuleFile &M, unsigned Value) override;
355+
void ReadCounter(const serialization::ModuleFile &M, uint32_t Value) override;
356356
};
357357

358358
/// ASTReaderListenter implementation to set SuggestedPredefines of

clang/lib/Frontend/ASTUnit.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -518,14 +518,14 @@ class ASTInfoCollector : public ASTReaderListener {
518518
LangOptions &LangOpts;
519519
CodeGenOptions &CodeGenOpts;
520520
TargetOptions &TargetOpts;
521-
unsigned &Counter;
521+
uint32_t &Counter;
522522

523523
public:
524524
ASTInfoCollector(HeaderSearchOptions &HSOpts,
525525
std::string &SpecificModuleCachePath,
526526
PreprocessorOptions &PPOpts, LangOptions &LangOpts,
527527
CodeGenOptions &CodeGenOpts, TargetOptions &TargetOpts,
528-
unsigned &Counter)
528+
uint32_t &Counter)
529529
: HSOpts(HSOpts), SpecificModuleCachePath(SpecificModuleCachePath),
530530
PPOpts(PPOpts), LangOpts(LangOpts), CodeGenOpts(CodeGenOpts),
531531
TargetOpts(TargetOpts), Counter(Counter) {}
@@ -577,7 +577,7 @@ class ASTInfoCollector : public ASTReaderListener {
577577
}
578578

579579
void ReadCounter(const serialization::ModuleFile &M,
580-
unsigned NewCounter) override {
580+
uint32_t NewCounter) override {
581581
Counter = NewCounter;
582582
}
583583
};

clang/lib/Frontend/InitPreprocessor.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1542,6 +1542,9 @@ void clang::InitializePreprocessor(Preprocessor &PP,
15421542
llvm::raw_string_ostream Predefines(PredefineBuffer);
15431543
MacroBuilder Builder(Predefines);
15441544

1545+
// Ensure that the initial value of __COUNTER__ is hooked up.
1546+
PP.setCounterValue(InitOpts.InitialCounterValue);
1547+
15451548
// Emit line markers for various builtin sections of the file. The 3 here
15461549
// marks <built-in> as being a system header, which suppresses warnings when
15471550
// the same macro is defined multiple times.

clang/lib/Lex/PPMacroExpansion.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1735,7 +1735,19 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
17351735
Diag(getLastFPEvalPragmaLocation(), diag::note_pragma_entered_here);
17361736
}
17371737
} else if (II == Ident__COUNTER__) {
1738-
// __COUNTER__ expands to a simple numeric value.
1738+
Diag(Tok.getLocation(),
1739+
getLangOpts().C2y ? diag::warn_counter : diag::ext_counter);
1740+
// __COUNTER__ expands to a simple numeric value that must be less than
1741+
// 2147483647.
1742+
constexpr uint32_t MaxPosValue = std::numeric_limits<int32_t>::max();
1743+
if (CounterValue > MaxPosValue) {
1744+
Diag(Tok.getLocation(), diag::err_counter_overflow);
1745+
// Retain the maximal value so we don't issue conversion-related
1746+
// diagnostics by overflowing into a long long. While this does produce
1747+
// a duplicate value, there's no way to ignore this error so there's no
1748+
// translation anyway.
1749+
CounterValue = MaxPosValue;
1750+
}
17391751
OS << CounterValue++;
17401752
Tok.setKind(tok::numeric_constant);
17411753
} else if (II == Ident__has_feature) {

0 commit comments

Comments
 (0)