<!doctype html><html lang="en">
 <head>
  <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  <meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport">
  <title>P3423R0: Extending User-Generated Diagnostic Messages</title>
<style data-fill-with="stylesheet">/******************************************************************************
 *                   Style sheet for the W3C specifications                   *
 *
 * Special classes handled by this style sheet include:
 *
 * Indices
 *   - .toc for the Table of Contents (<ol class="toc">)
 *     + <span class="secno"> for the section numbers
 *   - #toc for the Table of Contents (<nav id="toc">)
 *   - ul.index for Indices (<a href="#ref">term</a><span>, in § N.M</span>)
 *   - table.index for Index Tables (e.g. for properties or elements)
 *
 * Structural Markup
 *   - table.data for general data tables
 *     -> use 'scope' attribute, <colgroup>, <thead>, and <tbody> for best results !
 *     -> use <table class='complex data'> for extra-complex tables
 *     -> use <td class='long'> for paragraph-length cell content
 *     -> use <td class='pre'> when manual line breaks/indentation would help readability
 *   - dl.switch for switch statements
 *   - ol.algorithm for algorithms (helps to visualize nesting)
 *   - .figure and .caption (HTML4) and figure and figcaption (HTML5)
 *     -> .sidefigure for right-floated figures
 *   - ins/del
 *     -> ins/del.c### for candidate and proposed changes (amendments)
 *
 * Code
 *   - pre and code
 *
 * Special Sections
 *   - .note       for informative notes             (div, p, span, aside, details)
 *   - .example    for informative examples          (div, p, pre, span)
 *   - .issue      for issues                        (div, p, span)
 *   - .advisement for loud normative statements     (div, p, strong)
 *   - .annoying-warning for spec obsoletion notices (div, aside, details)
 *   - .correction for "candidate corrections"       (div, aside, details, section)
 *   - .addition   for "candidate additions"         (div, aside, details, section)
 *   - .correction.proposed for "proposed corrections" (div, aside, details, section)
 *   - .addition.proposed   for "proposed additions"   (div, aside, details, section)
 *
 * Definition Boxes
 *   - pre.def   for WebIDL definitions
 *   - table.def for tables that define other entities (e.g. CSS properties)
 *   - dl.def    for definition lists that define other entitles (e.g. HTML elements)
 *
 * Numbering
 *   - .secno for section numbers in .toc and headings (<span class='secno'>3.2</span>)
 *   - .marker for source-inserted example/figure/issue numbers (<span class='marker'>Issue 4</span>)
 *   - ::before styled for CSS-generated issue/example/figure numbers:
 *     -> Documents wishing to use this only need to add
 *        figcaption::before,
 *        .caption::before { content: "Figure "  counter(figure) " ";  }
 *        .example::before { content: "Example " counter(example) " "; }
 *        .issue::before   { content: "Issue "   counter(issue) " ";   }
 *
 * Header Stuff (ignore, just don't conflict with these classes)
 *   - .head for the header
 *   - .copyright for the copyright
 *
 * Outdated warning for old specs
 *
 * Miscellaneous
 *   - .overlarge for things that should be as wide as possible, even if
 *     that overflows the body text area. This can be used on an item or
 *     on its container, depending on the effect desired.
 *     Note that this styling basically doesn't help at all when printing,
 *     since A4 paper isn't much wider than the max-width here.
 *     It's better to design things to fit into a narrower measure if possible.
 *
 *   - js-added ToC jump links (see fixup.js)
 *
 ******************************************************************************/

/* color variables included separately for reliability */

/******************************************************************************/
/*                                    Body                                    */
/******************************************************************************/

	html {
	}

	body {
		counter-reset: example figure issue;

		/* Layout */
		max-width: 50em;			  /* limit line length to 50em for readability   */
		margin: 0 auto;				/* center text within page                    */
		padding: 1.6em 1.5em 2em 50px; /* assume 16px font size for downlevel clients */
		padding: 1.6em 1.5em 2em calc(26px + 1.5em); /* leave space for status flag    */

		/* Typography */
		line-height: 1.5;
		font-family: sans-serif;
		widows: 2;
		orphans: 2;
		word-wrap: break-word;
		overflow-wrap: break-word;
		hyphens: auto;

		color: black;
		color: var(--text);
		background: white top left fixed no-repeat;
		background: var(--bg) top left fixed no-repeat;
		background-size: 25px auto;
	}


/******************************************************************************/
/*                         Front Matter & Navigation                          */
/******************************************************************************/

/** Header ********************************************************************/

	div.head { margin-bottom: 1em; }
	div.head hr { border-style: solid; }

	div.head h1 {
		font-weight: bold;
		margin: 0 0 .1em;
		font-size: 220%;
	}

	div.head h2 { margin-bottom: 1.5em;}

/** W3C Logo ******************************************************************/

	.head .logo {
		float: right;
		margin: 0.4rem 0 0.2rem .4rem;
	}

	.head img[src*="logos/W3C"] {
		display: block;
		border: solid #1a5e9a;
		border: solid var(--logo-bg);
		border-width: .65rem .7rem .6rem;
		border-radius: .4rem;
		background: #1a5e9a;
		background: var(--logo-bg);
		color: white;
		color: var(--logo-text);
		font-weight: bold;
	}

	.head a:hover > img[src*="logos/W3C"],
	.head a:focus > img[src*="logos/W3C"] {
		opacity: .8;
	}

	.head a:active > img[src*="logos/W3C"] {
		background: #c00;
		background: var(--logo-active-bg);
		border-color: #c00;
		border-color: var(--logo-active-bg);
	}

	/* see also additional rules in Link Styling section */

/** Copyright *****************************************************************/

	p.copyright,
	p.copyright small { font-size: small; }

/** Back to Top / ToC Toggle **************************************************/

	@media print {
		#toc-nav {
			display: none;
		}
	}
	@media not print {
		#toc-nav {
			position: fixed;
			z-index: 3;
			bottom: 0; left: 0;
			margin: 0;
			min-width: 1.33em;
			border-top-right-radius: 2rem;
			box-shadow: 0 0 2px;
			font-size: 1.5em;
		}
		#toc-nav > a {
			display: block;
			white-space: nowrap;

			height: 1.33em;
			padding: .1em 0.3em;
			margin: 0;

			box-shadow: 0 0 2px;
			border: none;
			border-top-right-radius: 1.33em;

			color: #707070;
			color: var(--tocnav-normal-text);
			background: white;
			background: var(--tocnav-normal-bg);
		}
		#toc-nav > a:hover,
		#toc-nav > a:focus {
			color: black;
			color: var(--tocnav-hover-text);
			background: #f8f8f8;
			background: var(--tocnav-hover-bg);
		}
		#toc-nav > a:active {
			color: #c00;
			color: var(--tocnav-active-text);
			background: white;
			background: var(--tocnav-active-bg);
		}

		#toc-nav > #toc-jump {
			padding-bottom: 2em;
			margin-bottom: -1.9em;
		}

		/* statusbar gets in the way on keyboard focus; remove once browsers fix */
		#toc-nav > a[href="#toc"]:not(:hover):focus:last-child {
			padding-bottom: 1.5rem;
		}

		#toc-nav:not(:hover) > a:not(:focus) > span + span {
			/* Ideally this uses :focus-within on #toc-nav */
			display: none;
		}
		#toc-nav > a > span + span {
			padding-right: 0.2em;
		}
	}

/** ToC Sidebar ***************************************************************/

	/* Floating sidebar */
	@media screen {
		body.toc-sidebar #toc {
			position: fixed;
			top: 0; bottom: 0;
			left: 0;
			width: 23.5em;
			max-width: 80%;
			max-width: calc(100% - 2em - 26px);
			overflow: auto;
			padding: 0 1em;
			padding-left: 42px;
			padding-left: calc(1em + 26px);
			color: black;
			color: var(--tocsidebar-text);
			background: inherit;
			background-color: #f7f8f9;
			background-color: var(--tocsidebar-bg);
			z-index: 1;
			box-shadow: -.1em 0 .25em rgba(0,0,0,.1) inset;
			box-shadow: -.1em 0 .25em var(--tocsidebar-shadow) inset;
		}
		body.toc-sidebar #toc h2 {
			margin-top: .8rem;
			font-variant: small-caps;
			font-variant: all-small-caps;
			text-transform: lowercase;
			font-weight: bold;
			color: gray;
			color: hsla(203,20%,40%,.7);
			color: var(--tocsidebar-heading-text);
		}
		body.toc-sidebar #toc-jump:not(:focus) {
			width: 0;
			height: 0;
			padding: 0;
			position: absolute;
			overflow: hidden;
		}
	}
	/* Hide main scroller when only the ToC is visible anyway */
	@media screen and (max-width: 28em) {
		body.toc-sidebar {
			overflow: hidden;
		}
	}

	/* Sidebar with its own space */
	@media screen and (min-width: 78em) {
		body:not(.toc-inline) #toc {
			position: fixed;
			top: 0; bottom: 0;
			left: 0;
			width: 23.5em;
			overflow: auto;
			padding: 0 1em;
			padding-left: 42px;
			padding-left: calc(1em + 26px);
			color: black;
			color: var(--tocsidebar-text);
			background: inherit;
			background-color: #f7f8f9;
			background-color: var(--tocsidebar-bg);
			z-index: 1;
			box-shadow: -.1em 0 .25em rgba(0,0,0,.1) inset;
			box-shadow: -.1em 0 .25em var(--tocsidebar-shadow) inset;
		}
		body:not(.toc-inline) #toc h2 {
			margin-top: .8rem;
			font-variant: small-caps;
			font-variant: all-small-caps;
			text-transform: lowercase;
			font-weight: bold;
			color: gray;
			color: hsla(203,20%,40%,.7);
			color: var(--tocsidebar-heading-text);
		}

		body:not(.toc-inline) {
			padding-left: 29em;
		}
		/* See also Overflow section at the bottom */

		body:not(.toc-inline) #toc-jump:not(:focus) {
			width: 0;
			height: 0;
			padding: 0;
			position: absolute;
			overflow: hidden;
		}
	}
	@media screen and (min-width: 90em) {
		body:not(.toc-inline) {
			margin: 0 4em;
		}
	}

/******************************************************************************/
/*                                Sectioning                                  */
/******************************************************************************/

/** Headings ******************************************************************/

	h1, h2, h3, h4, h5, h6, dt {
		page-break-after: avoid;
		page-break-inside: avoid;
		font: 100% sans-serif;   /* Reset all font styling to clear out UA styles */
		font-family: inherit;	/* Inherit the font family. */
		line-height: 1.2;		/* Keep wrapped headings compact */
		hyphens: manual;		/* Hyphenated headings look weird */
	}

	h2, h3, h4, h5, h6 {
		margin-top: 3rem;
	}

	h1, h2, h3 {
		color: #005A9C;
		color: var(--heading-text);
	}

	h1 { font-size: 170%; }
	h2 { font-size: 140%; }
	h3 { font-size: 120%; }
	h4 { font-weight: bold; }
	h5 { font-style: italic; }
	h6 { font-variant: small-caps; }
	dt { font-weight: bold; }

/** Subheadings ***************************************************************/

	h1 + h2,
	#profile-and-date {
		/* #profile-and-date is a subtitle in an H2 under the H1 */
		margin-top: 0;
	}
	h2 + h3,
	h3 + h4,
	h4 + h5,
	h5 + h6 {
		margin-top: 1.2em; /* = 1 x line-height */
	}

/** Section divider ***********************************************************/

	:not(.head) > :not(.head) + hr {
		font-size: 1.5em;
		text-align: center;
		margin: 1em auto;
		height: auto;
		color: black;
		color: var(--hr-text);
		border: transparent solid 0;
		background: transparent;
	}
	:not(.head) > hr::before {
		content: "\2727\2003\2003\2727\2003\2003\2727";
	}

/******************************************************************************/
/*                            Paragraphs and Lists                            */
/******************************************************************************/

	p {
		margin: 1em 0;
	}

	dd > p:first-child,
	li > p:first-child {
		margin-top: 0;
	}

	ul, ol {
		margin-left: 0;
		padding-left: 2em;
	}

	li {
		margin: 0.25em 0 0.5em;
		padding: 0;
	}

	dl dd {
		margin: 0 0 .5em 2em;
	}

	.head dd + dd { /* compact for header */
		margin-top: -.5em;
	}

	/* Style for algorithms */
	ol.algorithm ol:not(.algorithm),
	.algorithm > ol ol:not(.algorithm) {
	border-left: 0.5em solid #DEF;
	border-left: 0.5em solid var(--algo-border);
	}

	/* Put nice boxes around each algorithm. */
	[data-algorithm]:not(.heading) {
	 padding: .5em;
	 border: thin solid #ddd;
	 border: thin solid var(--algo-border);
	 border-radius: .5em;
	 margin: .5em calc(-0.5em - 1px);
	}
	[data-algorithm]:not(.heading) > :first-child {
	 margin-top: 0;
	}
	[data-algorithm]:not(.heading) > :last-child {
	 margin-bottom: 0;
	}

	/* Style for switch/case <dl>s */
	dl.switch > dd > ol.only,
	dl.switch > dd > .only > ol {
	margin-left: 0;
	}
	dl.switch > dd > ol.algorithm,
	dl.switch > dd > .algorithm > ol {
	margin-left: -2em;
	}
	dl.switch {
	padding-left: 2em;
	}
	dl.switch > dt {
	text-indent: -1.5em;
	margin-top: 1em;
	}
	dl.switch > dt + dt {
	margin-top: 0;
	}
	dl.switch > dt::before {
	content: '\21AA';
	padding: 0 0.5em 0 0;
	display: inline-block;
	width: 1em;
	text-align: right;
	line-height: 0.5em;
	}

/** Terminology Markup ********************************************************/


/******************************************************************************/
/*                                 Inline Markup                              */
/******************************************************************************/

/** Terminology Markup ********************************************************/
	dfn   { /* Defining instance */
		font-weight: bolder;
	}
	a > i { /* Instance of term */
		font-style: normal;
	}
	dt dfn code, code.idl {
		font-size: inherit;
	}
	dfn var {
		font-style: normal;
	}

/** Change Marking ************************************************************/

	del {
		color: #aa0000;
		color: var(--del-text);
		background: transparent;
		background: var(--del-bg);
		text-decoration: line-through;
	}
	ins {
		color: #006100;
		color: var(--ins-text);
		background: transparent;
		background: var(--ins-bg);
		text-decoration: underline;
	}

	/* for amendments (candidate/proposed changes) */

	.amendment ins, .correction ins, .addition ins,
	ins[class^=c] {
		text-decoration-style: dotted;
	}
	.amendment del, .correction del, .addition del,
	del[class^=c] {
		text-decoration-style: dotted;
	}
	.amendment.proposed ins, .correction.proposed ins, .addition.proposed ins,
	ins[class^=c].proposed {
		text-decoration-style: double;
	}
	.amendment.proposed del, .correction.proposed del, .addition.proposed del,
	del[class^=c].proposed {
		text-decoration-style: double;
	}

/** Miscellaneous improvements to inline formatting ***************************/

	sup {
		vertical-align: super;
		font-size: 80%
	}

/******************************************************************************/
/*                                    Code                                    */
/******************************************************************************/

/** General monospace/pre rules ***********************************************/

	pre, code, samp {
		font-family: Menlo, Consolas, "DejaVu Sans Mono", Monaco, monospace;
		font-size: .9em;
		hyphens: none;
		text-transform: none;
		text-align: left;
		text-align: start;
		font-variant: normal;
		orphans: 3;
		widows: 3;
		page-break-before: avoid;
	}
	pre code,
	code code {
		font-size: 100%;
	}

	pre {
		margin-top: 1em;
		margin-bottom: 1em;
		overflow: auto;
	}

/** Inline Code fragments *****************************************************/

	/* Do something nice. */

/******************************************************************************/
/*                                    Links                                   */
/******************************************************************************/

/** General Hyperlinks ********************************************************/

	/* We hyperlink a lot, so make it less intrusive */
	a[href] {
		color: #034575;
		color: var(--a-normal-text);
		text-decoration: underline #707070;
		text-decoration: underline var(--a-normal-underline);
		text-decoration-skip-ink: none;
	}
	a:visited {
		color: #034575;
		color: var(--a-visited-text);
		text-decoration-color: #bbb;
		text-decoration-color: var(--a-visited-underline);
	}

	/* Indicate interaction with the link */
	a[href]:focus,
	a[href]:hover {
		text-decoration-thickness: 2px;
	}
	a[href]:active {
		color: #c00;
		color: var(--a-active-text);
		text-decoration-color: #c00;
		text-decoration-color: var(--a-active-underline);
	}

	/* Backout above styling for W3C logo */
	.head .logo,
	.head .logo a {
		border: none;
		text-decoration: none;
		background: transparent;
	}

/******************************************************************************/
/*                                    Images                                  */
/******************************************************************************/

	img {
		border-style: none;
	}

	img, svg {
		/* Intentionally not color-scheme aware. */
		background: white;
	}

	/* For autogen numbers, add
	  .caption::before, figcaption::before { content: "Figure " counter(figure) ". "; }
	*/

	figure, .figure, .sidefigure {
		page-break-inside: avoid;
		text-align: center;
		margin: 2.5em 0;
	}
	.figure img,	.sidefigure img,	figure img,
	.figure object, .sidefigure object, figure object {
		max-width: 100%;
		margin: auto;
		height: auto;
	}
	.figure pre, .sidefigure pre, figure pre {
		text-align: left;
		display: table;
		margin: 1em auto;
	}
	.figure table, figure table {
		margin: auto;
	}
	@media screen and (min-width: 20em) {
		.sidefigure {
			float: right;
			width: 50%;
			margin: 0 0 0.5em 0.5em;
		}
	}
	.caption, figcaption, caption {
		font-style: italic;
		font-size: 90%;
	}
	.caption::before, figcaption::before, figcaption > .marker {
		font-weight: bold;
	}
	.caption, figcaption {
		counter-increment: figure;
	}

	/* DL list is indented 2em, but figure inside it is not */
	dd > .figure, dd > figure { margin-left: -2em; }

/******************************************************************************/
/*                             Colored Boxes                                  */
/******************************************************************************/

	.issue, .note, .example, .assertion, .advisement, blockquote,
	.amendment, .correction, .addition {
		margin: 1em auto;
		padding: .5em;
		border: .5em;
		border-left-style: solid;
		page-break-inside: avoid;
	}
	span.issue, span.note {
		padding: .1em .5em .15em;
		border-right-style: solid;
	}

	blockquote > :first-child,
	.note  > p:first-child,
	.issue > p:first-child,
	.amendment > p:first-child,
	.correction > p:first-child,
	.addition > p:first-child {
		margin-top: 0;
	}
	blockquote > :last-child,
	.note  > p:last-child,
	.issue > p:last-child,
	.amendment > p:last-child,
	.correction > p:last-child,
	.addition > p:last-child {
		margin-bottom: 0;
	}


	.issue::before, .issue > .marker,
	.example::before, .example > .marker,
	.note::before, .note > .marker,
	details.note > summary > .marker,
	.amendment::before, .amendment > .marker,
	details.amendment > summary > .marker,
	.addition::before, .addition > .marker,
	addition.amendment > summary > .marker,
	.correction::before, .correction > .marker,
	correction.amendment > summary > .marker
	{
		text-transform: uppercase;
		padding-right: 1em;
	}

	.example::before, .example > .marker {
		display: block;
		padding-right: 0em;
	}

/** Blockquotes ***************************************************************/

	blockquote {
		border-color: silver;
		border-color: var(--blockquote-border);
		background: transparent;
		background: var(--blockquote-bg);
		color: currentcolor;
		color: var(--blockquote-text);
	}

/** Open issue ****************************************************************/

	.issue {
		border-color: #e05252;
		border-color: var(--issue-border);
		background: #fbe9e9;
		background: var(--issue-bg);
		color: black;
		color: var(--issue-text);
		counter-increment: issue;
		overflow: auto;
	}
	.issue::before, .issue > .marker {
		color: #831616;
		color: var(--issueheading-text);
	}
	/* Add .issue::before { content: "Issue " counter(issue) " "; } for autogen numbers,
	  or use class="marker" to mark up the issue number in source. */

/** Example *******************************************************************/

	.example {
		border-color: #e0cb52;
		border-color: var(--example-border);
		background: #fcfaee;
		background: var(--example-bg);
		color: black;
		color: var(--example-text);
		counter-increment: example;
		overflow: auto;
		clear: both;
	}
	.example::before, .example > .marker {
		color: #574b0f;
		color: var(--exampleheading-text);
	}
	/* Add .example::before { content: "Example " counter(example) " "; } for autogen numbers,
	  or use class="marker" to mark up the example number in source. */

/** Non-normative Note ********************************************************/

	.note {
		border-color: #52e052;
		border-color: var(--note-border);
		background: #e9fbe9;
		background: var(--note-bg);
		color: black;
		color: var(--note-text);
		overflow: auto;
	}

	.note::before, .note > .marker,
	details.note > summary {
		color: hsl(120, 70%, 30%);
		color: var(--noteheading-text);
	}
	/* Add .note::before { content: "Note "; } for autogen label,
	  or use class="marker" to mark up the label in source. */

	details.note[open] > summary {
		border-bottom: 1px silver solid;
		border-bottom: 1px var(--notesummary-underline) solid;
	}

/** Assertion Box *************************************************************/
	/*  for assertions in algorithms */

	.assertion {
		border-color: #AAA;
		border-color: var(--assertion-border);
		background: #EEE;
		background: var(--assertion-bg);
		color: black;
		color: var(--assertion-text);
	}

/** Advisement Box ************************************************************/
	/*  for attention-grabbing normative statements */

	.advisement {
		border-color: orange;
		border-color: var(--advisement-border);
		border-style: none solid;
		background: #fec;
		background: var(--advisement-bg);
		color: black;
		color: var(--advisement-text);
	}
	strong.advisement {
		display: block;
		text-align: center;
	}
	.advisement::before, .advisement > .marker {
		color: #b35f00;
		color: var(--advisementheading-text);
	}

/** Amendment Box *************************************************************/

	.amendment, .correction, .addition {
		border-color: #330099;
		border-color: var(--amendment-border);
		background: #F5F0FF;
		background: var(--amendment-bg);
		color: black;
		color: var(--amendment-text);
	}
	.amendment.proposed, .correction.proposed, .addition.proposed {
		border-style: solid;
		border-block-width: 0.25em;
	}
	.amendment::before, .amendment > .marker,
	details.amendment > summary::before, details.amendment > summary > .marker,
	.correction::before, .correction > .marker,
	details.correction > summary::before, details.correction > summary > .marker,
	.addition::before, .addition > .marker,
	details.addition > summary::before, details.addition > summary > .marker {
		color: #220066;
		color: var(--amendmentheading-text);
	}
	.amendment.proposed::before, .amendment.proposed > .marker,
	details.amendment.proposed > summary::before, details.amendment.proposed > summary > .marker,
	.correction.proposed::before, .correction.proposed > .marker,
	details.correction.proposed > summary::before, details.correction.proposed > summary > .marker,
	.addition.proposed::before, .addition.proposed > .marker,
	details.addition.proposed > summary::before, details.addition.proposed > summary > .marker {
		font-weight: bold;
	}

/** Spec Obsoletion Notice ****************************************************/
	/* obnoxious obsoletion notice for older/abandoned specs. */

	details {
		display: block;
	}
	summary {
		font-weight: bolder;
	}

	.annoying-warning:not(details),
	details.annoying-warning:not([open]) > summary,
	details.annoying-warning[open] {
		background: hsla(40,100%,50%,0.95);
		background: var(--warning-bg);
		color: black;
		color: var(--warning-text);
		padding: .75em 1em;
		border: red;
		border: var(--warning-border);
		border-style: solid none;
		box-shadow: 0 2px 8px black;
		text-align: center;
	}
	.annoying-warning :last-child {
		margin-bottom: 0;
	}

@media not print {
	details.annoying-warning[open] {
		position: fixed;
		left: 0;
		right: 0;
		bottom: 2em;
		z-index: 1000;
	}
}

	details.annoying-warning:not([open]) > summary {
		text-align: center;
	}

/** Entity Definition Boxes ***************************************************/

	.def {
		padding: .5em 1em;
		background: #def;
		background: var(--def-bg);
		margin: 1.2em 0;
		border-left: 0.5em solid #8ccbf2;
		border-left: 0.5em solid var(--def-border);
		color: black;
		color: var(--def-text);
	}

/******************************************************************************/
/*                                    Tables                                  */
/******************************************************************************/

	th, td {
		text-align: left;
		text-align: start;
	}

/** Property/Descriptor Definition Tables *************************************/

	table.def {
		/* inherits .def box styling, see above */
		width: 100%;
		border-spacing: 0;
	}

	table.def td,
	table.def th {
		padding: 0.5em;
		vertical-align: baseline;
		border-bottom: 1px solid #bbd7e9;
		border-bottom: 1px solid var(--defrow-border);
	}

	table.def > tbody > tr:last-child th,
	table.def > tbody > tr:last-child td {
		border-bottom: 0;
	}

	table.def th {
		font-style: italic;
		font-weight: normal;
		padding-left: 1em;
		width: 3em;
	}

	/* For when values are extra-complex and need formatting for readability */
	table td.pre {
		white-space: pre-wrap;
	}

	/* A footnote at the bottom of a def table */
	table.def td.footnote {
		padding-top: 0.6em;
	}
	table.def td.footnote::before {
		content: " ";
		display: block;
		height: 0.6em;
		width: 4em;
		border-top: thin solid;
	}

/** Data tables (and properly marked-up index tables) *************************/
	/*
		<table class="data"> highlights structural relationships in a table
		when correct markup is used (e.g. thead/tbody, th vs. td, scope attribute)

		Use class="complex data" for particularly complicated tables --
		(This will draw more lines: busier, but clearer.)

		Use class="long" on table cells with paragraph-like contents
		(This will adjust text alignment accordingly.)
		Alternately use class="longlastcol" on tables, to have the last column assume "long".
	*/

	table {
		word-wrap: normal;
		overflow-wrap: normal;
		hyphens: manual;
	}

	table.data,
	table.index {
		margin: 1em auto;
		border-collapse: collapse;
		border: hidden;
		width: 100%;
	}
	table.data caption,
	table.index caption {
		max-width: 50em;
		margin: 0 auto 1em;
	}

	table.data td,  table.data th,
	table.index td, table.index th {
		padding: 0.5em 1em;
		border-width: 1px;
		border-color: silver;
		border-color: var(--datacell-border);
		border-top-style: solid;
	}

	table.data thead td:empty {
		padding: 0;
		border: 0;
	}

	table.data  thead,
	table.index thead,
	table.data  tbody,
	table.index tbody {
		border-bottom: 2px solid;
	}

	table.data colgroup,
	table.index colgroup {
		border-left: 2px solid;
	}

	table.data  tbody th:first-child,
	table.index tbody th:first-child  {
		border-right: 2px solid;
		border-top: 1px solid silver;
		border-top: 1px solid var(--datacell-border);
		padding-right: 1em;
	}

	table.data th[colspan],
	table.data td[colspan] {
		text-align: center;
	}

	table.complex.data th,
	table.complex.data td {
		border: 1px solid silver;
		border: 1px solid var(--datacell-border);
		text-align: center;
	}

	table.data.longlastcol td:last-child,
	table.data td.long {
		vertical-align: baseline;
		text-align: left;
	}

	table.data img {
		vertical-align: middle;
	}


/*
Alternate table alignment rules

	table.data,
	table.index {
		text-align: center;
	}

	table.data  thead th[scope="row"],
	table.index thead th[scope="row"] {
		text-align: right;
	}

	table.data  tbody th:first-child,
	table.index tbody th:first-child  {
		text-align: right;
	}

Possible extra rowspan handling

	table.data  tbody th[rowspan]:not([rowspan='1']),
	table.index tbody th[rowspan]:not([rowspan='1']),
	table.data  tbody td[rowspan]:not([rowspan='1']),
	table.index tbody td[rowspan]:not([rowspan='1']) {
		border-left: 1px solid silver;
	}

	table.data  tbody th[rowspan]:first-child,
	table.index tbody th[rowspan]:first-child,
	table.data  tbody td[rowspan]:first-child,
	table.index tbody td[rowspan]:first-child{
		border-left: 0;
		border-right: 1px solid silver;
	}
*/

/******************************************************************************/
/*                                  Indices                                   */
/******************************************************************************/


/** Table of Contents *********************************************************/

	.toc a {
		/* More spacing; use padding to make it part of the click target. */
		padding: 0.1rem 1px 0;
		/* Larger, more consistently-sized click target */
		display: block;
		/* Switch to using border-bottom for underlines */
		text-decoration: none;
		border-bottom: 1px solid;
		/* Reverse color scheme */
		color: black;
		color: var(--toclink-text);
		border-color: #3980b5;
		border-color: var(--toclink-underline);
	}
	.toc a:visited {
		color: black;
		color: var(--toclink-visited-text);
		border-color: #054572;
		border-color: var(--toclink-visited-underline);
	}
	.toc a:focus,
	.toc a:hover {
		background: rgba(75%, 75%, 75%, .25);
		background: var(--a-hover-bg);
		border-bottom-width: 3px;
		margin-bottom: -2px;
	}
	.toc a:not(:focus):not(:hover) {
		/* Allow colors to cascade through from link styling */
		border-bottom-color: transparent;
	}

	.toc, .toc ol, .toc ul, .toc li {
		list-style: none; /* Numbers must be inlined into source */
		/* because generated content isn't search/selectable and markers can't do multilevel yet */
		margin:  0;
		padding: 0;
	}
	.toc {
		line-height: 1.1em;
	}

	/* ToC not indented until third level, but font style & margins show hierarchy */
	.toc > li			{ font-weight: bold;   }
	.toc > li li		 { font-weight: normal; }
	.toc > li li li	  { font-size:   95%;	}
	.toc > li li li li	{ font-size:   90%;	}
	.toc > li li li li li { font-size:   85%;	}

	/* @supports not (display:grid) { */
		.toc > li			{ margin: 1.5rem 0;	}
		.toc > li li		 { margin: 0.3rem 0;	}
		.toc > li li li	  { margin-left: 2rem;   }

		/* Section numbers in a column of their own */
		.toc .secno {
			float: left;
			width: 4rem;
			white-space: nowrap;
		}
		.toc > li li li li .secno { font-size: 85%; }
		.toc > li li li li li .secno { font-size: 100%; }

		.toc li {
			clear: both;
		}

		:not(li) > .toc			 { margin-left:  5rem; }
		.toc .secno				 { margin-left: -5rem; }
		.toc > li li li .secno	  { margin-left: -7rem; }
		.toc > li li li li .secno	{ margin-left: -9rem; }
		.toc > li li li li li .secno { margin-left: -11rem; }

		/* Tighten up indentation in narrow ToCs */
		@media (max-width: 30em) {
			:not(li) > .toc			 { margin-left:  4rem; }
			.toc .secno				 { margin-left: -4rem; }
			.toc > li li li			 { margin-left:  1rem; }
			.toc > li li li .secno	  { margin-left: -5rem; }
			.toc > li li li li .secno	{ margin-left: -6rem; }
			.toc > li li li li li .secno { margin-left: -7rem; }
		}
		/* Loosen it on wide screens */
		@media screen and (min-width: 78em) {
			body:not(.toc-inline) :not(li) > .toc			 { margin-left:  4rem; }
			body:not(.toc-inline) .toc .secno				 { margin-left: -4rem; }
			body:not(.toc-inline) .toc > li li li			 { margin-left:  1rem; }
			body:not(.toc-inline) .toc > li li li .secno	  { margin-left: -5rem; }
			body:not(.toc-inline) .toc > li li li li .secno	{ margin-left: -6rem; }
			body:not(.toc-inline) .toc > li li li li li .secno { margin-left: -7rem; }
	}
	/* } */

	@supports (display:grid) and (display:contents) {
		/* Use #toc over .toc to override non-@supports rules. */
		#toc {
			display: grid;
			align-content: start;
			grid-template-columns: auto 1fr;
			grid-column-gap: 1rem;
			column-gap: 1rem;
			grid-row-gap: .6rem;
			row-gap: .6rem;
		}
		#toc h2 {
			grid-column: 1 / -1;
			margin-bottom: 0;
		}
		#toc ol,
		#toc li,
		#toc a {
			display: contents;
			/* Switch <a> to subgrid when supported */
		}
		#toc span {
			margin: 0;
		}
		#toc > .toc > li > a > span {
			/* The spans of the top-level list,
			  comprising the first items of each top-level section. */
			margin-top: 1.1rem;
		}
		#toc#toc .secno { /* Ugh, need more specificity to override base.css */
			grid-column: 1;
			width: auto;
			margin-left: 0;
		}
		#toc .content {
			grid-column: 2;
			width: auto;
			margin-right: 1rem;
			border-bottom: 3px solid transparent;
			margin-bottom: -3px;
		}
		#toc .content:hover,
		#toc .content:focus {
			background: rgba(75%, 75%, 75%, .25);
			background: var(--a-hover-bg);
			border-bottom-color: #054572;
			border-bottom-color: var(--toclink-underline);
		}
		#toc li li li .content {
			margin-left: 1rem;
		}
		#toc li li li li .content {
			margin-left: 2rem;
		}
	}


/** Index *********************************************************************/

	/* Index Lists: Layout */
	ul.index	  { margin-left: 0; columns: 15em; text-indent: 1em hanging; }
	ul.index li	{ margin-left: 0; list-style: none; break-inside: avoid; }
	ul.index li li { margin-left: 1em; }
	ul.index dl	{ margin-top: 0; }
	ul.index dt	{ margin: .2em 0 .2em 20px;}
	ul.index dd	{ margin: .2em 0 .2em 40px;}
	/* Index Lists: Typography */
	ul.index ul,
	ul.index dl { font-size: smaller; }
	@media not print {
		ul.index li a + span {
			white-space: nowrap;
			color: transparent; }
		ul.index li a:hover + span,
		ul.index li a:focus + span {
			color: #707070;
			color: var(--indexinfo-text);
		}
	}

/** Index Tables *****************************************************/
	/* See also the data table styling section, which this effectively subclasses */

	table.index {
		font-size: small;
		border-collapse: collapse;
		border-spacing: 0;
		text-align: left;
		margin: 1em 0;
	}

	table.index td,
	table.index th {
		padding: 0.4em;
	}

	table.index tr:hover td:not([rowspan]),
	table.index tr:hover th:not([rowspan]) {
		color: black;
		color: var(--indextable-hover-text);
		background: #f7f8f9;
		background: var(--indextable-hover-bg);
	}

	/* The link in the first column in the property table (formerly a TD) */
	table.index th:first-child a {
		font-weight: bold;
	}

/** Outdated warning **********************************************************/

.outdated-spec {
	color: black;
	color: var(--outdatedspec-text);
	background-color: rgba(0,0,0,0.5);
	background-color: var(--outdatedspec-bg);
}

.outdated-warning {
	position: fixed;
	bottom: 50%;
	left: 0;
	right: 0;
	margin: 0 auto;
	width: 50%;
	background: maroon;
	background: var(--outdated-bg);
	color: white;
	color: var(--outdated-text);
	border-radius: 1em;
	box-shadow: 0 0 1em red;
	box-shadow: 0 0 1em var(--outdated-shadow);
	padding: 2em;
	text-align: center;
	z-index: 2;
}

.outdated-warning a {
	color: currentcolor;
	background: transparent;
}

.edited-rec-warning {
	background: darkorange;
	background: var(--editedrec-bg);
	box-shadow: 0 0 1em;
}

.outdated-warning button {
	color: var(--outdated-text);
	border-radius: 1em;
	box-shadow: 0 0 1em red;
	box-shadow: 0 0 1em var(--outdated-shadow);
	padding: 2em;
	text-align: center;
	z-index: 2;
}

.outdated-warning a {
	color: currentcolor;
	background: transparent;
}

.edited-rec-warning {
	background: darkorange;
	background: var(--editedrec-bg);
	box-shadow: 0 0 1em;
}

.outdated-warning button {
	position: absolute;
	top: 0;
	right:0;
	margin: 0;
	border: 0;
	padding: 0.25em 0.5em;
	background: transparent;
	color: white;
	color: var(--outdated-text);
	font:1em sans-serif;
	text-align:center;
}

.outdated-warning span {
	display: block;
}

.outdated-collapsed {
	bottom: 0;
	border-radius: 0;
	width: 100%;
	padding: 0;
}

/******************************************************************************/
/*                                    Print                                   */
/******************************************************************************/

	@media print {
		/* Pages have their own margins. */
		html {
			margin: 0;
		}
		/* Serif for print. */
		body {
			font-family: serif;
		}

		.outdated-warning {
			position: absolute;
			border-style: solid;
			border-color: red;
		}

		.outdated-warning input {
			display: none;
		}
	}
	@page {
		margin: 1.5cm 1.1cm;
	}



/******************************************************************************/
/*                             Overflow Control                               */
/******************************************************************************/

	.figure .caption, .sidefigure .caption, figcaption {
		/* in case figure is overlarge, limit caption to 50em */
		max-width: 50rem;
		margin-left: auto;
		margin-right: auto;
	}
	.overlarge {
		/* Magic to create good item positioning:
		  "content column" is 50ems wide at max; less on smaller screens.
		  Extra space (after ToC + content) is empty on the right.

		  1. When item < content column, centers item in column.
		  2. When content < item < available, left-aligns.
		  3. When item > available, fills available + scroll bar.
		*/
		display: grid;
		grid-template-columns: minmax(0, 50em);
	}
	.overlarge > table {
		/* limit preferred width of table */
		max-width: 50em;
		margin-left: auto;
		margin-right: auto;
	}

	@media (min-width: 55em) {
		.overlarge {
			margin-right: calc(13px + 26.5rem - 50vw);
			max-width: none;
		}
	}
	@media screen and (min-width: 78em) {
		body:not(.toc-inline) .overlarge {
			/* 30.5em body padding 50em content area */
			margin-right: calc(40em - 50vw) !important;
		}
	}
	@media screen and (min-width: 90em) {
		body:not(.toc-inline) .overlarge {
			/* 4em html margin 30.5em body padding 50em content area */
			margin-right: calc(84.5em - 100vw) !important;
		}
	}

	@media not print {
		.overlarge {
			overflow-x: auto;
			/* See Lea Verou's explanation background-attachment:
			* http://lea.verou.me/2012/04/background-attachment-local/
			*
			background: top left  / 4em 100% linear-gradient(to right,  #ffffff, rgba(255, 255, 255, 0)) local,
						top right / 4em 100% linear-gradient(to left, #ffffff, rgba(255, 255, 255, 0)) local,
						top left  / 1em 100% linear-gradient(to right,  #c3c3c5, rgba(195, 195, 197, 0)) scroll,
						top right / 1em 100% linear-gradient(to left, #c3c3c5, rgba(195, 195, 197, 0)) scroll,
						white;
			background-repeat: no-repeat;
			*/
		}
	}
</style>
<style>
    table, th, td {
      border: 1px solid black;
      border-collapse: collapse;
      vertical-align: top;
    }
    th, td {
      border-left: none;
      border-right: none;
      padding: 0px 10px;
    }
    th {
      text-align: center;
    }

    del { background: #fcc; color: #000; text-decoration: line-through; }
    ins { background: #cfc; color: #000; }
    blockquote .highlight:not(.idl) { background: initial; margin: initial; padding: 0.5em }
    blockquote ul { background: inherit; }
    blockquote code.highlight:not(.idl) { padding: initial; }
    blockquote c-[a] { color: inherit; } /* Keyword.Declaration */
    blockquote c-[b] { color: inherit; } /* Keyword.Type */
    blockquote c-[c] { color: inherit; } /* Comment */
    blockquote c-[d] { color: inherit; } /* Comment.Multiline */
    blockquote c-[e] { color: inherit; } /* Name.Attribute */
    blockquote c-[f] { color: inherit; } /* Name.Tag */
    blockquote c-[g] { color: inherit; } /* Name.Variable */
    blockquote c-[k] { color: inherit; } /* Keyword */
    blockquote c-[l] { color: inherit; } /* Literal */
    blockquote c-[m] { color: inherit; } /* Literal.Number */
    blockquote c-[n] { color: inherit; } /* Name */
    blockquote c-[o] { color: inherit; } /* Operator */
    blockquote c-[p] { color: inherit; } /* Punctuation */
    blockquote c-[s] { color: inherit; } /* Literal.String */
    blockquote c-[t] { color: inherit; } /* Literal.String.Single */
    blockquote c-[u] { color: inherit; } /* Literal.String.Double */
    blockquote c-[cp] { color: inherit; } /* Comment.Preproc */
    blockquote c-[c1] { color: inherit; } /* Comment.Single */
    blockquote c-[cs] { color: inherit; } /* Comment.Special */
    blockquote c-[kc] { color: inherit; } /* Keyword.Constant */
    blockquote c-[kn] { color: inherit; } /* Keyword.Namespace */
    blockquote c-[kp] { color: inherit; } /* Keyword.Pseudo */
    blockquote c-[kr] { color: inherit; } /* Keyword.Reserved */
    blockquote c-[ld] { color: inherit; } /* Literal.Date */
    blockquote c-[nc] { color: inherit; } /* Name.Class */
    blockquote c-[no] { color: inherit; } /* Name.Constant */
    blockquote c-[nd] { color: inherit; } /* Name.Decorator */
    blockquote c-[ni] { color: inherit; } /* Name.Entity */
    blockquote c-[ne] { color: inherit; } /* Name.Exception */
    blockquote c-[nf] { color: inherit; } /* Name.Function */
    blockquote c-[nl] { color: inherit; } /* Name.Label */
    blockquote c-[nn] { color: inherit; } /* Name.Namespace */
    blockquote c-[py] { color: inherit; } /* Name.Property */
    blockquote c-[ow] { color: inherit; } /* Operator.Word */
    blockquote c-[mb] { color: inherit; } /* Literal.Number.Bin */
    blockquote c-[mf] { color: inherit; } /* Literal.Number.Float */
    blockquote c-[mh] { color: inherit; } /* Literal.Number.Hex */
    blockquote c-[mi] { color: inherit; } /* Literal.Number.Integer */
    blockquote c-[mo] { color: inherit; } /* Literal.Number.Oct */
    blockquote c-[sb] { color: inherit; } /* Literal.String.Backtick */
    blockquote c-[sc] { color: inherit; } /* Literal.String.Char */
    blockquote c-[sd] { color: inherit; } /* Literal.String.Doc */
    blockquote c-[se] { color: inherit; } /* Literal.String.Escape */
    blockquote c-[sh] { color: inherit; } /* Literal.String.Heredoc */
    blockquote c-[si] { color: inherit; } /* Literal.String.Interpol */
    blockquote c-[sx] { color: inherit; } /* Literal.String.Other */
    blockquote c-[sr] { color: inherit; } /* Literal.String.Regex */
    blockquote c-[ss] { color: inherit; } /* Literal.String.Symbol */
    blockquote c-[vc] { color: inherit; } /* Name.Variable.Class */
    blockquote c-[vg] { color: inherit; } /* Name.Variable.Global */
    blockquote c-[vi] { color: inherit; } /* Name.Variable.Instance */
    blockquote c-[il] { color: inherit; } /* Literal.Number.Integer.Long */
  </style>
  <meta content="Bikeshed version d765c696b, updated Fri Mar 8 15:58:52 2024 -0800" name="generator">
  <link href="https://wg21.link/P3423R0" rel="canonical">
  <link href="https://isocpp.org/favicon.ico" rel="icon">
  <meta content="12020f3427e32cd3ad7c447ff1caf53057b38a92" name="revision">
  <meta content="dark light" name="color-scheme">
<style>
table, th, td { border:1px solid grey; }
</style>
<style>/* Boilerplate: style-autolinks */
.css.css, .property.property, .descriptor.descriptor {
    color: var(--a-normal-text);
    font-size: inherit;
    font-family: inherit;
}
.css::before, .property::before, .descriptor::before {
    content: "‘";
}
.css::after, .property::after, .descriptor::after {
    content: "’";
}
.property, .descriptor {
    /* Don't wrap property and descriptor names */
    white-space: nowrap;
}
.type { /* CSS value <type> */
    font-style: italic;
}
pre .property::before, pre .property::after {
    content: "";
}
[data-link-type="property"]::before,
[data-link-type="propdesc"]::before,
[data-link-type="descriptor"]::before,
[data-link-type="value"]::before,
[data-link-type="function"]::before,
[data-link-type="at-rule"]::before,
[data-link-type="selector"]::before,
[data-link-type="maybe"]::before {
    content: "‘";
}
[data-link-type="property"]::after,
[data-link-type="propdesc"]::after,
[data-link-type="descriptor"]::after,
[data-link-type="value"]::after,
[data-link-type="function"]::after,
[data-link-type="at-rule"]::after,
[data-link-type="selector"]::after,
[data-link-type="maybe"]::after {
    content: "’";
}

[data-link-type].production::before,
[data-link-type].production::after,
.prod [data-link-type]::before,
.prod [data-link-type]::after {
    content: "";
}

[data-link-type=element],
[data-link-type=element-attr] {
    font-family: Menlo, Consolas, "DejaVu Sans Mono", monospace;
    font-size: .9em;
}
[data-link-type=element]::before { content: "<" }
[data-link-type=element]::after  { content: ">" }

[data-link-type=biblio] {
    white-space: pre;
}

@media (prefers-color-scheme: dark) {
    :root {
        --selflink-text: black;
        --selflink-bg: silver;
        --selflink-hover-text: white;
    }
}
</style>
<style>/* Boilerplate: style-colors */
/* Any --*-text not paired with a --*-bg is assumed to have a transparent bg */
:root {
    color-scheme: light dark;

    --text: black;
    --bg: white;

    --unofficial-watermark: url(https://www.w3.org/StyleSheets/TR/2016/logos/UD-watermark);

    --logo-bg: #1a5e9a;
    --logo-active-bg: #c00;
    --logo-text: white;

    --tocnav-normal-text: #707070;
    --tocnav-normal-bg: var(--bg);
    --tocnav-hover-text: var(--tocnav-normal-text);
    --tocnav-hover-bg: #f8f8f8;
    --tocnav-active-text: #c00;
    --tocnav-active-bg: var(--tocnav-normal-bg);

    --tocsidebar-text: var(--text);
    --tocsidebar-bg: #f7f8f9;
    --tocsidebar-shadow: rgba(0,0,0,.1);
    --tocsidebar-heading-text: hsla(203,20%,40%,.7);

    --toclink-text: var(--text);
    --toclink-underline: #3980b5;
    --toclink-visited-text: var(--toclink-text);
    --toclink-visited-underline: #054572;

    --heading-text: #005a9c;

    --hr-text: var(--text);

    --algo-border: #def;

    --del-text: red;
    --del-bg: transparent;
    --ins-text: #080;
    --ins-bg: transparent;

    --a-normal-text: #034575;
    --a-normal-underline: #bbb;
    --a-visited-text: var(--a-normal-text);
    --a-visited-underline: #707070;
    --a-hover-bg: rgba(75%, 75%, 75%, .25);
    --a-active-text: #c00;
    --a-active-underline: #c00;

    --blockquote-border: silver;
    --blockquote-bg: transparent;
    --blockquote-text: currentcolor;

    --issue-border: #e05252;
    --issue-bg: #fbe9e9;
    --issue-text: var(--text);
    --issueheading-text: #831616;

    --example-border: #e0cb52;
    --example-bg: #fcfaee;
    --example-text: var(--text);
    --exampleheading-text: #574b0f;

    --note-border: #52e052;
    --note-bg: #e9fbe9;
    --note-text: var(--text);
    --noteheading-text: hsl(120, 70%, 30%);
    --notesummary-underline: silver;

    --assertion-border: #aaa;
    --assertion-bg: #eee;
    --assertion-text: black;

    --advisement-border: orange;
    --advisement-bg: #fec;
    --advisement-text: var(--text);
    --advisementheading-text: #b35f00;

    --warning-border: red;
    --warning-bg: hsla(40,100%,50%,0.95);
    --warning-text: var(--text);

    --amendment-border: #330099;
    --amendment-bg: #F5F0FF;
    --amendment-text: var(--text);
    --amendmentheading-text: #220066;

    --def-border: #8ccbf2;
    --def-bg: #def;
    --def-text: var(--text);
    --defrow-border: #bbd7e9;

    --datacell-border: silver;

    --indexinfo-text: #707070;

    --indextable-hover-text: black;
    --indextable-hover-bg: #f7f8f9;

    --outdatedspec-bg: rgba(0, 0, 0, .5);
    --outdatedspec-text: black;
    --outdated-bg: maroon;
    --outdated-text: white;
    --outdated-shadow: red;

    --editedrec-bg: darkorange;
}

@media (prefers-color-scheme: dark) {
    :root {
        --text: #ddd;
        --bg: black;

        --unofficial-watermark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='400'%3E%3Cg fill='%23100808' transform='translate(200 200) rotate(-45) translate(-200 -200)' stroke='%23100808' stroke-width='3'%3E%3Ctext x='50%25' y='220' style='font: bold 70px sans-serif; text-anchor: middle; letter-spacing: 6px;'%3EUNOFFICIAL%3C/text%3E%3Ctext x='50%25' y='305' style='font: bold 70px sans-serif; text-anchor: middle; letter-spacing: 6px;'%3EDRAFT%3C/text%3E%3C/g%3E%3C/svg%3E");

        --logo-bg: #1a5e9a;
        --logo-active-bg: #c00;
        --logo-text: white;

        --tocnav-normal-text: #999;
        --tocnav-normal-bg: var(--bg);
        --tocnav-hover-text: var(--tocnav-normal-text);
        --tocnav-hover-bg: #080808;
        --tocnav-active-text: #f44;
        --tocnav-active-bg: var(--tocnav-normal-bg);

        --tocsidebar-text: var(--text);
        --tocsidebar-bg: #080808;
        --tocsidebar-shadow: rgba(255,255,255,.1);
        --tocsidebar-heading-text: hsla(203,20%,40%,.7);

        --toclink-text: var(--text);
        --toclink-underline: #6af;
        --toclink-visited-text: var(--toclink-text);
        --toclink-visited-underline: #054572;

        --heading-text: #8af;

        --hr-text: var(--text);

        --algo-border: #456;

        --del-text: #f44;
        --del-bg: transparent;
        --ins-text: #4a4;
        --ins-bg: transparent;

        --a-normal-text: #6af;
        --a-normal-underline: #555;
        --a-visited-text: var(--a-normal-text);
        --a-visited-underline: var(--a-normal-underline);
        --a-hover-bg: rgba(25%, 25%, 25%, .2);
        --a-active-text: #f44;
        --a-active-underline: var(--a-active-text);

        --borderedblock-bg: rgba(255, 255, 255, .05);

        --blockquote-border: silver;
        --blockquote-bg: var(--borderedblock-bg);
        --blockquote-text: currentcolor;

        --issue-border: #e05252;
        --issue-bg: var(--borderedblock-bg);
        --issue-text: var(--text);
        --issueheading-text: hsl(0deg, 70%, 70%);

        --example-border: hsl(50deg, 90%, 60%);
        --example-bg: var(--borderedblock-bg);
        --example-text: var(--text);
        --exampleheading-text: hsl(50deg, 70%, 70%);

        --note-border: hsl(120deg, 100%, 35%);
        --note-bg: var(--borderedblock-bg);
        --note-text: var(--text);
        --noteheading-text: hsl(120, 70%, 70%);
        --notesummary-underline: silver;

        --assertion-border: #444;
        --assertion-bg: var(--borderedblock-bg);
        --assertion-text: var(--text);

        --advisement-border: orange;
        --advisement-bg: #222218;
        --advisement-text: var(--text);
        --advisementheading-text: #f84;

        --warning-border: red;
        --warning-bg: hsla(40,100%,20%,0.95);
        --warning-text: var(--text);

        --amendment-border: #330099;
        --amendment-bg: #080010;
        --amendment-text: var(--text);
        --amendmentheading-text: #cc00ff;

        --def-border: #8ccbf2;
        --def-bg: #080818;
        --def-text: var(--text);
        --defrow-border: #136;

        --datacell-border: silver;

        --indexinfo-text: #aaa;

        --indextable-hover-text: var(--text);
        --indextable-hover-bg: #181818;

        --outdatedspec-bg: rgba(255, 255, 255, .5);
        --outdatedspec-text: black;
        --outdated-bg: maroon;
        --outdated-text: white;
        --outdated-shadow: red;

        --editedrec-bg: darkorange;
    }
    /* In case a transparent-bg image doesn't expect to be on a dark bg,
       which is quite common in practice... */
    img { background: white; }
}
</style>
<style>/* Boilerplate: style-counters */
body {
    counter-reset: example figure issue;
}
.issue {
    counter-increment: issue;
}
.issue:not(.no-marker)::before {
    content: "Issue " counter(issue);
}

.example {
    counter-increment: example;
}
.example:not(.no-marker)::before {
    content: "Example " counter(example);
}
.invalid.example:not(.no-marker)::before,
.illegal.example:not(.no-marker)::before {
    content: "Invalid Example" counter(example);
}

figcaption {
    counter-increment: figure;
}
figcaption:not(.no-marker)::before {
    content: "Figure " counter(figure) " ";
}
</style>
<style>/* Boilerplate: style-issues */
a[href].issue-return {
    float: right;
    float: inline-end;
    color: var(--issueheading-text);
    font-weight: bold;
    text-decoration: none;
}
</style>
<style>/* Boilerplate: style-md-lists */
/* This is a weird hack for me not yet following the commonmark spec
   regarding paragraph and lists. */
[data-md] > :first-child {
    margin-top: 0;
}
[data-md] > :last-child {
    margin-bottom: 0;
}
</style>
<style>/* Boilerplate: style-selflinks */
:root {
    --selflink-text: white;
    --selflink-bg: gray;
    --selflink-hover-text: black;
}
.heading, .issue, .note, .example, li, dt {
    position: relative;
}
a.self-link {
    position: absolute;
    top: 0;
    left: calc(-1 * (3.5rem - 26px));
    width: calc(3.5rem - 26px);
    height: 2em;
    text-align: center;
    border: none;
    transition: opacity .2s;
    opacity: .5;
}
a.self-link:hover {
    opacity: 1;
}
.heading > a.self-link {
    font-size: 83%;
}
.example > a.self-link,
.note > a.self-link,
.issue > a.self-link {
    /* These blocks are overflow:auto, so positioning outside
       doesn't work. */
    left: auto;
    right: 0;
}
li > a.self-link {
    left: calc(-1 * (3.5rem - 26px) - 2em);
}
dfn > a.self-link {
    top: auto;
    left: auto;
    opacity: 0;
    width: 1.5em;
    height: 1.5em;
    background: var(--selflink-bg);
    color: var(--selflink-text);
    font-style: normal;
    transition: opacity .2s, background-color .2s, color .2s;
}
dfn:hover > a.self-link {
    opacity: 1;
}
dfn > a.self-link:hover {
    color: var(--selflink-hover-text);
}

a.self-link::before            { content: "¶"; }
.heading > a.self-link::before { content: "§"; }
dfn > a.self-link::before      { content: "#"; }
</style>
<style>/* Boilerplate: style-syntax-highlighting */
code.highlight { padding: .1em; border-radius: .3em; }
pre.highlight, pre > code.highlight { display: block; padding: 1em; margin: .5em 0; overflow: auto; border-radius: 0; }

.highlight:not(.idl) { background: rgba(0, 0, 0, .03); }
c-[a] { color: #990055 } /* Keyword.Declaration */
c-[b] { color: #990055 } /* Keyword.Type */
c-[c] { color: #708090 } /* Comment */
c-[d] { color: #708090 } /* Comment.Multiline */
c-[e] { color: #0077aa } /* Name.Attribute */
c-[f] { color: #669900 } /* Name.Tag */
c-[g] { color: #222222 } /* Name.Variable */
c-[k] { color: #990055 } /* Keyword */
c-[l] { color: #000000 } /* Literal */
c-[m] { color: #000000 } /* Literal.Number */
c-[n] { color: #0077aa } /* Name */
c-[o] { color: #999999 } /* Operator */
c-[p] { color: #999999 } /* Punctuation */
c-[s] { color: #a67f59 } /* Literal.String */
c-[t] { color: #a67f59 } /* Literal.String.Single */
c-[u] { color: #a67f59 } /* Literal.String.Double */
c-[cp] { color: #708090 } /* Comment.Preproc */
c-[c1] { color: #708090 } /* Comment.Single */
c-[cs] { color: #708090 } /* Comment.Special */
c-[kc] { color: #990055 } /* Keyword.Constant */
c-[kn] { color: #990055 } /* Keyword.Namespace */
c-[kp] { color: #990055 } /* Keyword.Pseudo */
c-[kr] { color: #990055 } /* Keyword.Reserved */
c-[ld] { color: #000000 } /* Literal.Date */
c-[nc] { color: #0077aa } /* Name.Class */
c-[no] { color: #0077aa } /* Name.Constant */
c-[nd] { color: #0077aa } /* Name.Decorator */
c-[ni] { color: #0077aa } /* Name.Entity */
c-[ne] { color: #0077aa } /* Name.Exception */
c-[nf] { color: #0077aa } /* Name.Function */
c-[nl] { color: #0077aa } /* Name.Label */
c-[nn] { color: #0077aa } /* Name.Namespace */
c-[py] { color: #0077aa } /* Name.Property */
c-[ow] { color: #999999 } /* Operator.Word */
c-[mb] { color: #000000 } /* Literal.Number.Bin */
c-[mf] { color: #000000 } /* Literal.Number.Float */
c-[mh] { color: #000000 } /* Literal.Number.Hex */
c-[mi] { color: #000000 } /* Literal.Number.Integer */
c-[mo] { color: #000000 } /* Literal.Number.Oct */
c-[sb] { color: #a67f59 } /* Literal.String.Backtick */
c-[sc] { color: #a67f59 } /* Literal.String.Char */
c-[sd] { color: #a67f59 } /* Literal.String.Doc */
c-[se] { color: #a67f59 } /* Literal.String.Escape */
c-[sh] { color: #a67f59 } /* Literal.String.Heredoc */
c-[si] { color: #a67f59 } /* Literal.String.Interpol */
c-[sx] { color: #a67f59 } /* Literal.String.Other */
c-[sr] { color: #a67f59 } /* Literal.String.Regex */
c-[ss] { color: #a67f59 } /* Literal.String.Symbol */
c-[vc] { color: #0077aa } /* Name.Variable.Class */
c-[vg] { color: #0077aa } /* Name.Variable.Global */
c-[vi] { color: #0077aa } /* Name.Variable.Instance */
c-[il] { color: #000000 } /* Literal.Number.Integer.Long */

@media (prefers-color-scheme: dark) {
    .highlight:not(.idl) { background: rgba(255, 255, 255, .05); }

    c-[a] { color: #d33682 } /* Keyword.Declaration */
    c-[b] { color: #d33682 } /* Keyword.Type */
    c-[c] { color: #2aa198 } /* Comment */
    c-[d] { color: #2aa198 } /* Comment.Multiline */
    c-[e] { color: #268bd2 } /* Name.Attribute */
    c-[f] { color: #b58900 } /* Name.Tag */
    c-[g] { color: #cb4b16 } /* Name.Variable */
    c-[k] { color: #d33682 } /* Keyword */
    c-[l] { color: #657b83 } /* Literal */
    c-[m] { color: #657b83 } /* Literal.Number */
    c-[n] { color: #268bd2 } /* Name */
    c-[o] { color: #657b83 } /* Operator */
    c-[p] { color: #657b83 } /* Punctuation */
    c-[s] { color: #6c71c4 } /* Literal.String */
    c-[t] { color: #6c71c4 } /* Literal.String.Single */
    c-[u] { color: #6c71c4 } /* Literal.String.Double */
    c-[ch] { color: #2aa198 } /* Comment.Hashbang */
    c-[cp] { color: #2aa198 } /* Comment.Preproc */
    c-[cpf] { color: #2aa198 } /* Comment.PreprocFile */
    c-[c1] { color: #2aa198 } /* Comment.Single */
    c-[cs] { color: #2aa198 } /* Comment.Special */
    c-[kc] { color: #d33682 } /* Keyword.Constant */
    c-[kn] { color: #d33682 } /* Keyword.Namespace */
    c-[kp] { color: #d33682 } /* Keyword.Pseudo */
    c-[kr] { color: #d33682 } /* Keyword.Reserved */
    c-[ld] { color: #657b83 } /* Literal.Date */
    c-[nc] { color: #268bd2 } /* Name.Class */
    c-[no] { color: #268bd2 } /* Name.Constant */
    c-[nd] { color: #268bd2 } /* Name.Decorator */
    c-[ni] { color: #268bd2 } /* Name.Entity */
    c-[ne] { color: #268bd2 } /* Name.Exception */
    c-[nf] { color: #268bd2 } /* Name.Function */
    c-[nl] { color: #268bd2 } /* Name.Label */
    c-[nn] { color: #268bd2 } /* Name.Namespace */
    c-[py] { color: #268bd2 } /* Name.Property */
    c-[ow] { color: #657b83 } /* Operator.Word */
    c-[mb] { color: #657b83 } /* Literal.Number.Bin */
    c-[mf] { color: #657b83 } /* Literal.Number.Float */
    c-[mh] { color: #657b83 } /* Literal.Number.Hex */
    c-[mi] { color: #657b83 } /* Literal.Number.Integer */
    c-[mo] { color: #657b83 } /* Literal.Number.Oct */
    c-[sa] { color: #6c71c4 } /* Literal.String.Affix */
    c-[sb] { color: #6c71c4 } /* Literal.String.Backtick */
    c-[sc] { color: #6c71c4 } /* Literal.String.Char */
    c-[dl] { color: #6c71c4 } /* Literal.String.Delimiter */
    c-[sd] { color: #6c71c4 } /* Literal.String.Doc */
    c-[se] { color: #6c71c4 } /* Literal.String.Escape */
    c-[sh] { color: #6c71c4 } /* Literal.String.Heredoc */
    c-[si] { color: #6c71c4 } /* Literal.String.Interpol */
    c-[sx] { color: #6c71c4 } /* Literal.String.Other */
    c-[sr] { color: #6c71c4 } /* Literal.String.Regex */
    c-[ss] { color: #6c71c4 } /* Literal.String.Symbol */
    c-[fm] { color: #268bd2 } /* Name.Function.Magic */
    c-[vc] { color: #cb4b16 } /* Name.Variable.Class */
    c-[vg] { color: #cb4b16 } /* Name.Variable.Global */
    c-[vi] { color: #cb4b16 } /* Name.Variable.Instance */
    c-[vm] { color: #cb4b16 } /* Name.Variable.Magic */
    c-[il] { color: #657b83 } /* Literal.Number.Integer.Long */
}
</style>
 <body class="h-entry">
  <div class="head">
   <p data-fill-with="logo"></p>
   <h1 class="p-name no-ref" id="title">P3423R0<br>Extending User-Generated Diagnostic Messages</h1>
   <h2 class="no-num no-toc no-ref heading settled" id="profile-and-date"><span class="content">Published Proposal, <time class="dt-updated" datetime="2024-10-15">2024-10-15</time></span></h2>
   <div data-fill-with="spec-metadata">
    <dl>
     <dt>This version:
     <dd><a class="u-url" href="https://wg21.link/P3423R0">https://wg21.link/P3423R0</a>
     <dt class="editor">Author:
     <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:winmikedows@hotmail.com">Yihe Li</a>
     <dt>Audience:
     <dd>EWG
     <dt>Project:
     <dd>ISO/IEC 14882 Programming Languages — C++, ISO/IEC JTC1/SC22/WG21
     <dt>Target:
     <dd>C++26
     <dt>Source:
     <dd><a href="https://github.com/Mick235711/wg21-papers/blob/main/P3423/P3423R0.bs">github.com/Mick235711/wg21-papers/blob/main/P3423/P3423R0.bs</a>
     <dt>Issue Tracking:
     <dd><a href="https://github.com/Mick235711/wg21-papers/issues">GitHub Mick235711/wg21-papers</a>
    </dl>
   </div>
   <div data-fill-with="warning"></div>
   <hr title="Separator for header">
  </div>
  <nav data-fill-with="table-of-contents" id="toc">
   <h2 class="no-num no-toc no-ref" id="contents">Table of Contents</h2>
   <ol class="toc" role="directory">
    <li>
     <a href="#revisions"><span class="secno">1</span> <span class="content">Revision History</span></a>
     <ol class="toc">
      <li><a href="#r0"><span class="secno">1.1</span> <span class="content">R0 (2024-10 pre-Wrocław Mailing)</span></a>
     </ol>
    <li><a href="#motivation-and-history"><span class="secno">2</span> <span class="content">Motivation and History</span></a>
    <li>
     <a href="#usage-examples"><span class="secno">3</span> <span class="content">Usage Example</span></a>
     <ol class="toc">
      <li><a href="#stl-usage"><span class="secno">3.1</span> <span class="content">Standard Library</span></a>
      <li><a href="#third-party-libraries"><span class="secno">3.2</span> <span class="content">Third-Party Libraries</span></a>
     </ol>
    <li>
     <a href="#design"><span class="secno">4</span> <span class="content">Design</span></a>
     <ol class="toc">
      <li><a href="#what-is-a-string"><span class="secno">4.1</span> <span class="content">What Is A String?</span></a>
      <li><a href="#design-decisions"><span class="secno">4.2</span> <span class="content">Design Decisions</span></a>
      <li><a href="#attribute-expression-argument"><span class="secno">4.3</span> <span class="content">Attribute Expression Argument</span></a>
      <li><a href="#attribute-placement"><span class="secno">4.4</span> <span class="content">Attribute Placement and Name Visibility</span></a>
      <li><a href="#invalid-message"><span class="secno">4.5</span> <span class="content">What If The Message Parameter Is Invalid?</span></a>
      <li><a href="#alternative-syntax"><span class="secno">4.6</span> <span class="content">Alternative Syntax Considered</span></a>
      <li><a href="#claim-of-syntax-space"><span class="secno">4.7</span> <span class="content">Claim of Syntax Space</span></a>
      <li><a href="#interaction-with-reflection"><span class="secno">4.8</span> <span class="content">Interaction with Reflection</span></a>
      <li><a href="#proposal-scope"><span class="secno">4.9</span> <span class="content">Proposal Scope</span></a>
      <li><a href="#target-vehicle"><span class="secno">4.10</span> <span class="content">Target Vehicle</span></a>
      <li><a href="#feature-test-macro"><span class="secno">4.11</span> <span class="content">Feature Test Macro</span></a>
     </ol>
    <li><a href="#implementation"><span class="secno">5</span> <span class="content">Implementation Experience</span></a>
    <li>
     <a href="#wording"><span class="secno">6</span> <span class="content">Wording</span></a>
     <ol class="toc">
      <li><a href="#expr.const"><span class="secno">6.1</span> <span class="content">7.7 Constant expressions [expr.const]</span></a>
      <li><a href="#dcl.pre"><span class="secno">6.2</span> <span class="content">9.1 Preamble [dcl.pre]</span></a>
      <li>
       <a href="#dcl.fct.def"><span class="secno">6.3</span> <span class="content">9.5 Function definitions [dcl.fct.def]</span></a>
       <ol class="toc">
        <li><a href="#dcl.fct.def.general"><span class="secno">6.3.1</span> <span class="content">9.5.1 General [dcl.fct.def.general]</span></a>
        <li><a href="#dcl.fct.def.delete"><span class="secno">6.3.2</span> <span class="content">9.5.3 Deleted definitions [dcl.fct.def.delete]</span></a>
       </ol>
      <li>
       <a href="#dcl.attr"><span class="secno">6.4</span> <span class="content">9.12 Attributes [dcl.attr]</span></a>
       <ol class="toc">
        <li><a href="#dcl.attr.deprecated"><span class="secno">6.4.1</span> <span class="content">9.12.5 Deprecated attribute [dcl.attr.deprecated]</span></a>
        <li><a href="#dcl.attr.nodiscard"><span class="secno">6.4.2</span> <span class="content">9.12.10 Nodiscard attribute [dcl.attr.nodiscard]</span></a>
       </ol>
      <li><a href="#cpp.cond"><span class="secno">6.5</span> <span class="content">15.2 Conditional inclusion [cpp.cond]</span></a>
      <li><a href="#cpp.predefined"><span class="secno">6.6</span> <span class="content">15.11 Predefined macro names [cpp.predefined]</span></a>
     </ol>
    <li>
     <a href="#references"><span class="secno"></span> <span class="content">References</span></a>
     <ol class="toc">
      <li><a href="#normative"><span class="secno"></span> <span class="content">Normative References</span></a>
      <li><a href="#informative"><span class="secno"></span> <span class="content">Informative References</span></a>
     </ol>
   </ol>
  </nav>
  <main>
   <p>During Varna (2023-06), <a data-link-type="biblio" href="#biblio-p2741r3" title="user-generated static_assert messages">[P2741R3]</a> had been adopted into the C++26 working draft, which gave <code class="highlight"><c- k>static_assert</c-></code> the ability to accept a user-generated string-like object as the message parameter. This extension allowed the user of <code class="highlight"><c- k>static_assert</c-></code> to provide a more precise error message in compile time, thus significantly increasing the user-friendliness of libraries. This proposal, therefore, proposes to unify the language by allowing other constructs in the language that currently accept a message parameter, namely <code class="highlight"><c- p>[[</c-><c- n>nodiscard</c-><c- p>]]</c-></code>, <code class="highlight"><c- p>[[</c-><c- n>deprecated</c-><c- p>]]</c-></code>, and <code class="highlight"><c- o>=</c-> <c- k>delete</c-></code>, to also allow a user-generated string-like object as the provided message.</p>
   <h2 class="heading settled" data-level="1" id="revisions"><span class="secno">1. </span><span class="content">Revision History</span><a class="self-link" href="#revisions"></a></h2>
   <h3 class="heading settled" data-level="1.1" id="r0"><span class="secno">1.1. </span><span class="content">R0 (2024-10 pre-Wrocław Mailing)</span><a class="self-link" href="#r0"></a></h3>
   <ul>
    <li data-md>
     <p>Initial revision.</p>
   </ul>
   <h2 class="heading settled" data-level="2" id="motivation-and-history"><span class="secno">2. </span><span class="content">Motivation and History</span><a class="self-link" href="#motivation-and-history"></a></h2>
   <p>The first appearance of the compile-time message parameter in the C++ core language is in C++11, where <code class="highlight"><c- k>static_assert</c-></code> declaration was introduced into the language by <a data-link-type="biblio" href="#biblio-n1720" title="Proposal to Add Static Assertions to the Core Language (Revision 3)">[N1720]</a> with the syntax <code class="highlight"><c- k>static_assert</c-><c- p>(</c-><c- n>condition</c-><c- p>,</c-> <c- n>message</c-><c- p>)</c-></code>. At that time, the message parameter was the first time that users of the C++ language were able to control the generation of diagnostic messages in a dynamic way (excluding the preprocess macro <code class="highlight"><c- cp>#error</c-></code>, which is not controllable by the language itself, let alone dynamically in compile-time programming). Such flexibility has allowed the emergence of user-friendly compile-time libraries, where error messages can directly present to the user what they have done wrong. For instance, the following misuse of <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>print</c-></code>:</p>
<pre class="language-cpp highlight"><c- cp>#include</c-> &lt;print>

<c- k>struct</c-> <c- nc>A</c-> <c- p>{};</c->

<c- b>int</c-> <c- nf>main</c-><c- p>()</c->
<c- p>{</c->
    <c- n>A</c-> <c- n>a</c-><c- p>;</c->
    <c- n>std</c-><c- o>::</c-><c- n>println</c-><c- p>(</c-><c- s>"{}"</c-><c- p>,</c-> <c- n>a</c-><c- p>);</c->
<c- p>}</c->
</pre>
   <p><a href="https://godbolt.org/z/7jaTGxcKo">can directly generate</a> user-friendly diagnostics under clang 19.1.0 with libstdc++:</p>
<pre class="language-cpp highlight"><c- p>[...]</c->
<c- n>In</c-> <c- n>file</c-> <c- n>included</c-> <c- n>from</c-> <c- o>&lt;</c-><c- n>source</c-><c- o>>:</c-><c- mi>1</c-><c- o>:</c->
<c- n>In</c-> <c- n>file</c-> <c- n>included</c-> <c- n>from</c-> <c- o>/</c-><c- n>opt</c-><c- o>/</c-><c- n>compiler</c-><c- o>-</c-><c- n>explorer</c-><c- o>/</c-><c- n>gcc</c-><c- mf>-14.2.0</c-><c- o>/</c-><c- n>lib</c-><c- o>/</c-><c- n>gcc</c-><c- o>/</c-><c- n>x86_64</c-><c- o>-</c-><c- n>linux</c-><c- o>-</c-><c- n>gnu</c-><c- o>/</c-><c- mf>14.2.0</c-><c- o>/</c-><c- p>..</c-><c- o>/</c-><c- p>..</c-><c- o>/</c-><c- p>..</c-><c- o>/</c-><c- p>..</c-><c- o>/</c-><c- n>include</c-><c- o>/</c-><c- n>c</c-><c- o>++/</c-><c- mf>14.2.0</c-><c- o>/</c-><c- n>print</c-><c- o>:</c-><c- mi>41</c-><c- o>:</c->
<c- o>/</c-><c- n>opt</c-><c- o>/</c-><c- n>compiler</c-><c- o>-</c-><c- n>explorer</c-><c- o>/</c-><c- n>gcc</c-><c- mf>-14.2.0</c-><c- o>/</c-><c- n>lib</c-><c- o>/</c-><c- n>gcc</c-><c- o>/</c-><c- n>x86_64</c-><c- o>-</c-><c- n>linux</c-><c- o>-</c-><c- n>gnu</c-><c- o>/</c-><c- mf>14.2.0</c-><c- o>/</c-><c- p>..</c-><c- o>/</c-><c- p>..</c-><c- o>/</c-><c- p>..</c-><c- o>/</c-><c- p>..</c-><c- o>/</c-><c- n>include</c-><c- o>/</c-><c- n>c</c-><c- o>++/</c-><c- mf>14.2.0</c-><c- o>/</c-><c- n>format</c-><c- o>:</c-><c- mi>3732</c-><c- o>:</c-><c- mi>18</c-><c- o>:</c-> <c- n>error</c-><c- o>:</c-> <c- k>static</c-> <c- n>assertion</c-> <c- n>failed</c-> <c- n>due</c-> <c- n>to</c-> <c- n>requirement</c-> '<c- n>is_default_constructible_v</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>formatter</c-><c- o>&lt;</c-><c- n>A</c-><c- p>,</c-> <c- b>char</c-><c- o>>></c->'<c- o>:</c-> <c- n>std</c-><c- o>::</c-><c- n>formatter</c-> <c- n>must</c-> <c- n>be</c-> <c- n>specialized</c-> <c- k>for</c-> <c- n>the</c-> <c- n>type</c-> <c- n>of</c-> <c- n>each</c-> <c- n>format</c-> <c- n>arg</c->
 <c- mi>3732</c-> <c- o>|</c->           <c- k>static_assert</c-><c- p>(</c-><c- n>is_default_constructible_v</c-><c- o>&lt;</c-><c- n>formatter</c-><c- o>&lt;</c-><c- n>_Tq</c-><c- p>,</c-> <c- n>_CharT</c-><c- o>>></c-><c- p>,</c->
      <c- o>|</c->
<c- p>[...]</c->
</pre>
   <p>Although a bit cramped and hidden, the error message directly tells the user that <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>formatter</c-></code> must be specialized, thus informing them how to fix the problem. Without this feature, the user will only be faced with cryptic error messages such as "<code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>formatter</c-><c- o>&lt;</c-><c- n>A</c-><c- p>,</c-> <c- b>char</c-><c- o>></c-></code> is not default constructible", which requires an expert with a deep understanding of the specification of <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>formatter</c-></code> to uncover the actual cause of the error.</p>
   <p>Over the following years, more and more control over the generation and content of the diagnostic message of the compiler had been opened to the library writer:</p>
   <ul>
    <li data-md>
     <p>In C++14, <a data-link-type="biblio" href="#biblio-n3760" title="[[deprecated]] attribute">[N3760]</a> introduced the <code class="highlight"><c- p>[[</c-><c- n>deprecated</c-><c- p>]]</c-></code> attribute with an optional message parameter.</p>
    <li data-md>
     <p>In C++17, <a data-link-type="biblio" href="#biblio-n3928" title="Extending static_assert, v2">[N3928]</a> made <code class="highlight"><c- k>static_assert</c-></code>’s message parameter optional, making the condition expression automatically usable as an error message.</p>
    <li data-md>
     <p>In C++20, <a data-link-type="biblio" href="#biblio-p1301r4" title="[[nodiscard(&quot;should have a reason&quot;)]]">[P1301R4]</a> introduced an optional message parameter to the <code class="highlight"><c- p>[[</c-><c- n>nodiscard</c-><c- p>]]</c-></code> attribute.</p>
    <li data-md>
     <p>In C++23, <a data-link-type="biblio" href="#biblio-p2593r1" title="Allowing static_assert(false)">[P2593R1]</a> (adopted through <a data-link-type="biblio" href="#biblio-cwg2518" title="Conformance requirements and #error/#warning">[CWG2518]</a>) allowed <code class="highlight"><c- k>static_assert</c-><c- p>(</c->false<c- p>,</c-> <c- s>"message"</c-><c- p>)</c-></code> to appear in dependent contexts, which effectively turned <code class="highlight"><c- k>static_assert</c-></code> into a basic compile-time print statement that can be used to emit custom error messages.</p>
    <li data-md>
     <p>In C++26, <a data-link-type="biblio" href="#biblio-p2573r2" title="= delete(&quot;should have a reason&quot;);">[P2573R2]</a> allowed <code class="highlight"><c- o>=</c-> <c- k>delete</c-></code> to have an optional message parameter.</p>
   </ul>
   <p>The key difference between those extensions of the message parameter compared to <code class="highlight"><c- k>static_assert</c-></code> is that some of them don’t generate error messages but allow the library writer to control the content of the warnings generated by the compiler. These extensions have allowed more and more misuse of the library to be diagnosed with user-friendly error messages that directly convey the cause and the fix of errors, and contributed significantly to making C++'s error message more approachable and readable.</p>
   <p>However, despite these advancements, one key limitation of the message parameter in all these examples remained: the parameter must be an (unevaluated) string literal. This restriction means that no computation can be performed when providing the custom message, preventing library writers from providing more useful diagnostic messages to the user. For instance, with the following misuse of <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>format</c-></code>:</p>
<pre class="language-cpp highlight"><c- n>std</c-><c- o>::</c-><c- n>format</c-><c- p>(</c-><c- s>"{:d}"</c-><c- p>,</c-> <c- s>"not a number"</c-><c- p>);</c->
<c- c1>// Current error message: (https://godbolt.org/z/enxWj5WY1)</c->
<c- nl>error</c-><c- p>:</c-> <c- n>call</c-> <c- n>to</c-> <c- k>consteval</c-> <c- n>function</c-> '<c- n>std</c-><c- o>::</c-><c- n>basic_format_string</c-><c- o>&lt;</c-><c- b>char</c-><c- p>,</c-> <c- k>const</c-> <c- b>char</c-> <c- p>(</c-><c- o>&amp;</c-><c- p>)[</c-><c- mi>13</c-><c- p>]</c-><c- o>>::</c-><c- n>basic_format_string</c-><c- o>&lt;</c-><c- b>char</c-><c- p>[</c-><c- mi>5</c-><c- p>]</c-><c- o>></c->' <c- n>is</c-> <c- k>not</c-> <c- n>a</c-> <c- n>constant</c-> <c- n>expression</c->
<c- c1>// Potential best we can get using static_assert with fixed message parameter:</c->
<c- nl>error</c-><c- p>:</c-> <c- k>static</c-> <c- n>assertion</c-> <c- n>failed</c-> <c- n>due</c-> <c- n>to</c-> <c- n>requirement</c-> <c- p>[...]</c-><c- o>:</c-> <c- n>wrong</c-> <c- n>formatter</c-> <c- n>specified</c-> <c- k>for</c-> <c- n>std</c-><c- o>::</c-><c- n>format</c->
</pre>
   <p>The above "potential best" message is already much more user-friendly than the status quo but still lacks some crucial information: the position of the invalid argument (the first, the second, etc.), the actual required type of <code class="highlight"><c- o>:</c-><c- n>d</c-></code> (integer), and so on. Let’s compare with <a href="https://godbolt.org/z/GnKrGx7hn">Rust’s error message</a>:</p>
<pre class="language-rust highlight">format!<c- p>(</c-><c- s>"{} {:b}"</c-><c- p>,</c-> <c- mi>2</c-><c- p>,</c-> <c- s>"not a number"</c-><c- p>);</c->
<c- c1>// Error message:</c->
<c- n>error</c-><c- p>[</c-><c- n>E0277</c-><c- p>]</c->: <c- nc>the</c-> <c- k>trait</c-> <c- n>bound</c-> `<c- b>str</c->: <c- nc>Binary</c->` <c- n>is</c-> <c- n>not</c-> <c- n>satisfied</c->
 <c- o>-</c->-> <c- o>&lt;</c-><c- n>source</c-><c- o>></c->:<c- mi>3</c->:<c- mi>27</c->
  <c- o>|</c->
<c- mi>3</c-> <c- o>|</c->     format!<c- p>(</c-><c- s>"{} {:b}"</c-><c- p>,</c-> <c- mi>2</c-><c- p>,</c-> <c- s>"not a number"</c-><c- p>);</c->
  <c- o>|</c->                 <c- o>----</c->      <c- o>^^^^^^^^^^^^^^</c-> <c- n>the</c-> <c- k>trait</c-> `<c- n>Binary</c->` <c- n>is</c-> <c- n>not</c-> <c- n>implemented</c-> <c- k>for</c-> `<c- b>str</c->`<c- p>,</c-> <c- n>which</c-> <c- n>is</c-> <c- n>required</c-> <c- n>by</c-> `<c- o>&amp;</c-><c- b>str</c->: <c- nc>Binary</c->`
  <c- o>|</c->                 <c- o>|</c->
  <c- o>|</c->                 <c- n>required</c-> <c- n>by</c-> <c- n>a</c-> <c- n>bound</c-> <c- n>introduced</c-> <c- n>by</c-> <c- n>this</c-> <c- n>call</c->
  <c- o>|</c->
  <c- o>=</c-> <c- n>help</c->: <c- nc>the</c-> <c- n>following</c-> <c- n>other</c-> <c- n>types</c-> <c- n>implement</c-> <c- k>trait</c-> `<c- n>Binary</c->`:
            <c- kp>&amp;</c-><c- nc>T</c->
            <c- o>&amp;</c-><c- k>mut</c-> <c- n>T</c->
            <c- n>NonZero</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c->
            <c- n>Saturating</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c->
            <c- n>Wrapping</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c->
            <c- b>i128</c->
            <c- b>i16</c->
            <c- b>i32</c->
          <c- n>and</c-> <c- mi>9</c-> <c- n>others</c->
<c- p>[</c-><c- o>..</c-><c- p>.]</c->
</pre>
   <p>The above error message is clearly a step ahead even compared to C++'s "potential best" message achievable. Not only is the precise wrong argument and format specifier is pointed out, but several possible fixes (correct type for the argument) are suggested, prompting the user that an integer-like argument is required here.</p>
   <p>Such an error message is not possible with <code class="highlight"><c- k>static_assert</c-></code> with a fixed message parameter. Since no computation is allowed, contextual information, such as the position of the argument, cannot be embedded within the message. In light of this, in the C++17 cycle, <a data-link-type="biblio" href="#biblio-n4433" title="Flexible static_assert messages">[N4433]</a> proposed making <code class="highlight"><c- k>static_assert</c-></code>’s message parameter dynamically computed and allowing any expression contextually convertible to <code class="highlight"><c- k>const</c-> <c- n>charT</c-><c- o>*</c-></code> to appear in the message parameter.</p>
   <p>However, the consensus at that time was that the C++ language was not yet ready for dynamically computed string literals, since <code class="highlight"><c- k>constexpr</c-></code> evaluation was still too limited at that point (for example, <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>string</c-><c- p>[</c-><c- n>_view</c-><c- p>]</c-></code> could not be used at compile time at that time). Therefore, the first attempt to introduce dynamically generated diagnostic messages to C++ failed.</p>
   <p>The <code class="highlight"><c- k>constexpr</c-></code> evaluation had evolved significantly after that point in time. In C++20, we gained the ability to use <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>string</c-></code> and <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>string_view</c-></code> in compile-time, and the extension of allowing user-defined class types in NTTP allowed strings to be passed to functions as compile-time arguments. Nowadays, users no longer need to write compile-time string concatenations on their own, and compile-time string generation facilities such as <code class="highlight"><c- k>constexpr</c-> <c- n>std</c-><c- o>::</c-><c- n>format</c-></code> are also on the horizon (implemented by <code class="highlight"><c- p>{</c-><c- n>fmt</c-><c- p>}</c-></code> already).</p>
   <p>Finally, in the C++26 cycle, the matter of user-generated <code class="highlight"><c- k>static_assert</c-></code> messages is revisited, and <a data-link-type="biblio" href="#biblio-p2741r3" title="user-generated static_assert messages">[P2741R3]</a> allowed the use of custom-generated string-like parameters as the second message parameter of <code class="highlight"><c- k>static_assert</c-></code>. This relaxation had allowed for significantly better error messages that embed contextual information to appear in library code, thus allowing the above <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>format</c-></code> misuse example to output an error message similar to:</p>
<pre class="language-cpp highlight"><c- nl>error</c-><c- p>:</c-> <c- k>static</c-> <c- n>assertion</c-> <c- n>failed</c-> <c- n>due</c-> <c- n>to</c-> <c- n>requirement</c-> <c- p>[...]</c-><c- o>:</c-> <c- n>For</c-> <c- n>argument</c-> #<c- mi>1</c-><c- p>,</c-> <c- n>the</c-> <c- n>d</c-> <c- n>specifier</c-> <c- n>is</c-> <c- n>only</c-> <c- n>valid</c-> <c- k>for</c-> <c- n>integers</c-><c- p>,</c-> <c- n>but</c-> <c- n>a</c-> <c- n>argument</c-> <c- n>with</c-> <c- n>type</c-> <c- k>const</c-> <c- b>char</c-> <c- p>(</c-><c- o>&amp;</c-><c- p>)[</c-><c- mi>13</c-><c- p>]</c-> <c- n>was</c-> <c- n>provided</c-><c- p>.</c->
</pre>
   <p>Clearly, this new "potential best" error message is much superior to the previous best possible message, thus marking another big step forward for the user-friendliness of C++ error messages. To further expand this advantage, this proposal, therefore, proposes to allow the other three appearances of the message parameter in the core language to also accept user-generated string-like approaches. Such expansion not only unifies the language but also provides more opportunities for more friendly error/warning messages to be provided. Several examples of the possible diagnostics that will be allowed by this proposal can be seen in the Usage Examples section below.</p>
   <h2 class="heading settled" data-level="3" id="usage-examples"><span class="secno">3. </span><span class="content">Usage Example</span><a class="self-link" href="#usage-examples"></a></h2>
   <h3 class="heading settled" data-level="3.1" id="stl-usage"><span class="secno">3.1. </span><span class="content">Standard Library</span><a class="self-link" href="#stl-usage"></a></h3>
   <p>This part contains some concrete examples of how functions and classes in the standard library can benefit from the new flexibility of message parameters. All examples are based on <a data-link-type="biblio" href="#biblio-n4988" title="Working Draft, Programming Languages — C++">[N4988]</a>, and also assumes the existence of <code class="highlight"><c- k>constexpr</c-> <c- n>std</c-><c- o>::</c-><c- n>format</c-></code> (<a data-link-type="biblio" href="#biblio-p3391r0" title="constexpr std::format">[P3391R0]</a>) and Reflection (<a data-link-type="biblio" href="#biblio-p2996r5" title="Reflection for C++26">[P2996R5]</a>).</p>
   <p>One thing to note here is that <code class="highlight"><c- p>[[</c-><c- n>deprecated</c-><c- p>]]</c-></code> is never required on the deprecated features in the standard library. Similarly, <code class="highlight"><c- p>[[</c-><c- n>nodiscard</c-><c- p>]]</c-></code> is regarded as QoI after the adoption of <a data-link-type="biblio" href="#biblio-p2422r1" title="Remove nodiscard annotations from the standard library specification">[P2422R1]</a> in St. Louis (2024-06) and no longer appears in the standard library’s specification. Therefore, all the following examples only resemble some possible use of the attributes by a standard library vendor. All the examples below that used <code class="highlight"><c- p>[[</c-><c- n>nodiscard</c-><c- p>]]</c-></code> were marked as so in the specification before <a data-link-type="biblio" href="#biblio-p2422r1" title="Remove nodiscard annotations from the standard library specification">[P2422R1]</a> landed.</p>
<pre class="language-cpp highlight"><c- c1>// [memory.syn]</c->
<c- k>namespace</c-> <c- nn>std</c-> <c- p>{</c->
    <c- c1>// ...</c->
    <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- p>,</c-> <c- k>class</c-><c- p>...</c-> <c- n>Args</c-><c- o>></c-> <c- c1>// T is not array</c->
        <c- k>constexpr</c-> <c- n>unique_ptr</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- n>make_unique</c-><c- p>(</c-><c- n>Args</c-><c- o>&amp;&amp;</c-><c- p>...</c-> <c- n>args</c-><c- p>);</c->
    <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- o>></c-> <c- c1>// T is U[]</c->
        <c- k>constexpr</c-> <c- n>unique_ptr</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- n>make_unique</c-><c- p>(</c-><c- b>size_t</c-> <c- n>n</c-><c- p>);</c->
    <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- p>,</c-> <c- k>class</c-><c- p>...</c-> <c- n>Args</c-><c- o>></c-> <c- c1>// T is U[N]</c->
        <c- n>unspecified</c-> <c- n>make_unique</c-><c- p>(</c-><c- n>Args</c-><c- o>&amp;&amp;</c-><c- p>...)</c-> <c- o>=</c-> <c- k>delete</c-><c- p>(</c-><c- n>format</c-><c- p>(</c->
            <c- s>"make_unique&lt;U[{}]>(...) is not supported; perhaps you mean make_unique&lt;U[]>({}) instead?"</c-><c- p>,</c->
            <c- n>extent_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>,</c-> <c- n>extent_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c->
        <c- p>));</c->

    <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- p>,</c-> <c- k>class</c-><c- p>...</c-> <c- n>Args</c-><c- o>></c-> <c- c1>// T is not array</c->
        <c- k>constexpr</c-> <c- n>unique_ptr</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- n>make_unique_for_overwrite</c-><c- p>(</c-><c- n>Args</c-><c- o>&amp;&amp;</c-><c- p>...</c-> <c- n>args</c-><c- p>);</c->
    <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- o>></c-> <c- c1>// T is U[]</c->
        <c- k>constexpr</c-> <c- n>unique_ptr</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- n>make_unique_for_overwrite</c-><c- p>(</c-><c- b>size_t</c-> <c- n>n</c-><c- p>);</c->
    <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- p>,</c-> <c- k>class</c-><c- p>...</c-> <c- n>Args</c-><c- o>></c-> <c- c1>// T is U[N]</c->
        <c- n>unspecified</c-> <c- n>make_unique_for_overwrite</c-><c- p>(</c-><c- n>Args</c-><c- o>&amp;&amp;</c-><c- p>...)</c-> <c- o>=</c-> <c- k>delete</c-><c- p>(</c-><c- n>format</c-><c- p>(</c->
            <c- s>"make_unique_for_overwrite&lt;U[{}]>(...) is not supported; perhaps you mean make_unique_for_overwrite&lt;U[]>({}) instead?"</c-><c- p>,</c->
            <c- n>extent_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>,</c-> <c- n>extent_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c->
        <c- p>));</c->
<c- p>}</c->

<c- c1>// [new.syn]</c->
<c- k>namespace</c-> <c- nn>std</c-> <c- p>{</c->
    <c- c1>// [ptr.launder], pointer optimization barrier</c->
    <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- o>></c->
    <c- p>[[</c-><c- n>nodiscard</c-><c- p>(</c-><c- n>format</c-><c- p>(</c->
        <c- s>"The resulting {}* pointer returned is discarded, which defeats the purpose of std::launder."</c-><c- p>,</c->
        <c- n>meta</c-><c- o>::</c-><c- n>identifier_of</c-><c- p>(</c-><c- o>^^</c-><c- n>T</c-><c- p>)</c->
    <c- p>))]]</c->
    <c- k>constexpr</c-> <c- n>T</c-><c- o>*</c-> <c- n>launder</c-><c- p>(</c-><c- n>T</c-><c- o>*</c-> <c- n>p</c-><c- p>)</c-> <c- k>noexcept</c-><c- p>;</c->
<c- p>}</c->

<c- c1>// [future.syn]</c->
<c- k>namespace</c-> <c- nn>std</c-> <c- p>{</c->
    <c- c1>// [futures.async], function template async</c->
    <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>F</c-><c- p>,</c-> <c- k>class</c-><c- p>...</c-> <c- n>Args</c-><c- o>></c->
    <c- p>[[</c-><c- n>nodiscard</c-><c- p>(</c-><c- n>format</c-><c- p>(</c->
        <c- s>"The returning future&lt;{}> is discarded, which makes the given function of type {} always executes synchronously."</c-><c- p>,</c->
        <c- n>meta</c-><c- o>::</c-><c- n>identifier_of</c-><c- p>(</c-><c- o>^^</c-><c- n>invoke_result_t</c-><c- o>&lt;</c-><c- n>decay_t</c-><c- o>&lt;</c-><c- n>F</c-><c- o>></c-><c- p>,</c-> <c- n>decay_t</c-><c- o>&lt;</c-><c- n>Args</c-><c- o>></c-><c- p>...</c-><c- o>></c-><c- p>),</c-> <c- n>meta</c-><c- o>::</c-><c- n>identifier_of</c-><c- p>(</c-><c- o>^^</c-><c- n>F</c-><c- p>)</c->
    <c- p>))]]</c->
    <c- n>future</c-><c- o>&lt;</c-><c- n>invoke_result_t</c-><c- o>&lt;</c-><c- n>decay_t</c-><c- o>&lt;</c-><c- n>F</c-><c- o>></c-><c- p>,</c-> <c- n>decay_t</c-><c- o>&lt;</c-><c- n>Args</c-><c- o>></c-><c- p>...</c-><c- o>>></c->
    <c- n>async</c-><c- p>(</c-><c- n>F</c-><c- o>&amp;&amp;</c-> <c- n>f</c-><c- p>,</c-> <c- n>Args</c-><c- o>&amp;&amp;</c-><c- p>...</c-> <c- n>args</c-><c- p>);</c->
    <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>F</c-><c- p>,</c-> <c- k>class</c-><c- p>...</c-> <c- n>Args</c-><c- o>></c->
    <c- p>[[</c-><c- n>nodiscard</c-><c- p>(</c-><c- n>format</c-><c- p>(</c->
        <c- s>"The returning future&lt;{}> is discarded, which makes the given function of type {} always executes synchronously."</c-><c- p>,</c->
        <c- n>meta</c-><c- o>::</c-><c- n>identifier_of</c-><c- p>(</c-><c- o>^^</c-><c- n>invoke_result_t</c-><c- o>&lt;</c-><c- n>decay_t</c-><c- o>&lt;</c-><c- n>F</c-><c- o>></c-><c- p>,</c-> <c- n>decay_t</c-><c- o>&lt;</c-><c- n>Args</c-><c- o>></c-><c- p>...</c-><c- o>></c-><c- p>),</c-> <c- n>meta</c-><c- o>::</c-><c- n>identifier_of</c-><c- p>(</c-><c- o>^^</c-><c- n>F</c-><c- p>)</c->
    <c- p>))]]</c->
    <c- n>future</c-><c- o>&lt;</c-><c- n>invoke_result_t</c-><c- o>&lt;</c-><c- n>decay_t</c-><c- o>&lt;</c-><c- n>F</c-><c- o>></c-><c- p>,</c-> <c- n>decay_t</c-><c- o>&lt;</c-><c- n>Args</c-><c- o>></c-><c- p>...</c-><c- o>>></c->
    <c- n>async</c-><c- p>(</c-><c- n>launch</c-> <c- n>policy</c-><c- p>,</c-> <c- n>F</c-><c- o>&amp;&amp;</c-> <c- n>f</c-><c- p>,</c-> <c- n>Args</c-><c- o>&amp;&amp;</c-><c- p>...</c-> <c- n>args</c-><c- p>);</c->
<c- p>}</c->

<c- c1>// [depr.relops]</c->
<c- k>namespace</c-> <c- nn>std</c-><c- o>::</c-><c- nn>rel_ops</c-> <c- p>{</c->
    <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- o>></c->
    <c- p>[[</c-><c- n>deprecated</c-><c- p>(</c-><c- n>format</c-><c- p>(</c->
        <c- s>"operator!= will be automatically generated for class {}"</c-><c- p>,</c->
        <c- n>meta</c-><c- o>::</c-><c- n>identifier_of</c-><c- p>(</c-><c- o>^^</c-><c- n>T</c-><c- p>)</c->
    <c- p>))]]</c->
    <c- b>bool</c-> <c- k>operator</c-><c- o>!=</c-><c- p>(</c-><c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-><c- p>);</c->
<c- p>}</c->

<c- c1>// [depr.meta.types]</c->
<c- k>namespace</c-> <c- nn>std</c-> <c- p>{</c->
    <c- c1>// ...</c->
    <c- k>template</c-><c- o>&lt;</c-><c- b>size_t</c-> <c- n>Len</c-><c- p>,</c-> <c- b>size_t</c-> <c- n>Align</c-> <c- o>=</c-> <c- k>default</c-><c- o>-</c-><c- n>alignment</c-><c- o>></c-> <c- c1>// see below</c->
        <c- k>struct</c-> <c- p>[[</c-><c- n>deprecated</c-><c- p>(</c-><c- n>format</c-><c- p>(</c->
            <c- s>"use alignas({}) std::byte[{}] instead."</c-><c- p>,</c->
            <c- n>Align</c-><c- p>,</c-> <c- n>Len</c->
        <c- p>))]]</c-> <c- n>aligned_storage</c-><c- p>;</c->
    <c- k>template</c-><c- o>&lt;</c-><c- b>size_t</c-> <c- n>Len</c-><c- p>,</c-> <c- b>size_t</c-> <c- n>Align</c-> <c- o>=</c-> <c- k>default</c-><c- o>-</c-><c- n>alignment</c-> <c- o>></c-> <c- c1>// see below</c->
        <c- k>using</c-> <c- n>aligned_storage_t</c-> <c- o>=</c-> <c- k>typename</c-> <c- nc>aligned_storage</c-><c- o>&lt;</c-><c- n>Len</c-><c- p>,</c-> <c- n>Align</c-><c- o>>::</c-><c- n>type</c-><c- p>;</c->
    <c- k>template</c-><c- o>&lt;</c-><c- b>size_t</c-> <c- n>Len</c-><c- p>,</c-> <c- k>class</c-><c- p>...</c-> <c- n>Types</c-><c- o>></c->
        <c- k>struct</c-> <c- p>[[</c-><c- n>deprecated</c-><c- p>(</c-><c- n>format</c-><c- p>(</c->
            <c- s>"use alignas({}) std::byte[std::max({{{}}})] instead."</c-><c- p>,</c->
            <c- n>string_view</c-><c- p>{</c-><c- n>vector</c-><c- p>{</c-><c- n>meta</c-><c- o>::</c-><c- n>identifier_of</c-><c- p>(</c-><c- o>^^</c-><c- n>Types</c-><c- p>)...}</c-> <c- o>|</c-> <c- n>views</c-><c- o>::</c-><c- n>join_with</c-><c- p>(</c-><c- s>", "</c-><c- p>)},</c->
            <c- n>string_view</c-><c- p>{</c-><c- n>vector</c-><c- p>{</c-><c- n>format</c-><c- p>(</c-><c- s>"sizeof({})"</c-><c- p>,</c-> <c- n>meta</c-><c- o>::</c-><c- n>identifier_of</c-><c- p>(</c-><c- o>^^</c-><c- n>Types</c-><c- p>))...}</c-> <c- o>|</c-> <c- n>views</c-><c- o>::</c-><c- n>join_with</c-><c- p>(</c-><c- s>", "</c-><c- p>)}</c->
        <c- p>))]]</c-> <c- n>aligned_union</c-><c- p>;</c->
    <c- k>template</c-><c- o>&lt;</c-><c- b>size_t</c-> <c- n>Len</c-><c- p>,</c-> <c- k>class</c-><c- p>...</c-> <c- n>Types</c-><c- o>></c->
        <c- k>using</c-> <c- n>aligned_union_t</c-> <c- o>=</c-> <c- k>typename</c-> <c- nc>aligned_union</c-><c- o>&lt;</c-><c- n>Len</c-><c- p>,</c-> <c- n>Types</c-><c- p>...</c-><c- o>>::</c-><c- n>type</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>Some of the examples above are particularly notable:</p>
   <ul>
    <li data-md>
     <p>For <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>rel_ops</c-></code>, the dynamically generated message will embed the corresponding type parameter, which makes it easier for users to pinpoint which class still has relation operators generated by the deprecated <code class="highlight"><c- n>rel_ops</c-></code> namespace helper.</p>
    <li data-md>
     <p>For <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>aligned_union</c-></code>, the dynamically generated message will directly tell users about the correct classes and specific invocations to use:</p>
   </ul>
<pre class="language-cpp highlight"><c- c1>// Usage:</c->
<c- n>std</c-><c- o>::</c-><c- n>aligned_union_t</c-><c- o>&lt;</c-><c- mi>0</c-><c- p>,</c-> <c- n>A</c-><c- p>,</c-> <c- n>B</c-><c- o>></c-> <c- n>t_buff</c-><c- o>:</c->
<c- c1>// Diagnostics:</c->
<c- nl>warning</c-><c- p>:</c-> '<c- n>std</c-><c- o>::</c-><c- n>aligned_union</c->' <c- n>is</c-> <c- n>deprecated</c-><c- o>:</c-> <c- n>use</c-> <c- k>alignas</c-><c- p>(</c-><c- n>A</c-><c- p>,</c-> <c- n>B</c-><c- p>)</c-> <c- n>std</c-><c- o>::</c-><c- n>byte</c-><c- p>[</c-><c- n>std</c-><c- o>::</c-><c- n>max</c-><c- p>({</c-><c- k>sizeof</c-><c- p>(</c-><c- n>A</c-><c- p>),</c-> <c- k>sizeof</c-><c- p>(</c-><c- n>B</c-><c- p>)})]</c-> <c- n>instead</c-><c- p>.</c->
</pre>
   <ul>
    <li data-md>
     <p>All of these examples are just a proof of concept on how user-friendly diagnostics is possible; in reality, due to the cost of pulling in the dependency on <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>format</c-></code> and <code class="highlight"><c- o>&lt;</c-><c- n>ranges</c-><c- o>></c-></code>, such a message is probably not feasible for most vendors.</p>
   </ul>
   <h3 class="heading settled" data-level="3.2" id="third-party-libraries"><span class="secno">3.2. </span><span class="content">Third-Party Libraries</span><a class="self-link" href="#third-party-libraries"></a></h3>
   <p>A potential use case of the new flexibility to third-party library developers is to include the library name in every diagnostic emitted by the types and functions within the library. Although this is already achievable with the current fixed message parameter, adding the name to each message parameter is error-prone. A better approach is something like (assuming that <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>fixed_string</c-></code> (<a data-link-type="biblio" href="#biblio-p3094r3" title="std::basic_fixed_string">[P3094R3]</a>) exists):</p>
<pre class="language-cpp highlight"><c- k>namespace</c-> <c- nn>my_lib</c->
<c- p>{</c->
    <c- k>constexpr</c-> <c- n>std</c-><c- o>::</c-><c- n>fixed_string</c-> <c- n>lib_name</c-> <c- o>=</c-> <c- s>"myLib"</c-><c- p>;</c->

    <c- p>[[</c-><c- n>nodiscard</c-><c- p>(</c-><c- n>lib_name</c-> <c- o>+</c-> <c- s>": api()'s return value should not be discarded because ..."</c-><c- p>)]]</c->
    <c- b>void</c-> <c- n>api</c-><c- p>();</c->

    <c- k>struct</c-> <c- p>[[</c-><c- n>deprecated</c-><c- p>(</c-><c- n>lib_name</c-> <c- o>+</c-> <c- s>": class S is deprecated because ..."</c-><c- p>)]]</c-> <c- n>S</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>This design allows the library name to be changed easily by altering <code class="highlight"><c- n>lib_name</c-></code> and also reduces the possibility of misspelling the library name across different message parameters. Furthermore, a similar design can be applied to functions within a class, with the class name factored out into a <code class="highlight"><c- n>fixed_string</c-></code> static variable.</p>
   <h2 class="heading settled" data-level="4" id="design"><span class="secno">4. </span><span class="content">Design</span><a class="self-link" href="#design"></a></h2>
   <p>The general design of this proposal is to allow the following constructs:</p>
<pre class="language-cpp highlight"><c- o>=</c-> <c- k>delete</c-><c- p>(</c-><c- n>message</c-><c- p>);</c->
<c- p>[[</c-><c- n>nodiscard</c-><c- p>(</c-><c- n>message</c-><c- p>)]]</c->
<c- p>[[</c-><c- n>deprecated</c-><c- p>(</c-><c- n>message</c-><c- p>)]]</c->
</pre>
   <p>where <code class="highlight"><c- n>message</c-></code> can be a user-provided string-like parameter with the requirements documented below.</p>
   <h3 class="heading settled" data-level="4.1" id="what-is-a-string"><span class="secno">4.1. </span><span class="content">What Is A String?</span><a class="self-link" href="#what-is-a-string"></a></h3>
   <p>An immediately obvious question is: What constitute as a string that can be provided as the message parameter? Obviously, we don’t want these core language parameters to be tied to a concrete library type such as <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>string_view</c-></code>.</p>
   <p>Fortunately, <a data-link-type="biblio" href="#biblio-p2741r3" title="user-generated static_assert messages">[P2741R3]</a> already solved this problem for <code class="highlight"><c- k>static_assert</c-></code>. A compatible string-like type that can be used as the message parameter to <code class="highlight"><c- k>static_assert</c-></code> has the following requirements:</p>
   <ul>
    <li data-md>
     <p>Has a <code class="highlight"><c- n>size</c-><c- p>()</c-></code> member function that produces a type implicitly convertible to <code class="highlight"><c- n>std</c-><c- o>::</c-><c- b>size_t</c-></code></p>
    <li data-md>
     <p>Has a <code class="highlight"><c- n>data</c-><c- p>()</c-></code> member function that produces a type implicitly convertible to <code class="highlight"><c- k>const</c-> <c- b>char</c-><c- o>*</c-></code></p>
    <li data-md>
     <p>The elements in the range <code class="highlight"><c- p>[</c-><c- n>data</c-><c- p>(),</c-> <c- n>data</c-><c- p>()</c-><c- o>+</c-><c- n>size</c-><c- p>())</c-></code> are valid integer constant expression</p>
   </ul>
   <p>This proposal also proposes the same requirement for the message parameter in <code class="highlight"><c- o>=</c-> <c- k>delete</c-></code>, <code class="highlight"><c- p>[[</c-><c- n>nodiscard</c-><c- p>]]</c-></code>, and <code class="highlight"><c- p>[[</c-><c- n>deprecated</c-><c- p>]]</c-></code>.</p>
   <h3 class="heading settled" data-level="4.2" id="design-decisions"><span class="secno">4.2. </span><span class="content">Design Decisions</span><a class="self-link" href="#design-decisions"></a></h3>
   <p>The following design decisions were made by <a data-link-type="biblio" href="#biblio-p2741r3" title="user-generated static_assert messages">[P2741R3]</a> and are also proposed by this proposal. Please see <a data-link-type="biblio" href="#biblio-p2741r3" title="user-generated static_assert messages">[P2741R3]</a> for detailed motivations of these decisions:</p>
   <ul>
    <li data-md>
     <p>Only contiguous ranges are supported. Thus <code class="highlight"><c- n>data</c-><c- p>()</c-></code> and <code class="highlight"><c- n>size</c-><c- p>()</c-></code> are used instead of <code class="highlight"><c- n>begin</c-><c- p>()</c-></code> and <code class="highlight"><c- n>end</c-><c- p>()</c-></code>.</p>
    <li data-md>
     <p>The message-producing expression is always instantiated but only evaluated if the corresponding declaration fires:</p>
   </ul>
<pre class="language-cpp highlight"><c- k>template</c-><c- o>&lt;</c-><c- b>int</c-> <c- n>N</c-><c- o>></c->
<c- b>void</c-> <c- n>bad</c-><c- p>()</c-> <c- p>{</c-> <c- k>static_assert</c-><c- p>(</c-><c- n>N</c-> <c- o>></c-> <c- mi>0</c-><c- p>,</c-> <c- s>"fires"</c-><c- p>);</c-> <c- p>}</c->
<c- p>[[</c-><c- n>nodiscard</c-><c- p>(</c-><c- n>bad</c-><c- o>&lt;</c-><c- mi>0</c-><c- o>></c-><c- p>())]]</c-> <c- b>int</c-> <c- n>fun</c-><c- p>()</c-> <c- p>{</c-> <c- k>return</c-> <c- mi>2</c-><c- p>;</c-> <c- p>}</c->
<c- c1>// although fun() is never called, bad&lt;0> is instantiated and the static_assert is fired.</c->
</pre>
   <ul>
    <li data-md>
     <p>Only ranges of <code class="highlight"><c- b>char</c-></code> are supported; no support for <code class="highlight"><c- b>wchar_t</c-></code>, <code class="highlight"><c- b>char8_t</c-></code>, <code class="highlight"><c- b>char16_t</c-></code>, or <code class="highlight"><c- b>char32_t</c-></code> is proposed following SG16 guidance to <a data-link-type="biblio" href="#biblio-p2741r3" title="user-generated static_assert messages">[P2741R3]</a>.</p>
    <li data-md>
     <p>Diagnostic encoding is used, and the provided message parameter needs to be converted to that encoding.</p>
    <li data-md>
     <p>Null-terminated strings are not supported (<code class="highlight">\<c- mi>0</c-></code> will always be printed in the message).</p>
   </ul>
   <h3 class="heading settled" data-level="4.3" id="attribute-expression-argument"><span class="secno">4.3. </span><span class="content">Attribute Expression Argument</span><a class="self-link" href="#attribute-expression-argument"></a></h3>
   <p>One thing that is novel in this proposal is the fact that arbitrary expression is allowed as arguments to <code class="highlight"><c- p>[[</c-><c- n>nodiscard</c-><c- p>]]</c-></code> and <code class="highlight"><c- p>[[</c-><c- n>deprecated</c-><c- p>]]</c-></code> attributes. This is not completely unheard of, as, in C++23, the <code class="highlight"><c- p>[[</c-><c- n>assume</c-><c- p>]]</c-></code> attribute was adopted via <a data-link-type="biblio" href="#biblio-p1774r8" title="Portable assumptions">[P1774R8]</a>, which also accepts arbitrary expression as an argument. However, the processing of expression in these two cases is different:</p>
   <ul>
    <li data-md>
     <p>For <code class="highlight"><c- p>[[</c-><c- n>assume</c-><c- p>(</c-><c- n>expr</c-><c- p>)]]</c-></code>, <code class="highlight"><c- n>expr</c-></code> is allowed to be any expression, which is unevaluated but ODR-used (i.e. potentially evaluated).</p>
    <li data-md>
     <p>For <code class="highlight"><c- p>[[</c-><c- n>nodiscard</c-><c- p>(</c-><c- n>message</c-><c- p>)]]</c-></code> and <code class="highlight"><c- p>[[</c-><c- n>deprecated</c-><c- p>(</c-><c- n>message</c-><c- p>)]]</c-></code>, <code class="highlight"><c- n>message</c-></code> must be a constant expression, which is treated as an unevaluated operand if the applied entity is not used.</p>
   </ul>
   <p>Here, potentially evaluated and unevaluated operands are complete inversions of each other (<a href="https://eel.is/c++draft/basic.def.odr#3">[basic.def.odr]/3</a>). The most prominent distinction between those two treatments is the requirement on the definition of the function used:</p>
<pre class="language-cpp highlight"><c- b>int</c-> <c- nf>some_fact</c-><c- p>();</c-> <c- c1>// no definition</c->
<c- k>consteval</c-> <c- n>std</c-><c- o>::</c-><c- n>array</c-><c- o>&lt;</c-><c- b>char</c-><c- p>,</c-> <c- mi>5</c-><c- o>></c-> <c- n>message</c-><c- p>();</c-> <c- c1>// no definition yet</c->

<c- c1>// For ODR-use, all used functions must have a definition ([basic.def.odr]/12)</c->
<c- c1>// For unevaluated operand, function definitions are not required at the point of use</c->
<c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- nc>T</c-><c- o>></c->
<c- b>void</c-> <c- n>fun</c-><c- p>()</c->
<c- p>{</c->
    <c- p>[[</c-><c- n>assume</c-><c- p>(</c-><c- n>some_fact</c-><c- p>()</c-> <c- o>></c-> <c- mi>42</c-><c- p>)]];</c-> <c- c1>// IFNDR</c->
    <c- k>static_assert</c-><c- p>(</c->false<c- p>,</c-> <c- n>message</c-><c- p>());</c-> <c- c1>// okay</c->
<c- p>}</c->

<c- k>consteval</c-> <c- n>std</c-><c- o>::</c-><c- n>array</c-><c- o>&lt;</c-><c- b>char</c-><c- p>,</c-> <c- mi>5</c-><c- o>></c-> <c- n>message</c-><c- p>()</c->
<c- p>{</c->
    <c- k>return</c-> <c- p>{</c-><c- sc>'H'</c-><c- p>,</c-> <c- sc>'e'</c-><c- p>,</c-> <c- sc>'l'</c-><c- p>,</c-> <c- sc>'l'</c-><c- p>,</c-> <c- sc>'o'</c-><c- p>};</c->
<c- p>}</c->

<c- b>int</c-> <c- n>main</c-><c- p>()</c->
<c- p>{</c->
    <c- n>fun</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-><c- p>();</c-> <c- c1>// Diagnostics: Hello</c->
<c- p>}</c->
</pre>
   <p>Although as of Oct 2024, the latest released versions of GCC and Clang both do not diagnose the above example (<a href="https://godbolt.org/z/TGWzjEfM5">Compiler Explorer</a>) and instead just silently ignore the assumption.</p>
   <p>This can also affect the ABI of a class, as demonstrated in <a data-link-type="biblio" href="#biblio-p1774r8" title="Portable assumptions">[P1774R8]</a>:</p>
<pre class="language-cpp highlight"><c- k>constexpr</c-> <c- k>auto</c-> <c- n>f</c-><c- p>(</c-><c- b>int</c-> <c- n>i</c-><c- p>)</c-> <c- p>{</c->
    <c- k>return</c-> <c- k>sizeof</c-><c- p>(</c-> <c- p>[</c-><c- o>=</c-><c- p>]</c-> <c- p>{</c-> <c- p>[[</c-><c- n>assume</c-><c- p>(</c-><c- n>i</c-> <c- o>==</c-> <c- mi>0</c-><c- p>)]];</c-> <c- p>}</c-> <c- p>);</c->
<c- p>}</c->
<c- k>constexpr</c-> <c- k>auto</c-> <c- n>f2</c-><c- p>(</c-><c- b>int</c-> <c- n>i</c-><c- p>)</c-> <c- p>{</c->
    <c- c1>// nothing is actually captured here</c->
    <c- k>return</c-> <c- k>sizeof</c-><c- p>(</c-> <c- p>[</c-><c- o>=</c-><c- p>]</c-> <c- p>{</c-> <c- k>static_assert</c-><c- p>(</c->true<c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>array</c-><c- o>&lt;</c-><c- b>char</c-><c- p>,</c-> <c- mi>1</c-><c- o>></c-><c- p>{</c-><c- s>"Hello"</c-><c- p>[</c-><c- k>sizeof</c-><c- p>(</c-><c- n>i</c-><c- p>)]});</c-> <c- p>}</c-> <c- p>);</c->
<c- p>}</c->
<c- k>struct</c-> <c- nc>X</c-> <c- p>{</c->
    <c- b>char</c-> <c- n>data</c-><c- p>[</c-><c- n>f</c-><c- p>(</c-><c- mi>0</c-><c- p>)];</c->
<c- p>};</c->
<c- k>struct</c-> <c- nc>X2</c-> <c- p>{</c->
    <c- b>char</c-> <c- n>data</c-><c- p>[</c-><c- n>f2</c-><c- p>(</c-><c- mi>0</c-><c- p>)];</c->
<c- p>};</c->
<c- c1>// sizeof(X) == 4, sizeof(X2) == 1</c->
</pre>
   <p>Overall, the author doesn’t think that this discrepancy has that much of an effect since <code class="highlight"><c- p>[[</c-><c- n>nodiscard</c-><c- p>]]</c-></code> and <code class="highlight"><c- p>[[</c-><c- n>deprecated</c-><c- p>]]</c-></code>’s message parameter is required to be a constant expression, and no runtime behavior should be affected.</p>
   <h3 class="heading settled" data-level="4.4" id="attribute-placement"><span class="secno">4.4. </span><span class="content">Attribute Placement and Name Visibility</span><a class="self-link" href="#attribute-placement"></a></h3>
   <p>An unfortunate consequence of the grammar of attributes is that, as demonstrated in the Usage Example section, the placement of <code class="highlight"><c- p>[[</c-><c- n>nodiscard</c-><c- p>]]</c-></code> and <code class="highlight"><c- p>[[</c-><c- n>deprecated</c-><c- p>]]</c-></code> on class declarations must be after the <code class="highlight"><c- k>class</c-><c- o>-</c-><c- n>key</c-></code>:</p>
<pre class="language-cpp highlight"><c- p>[[</c-><c- n>nodiscard</c-><c- p>(</c-><c- n>message</c-><c- p>)]]</c-> <c- k>struct</c-> <c- nc>S</c-><c- p>;</c-> <c- c1>// Wrong, attribute ignored</c->
<c- k>struct</c-> <c- p>[[</c-><c- n>nodiscard</c-><c- p>(</c-><c- n>message</c-><c- p>)]]</c-> <c- n>S</c-><c- p>;</c-> <c- c1>// Right</c->
</pre>
   <p>Fortunately, most compilers will emit a warning that the specified attribute is ignored in this case.</p>
   <p>Another problem caused by the placement of attribute and <code class="highlight"><c- o>=</c-> <c- k>delete</c-></code> is the name visibility problem. Since <code class="highlight"><c- o>=</c-> <c- k>delete</c-></code> is a kind of definition and attributes must appear before the parameter list, the former can reference the parameters to the function:</p>
<pre class="language-cpp highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- nc>T</c-><c- o>></c-> <c- n>std</c-><c- o>::</c-><c- n>fixed_string</c-> <c- n>message</c-><c- p>();</c->

<c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- nc>T</c-><c- p>,</c-> <c- k>typename</c-> <c- nc>U</c-><c- o>></c->
<c- b>void</c-> <c- n>fun</c-><c- p>(</c-><c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>t</c-><c- p>,</c-> <c- k>const</c-> <c- n>U</c-><c- o>&amp;</c-> <c- n>u</c-><c- p>)</c-> <c- o>=</c-> <c- k>delete</c-><c- p>(</c-><c- n>message</c-><c- o>&lt;</c-><c- k>decltype</c-><c- p>(</c-><c- n>t</c-> <c- o>+</c-> <c- n>u</c-><c- p>)</c-><c- o>></c-><c- p>());</c->

<c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- nc>T</c-><c- p>,</c-> <c- k>typename</c-> <c- nc>U</c-><c- o>></c->
<c- p>[[</c-><c- n>nodiscard</c-><c- p>(</c-><c- n>message</c-><c- o>&lt;</c-><c- k>decltype</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>declval</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>()</c-> <c- o>+</c-> <c- n>std</c-><c- o>::</c-><c- n>declval</c-><c- o>&lt;</c-><c- n>U</c-><c- o>></c-><c- p>())</c-><c- o>></c-><c- p>())]]</c-> <c- c1>// cannot reference t and u here</c->
<c- b>int</c-> <c- n>fun2</c-><c- p>(</c-><c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>t</c-><c- p>,</c-> <c- k>const</c-> <c- n>U</c-><c- o>&amp;</c-> <c- n>u</c-><c- p>);</c->

<c- c1>// Placement:</c->
<c- p>[[</c-><c- n>deprecated</c-><c- p>]]</c-> <c- b>void</c-> <c- n>fun</c-><c- p>();</c-> <c- c1>// okay</c->
<c- b>void</c-> <c- n>fun</c-> <c- p>[[</c-><c- n>deprecated</c-><c- p>]]</c-> <c- p>();</c-> <c- c1>// okay, equivalent</c->
<c- b>void</c-> <c- nf>fun</c-><c- p>()</c-> <c- p>[[</c-><c- n>deprecated</c-><c- p>]];</c-> <c- c1>// attribute here applies to the function type, which is invalid and is silently ignored/cause error in major implementations</c->
</pre>
   <p>This proposal does not propose to change any grammar of attribute placement, and these unfortunate consequences are only documented here for information.</p>
   <h3 class="heading settled" data-level="4.5" id="invalid-message"><span class="secno">4.5. </span><span class="content">What If The Message Parameter Is Invalid?</span><a class="self-link" href="#invalid-message"></a></h3>
   <p>As discussed before, the message parameter is intended to always be instantiated but only evaluated on triggering:</p>
<pre class="language-cpp highlight"><c- k>template</c-> <c- o>&lt;</c-><c- k>auto</c-> <c- n>N</c-><c- o>></c->
<c- k>consteval</c-> <c- n>std</c-><c- o>::</c-><c- n>string_view</c-> <c- n>oups</c-><c- p>()</c-> <c- p>{</c->
    <c- k>static_assert</c-><c- p>(</c-><c- n>N</c-><c- p>,</c-> <c- s>"this always fires"</c-><c- p>);</c->
    <c- k>return</c-> <c- s>"oups!"</c-><c- p>;</c->
<c- p>}</c->
<c- b>void</c-> <c- n>f</c-><c- p>()</c-> <c- o>=</c-> <c- k>delete</c-><c- p>(</c-><c- n>oups</c-><c- o>&lt;</c->false<c- o>></c-><c- p>());</c-> <c- c1>// static_assert fires even though f() is not called</c->
<c- p>[[</c-><c- n>deprecated</c-><c- p>(</c-><c- n>oups</c-><c- o>&lt;</c->false<c- o>></c-><c- p>())]]</c-> <c- b>void</c-> <c- n>f2</c-><c- p>();</c-> <c- c1>// ditto</c->
</pre>
   <p>One possible alternative is to treat this as SFINAE, but that is inconsistent with the behavior of <code class="highlight"><c- k>static_assert</c-></code> and <code class="highlight"><c- p>[[</c-><c- n>assume</c-><c- p>]]</c-></code> in the function body.</p>
   <h3 class="heading settled" data-level="4.6" id="alternative-syntax"><span class="secno">4.6. </span><span class="content">Alternative Syntax Considered</span><a class="self-link" href="#alternative-syntax"></a></h3>
   <p>One possible alternative syntax proposed by <a data-link-type="biblio" href="#biblio-p1267r0" title="Custom Constraint Diagnostics">[P1267R0]</a> is to use a <code class="highlight"><c- p>[[</c-><c- n>reason</c-><c- p>]]</c-></code> attribute to express the message uniformly. Such a design will look like:</p>
<pre class="language-cpp highlight"><c- p>[[</c-><c- n>deprecated</c-><c- p>,</c-> <c- n>reason</c-><c- p>(</c-><c- n>message</c-><c- p>)]]</c-> <c- b>void</c-> <c- n>fun</c-><c- p>();</c->
<c- p>[[</c-><c- n>nodiscard</c-><c- p>,</c-> <c- n>reason</c-><c- p>(</c-><c- n>message</c-><c- p>)]]</c-> <c- b>int</c-> <c- n>fun2</c-><c- p>();</c->
<c- p>[[</c-><c- n>reason</c-><c- p>(</c-><c- n>message</c-><c- p>)]]</c-> <c- b>void</c-> <c- n>fun3</c-><c- p>()</c-> <c- o>=</c-> <c- k>delete</c-><c- p>;</c->
</pre>
   <p>However, <code class="highlight"><c- p>[[</c-><c- n>deprecated</c-><c- p>]]</c-></code>, <code class="highlight"><c- p>[[</c-><c- n>nodiscard</c-><c- p>]]</c-></code>, and <code class="highlight"><c- o>=</c-> <c- k>delete</c-></code> already accept a message parameter today, so the author thinks this ship has already been sunk.</p>
   <h3 class="heading settled" data-level="4.7" id="claim-of-syntax-space"><span class="secno">4.7. </span><span class="content">Claim of Syntax Space</span><a class="self-link" href="#claim-of-syntax-space"></a></h3>
   <p>During the EWGI review of <a data-link-type="biblio" href="#biblio-p2573r2" title="= delete(&quot;should have a reason&quot;);">[P2573R2]</a>, some people expressed concern about the possibility of that proposal "claiming the syntax space" of possible further enhancement to <code class="highlight"><c- o>=</c-> <c- k>delete</c-></code>. The same concern may apply to this proposal; namely, it is possible for a future proposal to propose "conditional <code class="highlight"><c- p>[[</c-><c- n>nodiscard</c-><c- p>]]</c-></code>":</p>
<pre class="language-cpp highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- nc>T</c-><c- o>></c->
<c- p>[[</c-><c- n>nodiscard</c-><c- p>(</c-><c- k>sizeof</c-><c- p>(</c-><c- n>T</c-><c- p>)</c-> <c- o>></c-> <c- mi>10</c-><c- p>)]]</c-> <c- b>int</c-> <c- n>some_fun</c-><c- p>();</c->
</pre>
   <p>While this is certainly a possible future direction, the author doesn’t think this proposal claims any syntax space in this regard. Similar to <code class="highlight"><c- k>static_assert</c-></code>, the only modification needed for conditional <code class="highlight"><c- p>[[</c-><c- n>nodiscard</c-><c- p>]]</c-></code> to still be possible is to require two arguments in that case:</p>
<pre class="language-cpp highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- nc>T</c-><c- o>></c->
<c- p>[[</c-><c- n>nodiscard</c-><c- p>(</c-><c- k>sizeof</c-><c- p>(</c-><c- n>T</c-><c- p>)</c-> <c- o>></c-> <c- mi>10</c-><c- p>,</c-> <c- s>"reason"</c-><c- p>)]]</c-> <c- b>int</c-> <c- n>some_fun</c-><c- p>();</c->
</pre>
   <p>This does sacrifice some convenience, but if desired, the distinction can be made such that for <code class="highlight"><c- p>[[</c-><c- n>nodiscard</c-><c- p>(</c-><c- n>expr</c-><c- p>)]]</c-></code>, if <code class="highlight"><c- n>expr</c-></code> is convertible to <code class="highlight"><c- b>bool</c-></code>, then conditional semantic is used; if <code class="highlight"><c- n>expr</c-></code> satisfies the string-like requirements, the message semantic is used. A tie-breaker between these two is obviously needed for types that satisfy both, but the author doesn’t think this is a huge conflict that forms an obstacle to this proposal.</p>
   <h3 class="heading settled" data-level="4.8" id="interaction-with-reflection"><span class="secno">4.8. </span><span class="content">Interaction with Reflection</span><a class="self-link" href="#interaction-with-reflection"></a></h3>
   <p>Reflection (<a data-link-type="biblio" href="#biblio-p2996r5" title="Reflection for C++26">[P2996R5]</a>) is great and will probably come to C++ in the near future. It will also greatly aid in generating friendly diagnostic messages that display the template type argument’s name, as demonstrated in the Usage Examples section above.</p>
   <p>However, a natural question arises: should there be a reflection facility to get the message specified to <code class="highlight"><c- o>=</c-> <c- k>delete</c-></code> and attributes?</p>
   <p>In the current reflection proposal (<a data-link-type="biblio" href="#biblio-p2996r5" title="Reflection for C++26">[P2996R5]</a>), there is one metafunction that queries whether the function is deleted: <code class="highlight"><c- n>meta</c-><c- o>::</c-><c- n>is_deleted</c-></code>. No attribute-reflecting mechanisms are proposed in <a data-link-type="biblio" href="#biblio-p2996r5" title="Reflection for C++26">[P2996R5]</a>, but there is ongoing work on reflecting attributes first by <a data-link-type="biblio" href="#biblio-p1887r1" title="Reflection on attributes">[P1887R1]</a> and currently by <a data-link-type="biblio" href="#biblio-p3385r0" title="Attributes reflection">[P3385R0]</a>. Should these proposals also propose the ability to query the message provided to the attributes and <code class="highlight"><c- o>=</c-> <c- k>delete</c-></code>?</p>
   <p>The author thinks that they probably should (for instance, by letting <code class="highlight"><c- n>meta</c-><c- o>::</c-><c- n>display_name_of</c-></code> return the message or add a new <code class="highlight"><c- n>meta</c-><c- o>::</c-><c- n>message_of</c-></code>), but this is certainly outside the scope of this proposal. The message parameter already exists in these attributes, and this proposal does not add any new parameters to them, so the difficulty of supporting them should not change drastically.</p>
   <h3 class="heading settled" data-level="4.9" id="proposal-scope"><span class="secno">4.9. </span><span class="content">Proposal Scope</span><a class="self-link" href="#proposal-scope"></a></h3>
   <p>This proposal is a pure language extension proposal with no library changes involved. It is also a pure addition, so no breaking changes are involved.
It is intended practice that exchanging <code class="highlight"><c- o>=</c-> <c- k>delete</c-><c- p>(</c-><c- s>"message"</c-><c- p>);</c-></code> for <code class="highlight"><c- o>=</c-> <c- k>delete</c-><c- p>(</c-><c- n>func</c-><c- p>());</c-></code> will have no breakage and no user-noticeable effect except for the diagnostic messages.</p>
   <p>There has been sustained strong opposition to the idea of mandating diagnostic texts in the standard library specifications, and in my opinion, such complaints are justified.
This paper does not change this by only proposing to make passing a user-generated string-like object as a message parameter possible and nothing more.</p>
   <p>This paper encourages vendors to apply any message they see fit for the purpose as a non-breaking QoI feature.</p>
   <h3 class="heading settled" data-level="4.10" id="target-vehicle"><span class="secno">4.10. </span><span class="content">Target Vehicle</span><a class="self-link" href="#target-vehicle"></a></h3>
   <p>This proposal targets C++26.</p>
   <h3 class="heading settled" data-level="4.11" id="feature-test-macro"><span class="secno">4.11. </span><span class="content">Feature Test Macro</span><a class="self-link" href="#feature-test-macro"></a></h3>
   <p>This proposal bumps the feature test macro for <code class="highlight"><c- o>=</c-> <c- k>delete</c-></code> (<code class="highlight"><c- n>__cpp_deleted_function</c-></code>) and the value reported by <code class="highlight"><c- n>__has_cpp_attribute</c-></code> for <code class="highlight"><c- p>[[</c-><c- n>nodiscard</c-><c- p>]]</c-></code> and <code class="highlight"><c- p>[[</c-><c- n>deprecated</c-><c- p>]]</c-></code>.</p>
   <p>However, one thing to note here is that <code class="highlight"><c- n>__has_cpp_attribute</c-></code> will report <code class="highlight"><c- mi>0</c-></code> for <code class="highlight"><c- p>[[</c-><c- n>nodiscard</c-><c- p>]]</c-></code> and <code class="highlight"><c- p>[[</c-><c- n>deprecated</c-><c- p>]]</c-></code> if the implementation cannot issue a warning that includes the text of the message provided. This proposal intends for the following rules to be used:</p>
   <ul>
    <li data-md>
     <p>If an implementation cannot issue warnings that include the message (even a fixed message) at all, <code class="highlight"><c- n>__has_cpp_attribute</c-></code> should report <code class="highlight"><c- mi>0</c-></code>.</p>
    <li data-md>
     <p>If an implementation can issue warnings that include a fixed (string literal) message supplied but cannot support arbitrary string-like constant parameter as a message, <code class="highlight"><c- n>__has_cpp_attribute</c-></code> should report their current value (<code class="highlight"><c- mf>201907L</c-></code> for <code class="highlight"><c- p>[[</c-><c- n>nodiscard</c-><c- p>]]</c-></code> and <code class="highlight"><c- mf>201309L</c-></code> for <code class="highlight"><c- p>[[</c-><c- n>deprecated</c-><c- p>]]</c-></code> as of Oct 2024).</p>
    <li data-md>
     <p>If an implementation can issue warnings that include user-generated strings, <code class="highlight"><c- n>__has_cpp_attribute</c-></code> should report the new values modified by this proposal.</p>
   </ul>
   <p>Such rules are consistent with how other feature test macros worked.</p>
   <h2 class="heading settled" data-level="5" id="implementation"><span class="secno">5. </span><span class="content">Implementation Experience</span><a class="self-link" href="#implementation"></a></h2>
   <p>An experimental implementation of the proposed feature is located in my Clang fork at <a data-link-type="biblio" href="#biblio-clang-implementation" title="Mick235711&apos;s Clang Fork">[clang-implementation]</a>, which is capable of handling</p>
<pre class="language-cpp highlight"><c- k>template</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>fixed_string</c-> <c- n>str</c-><c- o>></c->
<c- k>consteval</c-> <c- n>std</c-><c- o>::</c-><c- n>fixed_string</c-><c- o>&lt;</c-><c- n>str</c-><c- p>.</c-><c- n>size</c-><c- p>()</c-> <c- o>+</c-> <c- mi>2</c-><c- o>></c-> <c- n>fun</c-><c- p>()</c->
<c- p>{</c->
    <c- k>return</c-> <c- s>"^"</c-> <c- o>+</c-> <c- n>str</c-> <c- o>+</c-> <c- s>"$"</c-><c- p>;</c->
<c- p>}</c->

<c- b>void</c-> <c- n>fun1</c-><c- p>()</c-> <c- o>=</c-> <c- k>delete</c-><c- p>(</c-><c- n>fun</c-><c- o>&lt;</c-><c- s>"Test"</c-><c- o>></c-><c- p>());</c->
<c- p>[[</c-><c- n>nodiscard</c-><c- p>(</c-><c- n>fun</c-><c- o>&lt;</c-><c- s>"Test2"</c-><c- o>></c-><c- p>())]]</c-> <c- b>int</c-> <c- n>fun2</c-><c- p>()</c-> <c- p>{</c-> <c- k>return</c-> <c- mi>2</c-><c- p>;</c-> <c- p>}</c->
<c- p>[[</c-><c- n>deprecated</c-><c- p>(</c-><c- n>fun</c-><c- o>&lt;</c-><c- s>"Test3"</c-><c- o>></c-><c- p>())]]</c-> <c- b>void</c-> <c- n>fun3</c-><c- p>()</c-> <c- p>{}</c->
</pre>
   <p>and outputting the following diagnostic messages (close to what the author intended; of course, there are other formats such as put reason on separate lines):</p>
<pre class="language-cpp highlight"><c- n>propose</c-><c- p>.</c-><c- n>cpp</c-><c- o>:</c-><c- mi>56</c-><c- o>:</c-><c- mi>5</c-><c- o>:</c-> <c- n>error</c-><c- o>:</c-> <c- n>call</c-> <c- n>to</c-> <c- n>deleted</c-> <c- n>function</c-> '<c- n>fun1</c->'<c- o>:</c-> <c- o>^</c-><c- n>Test$</c->
   <c- mi>56</c-> <c- o>|</c->     <c- n>fun1</c-><c- p>();</c-> <c- n>fun2</c-><c- p>();</c-> <c- n>fun3</c-><c- p>();</c->
      <c- o>|</c->     <c- o>^~~~</c->
<c- n>propose</c-><c- p>.</c-><c- n>cpp</c-><c- o>:</c-><c- mi>50</c-><c- o>:</c-><c- mi>6</c-><c- o>:</c-> <c- n>note</c-><c- o>:</c-> <c- n>candidate</c-> <c- n>function</c-> <c- n>has</c-> <c- n>been</c-> <c- n>explicitly</c-> <c- n>deleted</c->
   <c- mi>50</c-> <c- o>|</c-> <c- b>void</c-> <c- n>fun1</c-><c- p>()</c-> <c- o>=</c-> <c- k>delete</c-><c- p>(</c-><c- n>fun</c-><c- o>&lt;</c-><c- s>"Test"</c-><c- o>></c-><c- p>());</c->
      <c- o>|</c->      <c- o>^</c->
<c- n>propose</c-><c- p>.</c-><c- n>cpp</c-><c- o>:</c-><c- mi>56</c-><c- o>:</c-><c- mi>13</c-><c- o>:</c-> <c- n>warning</c-><c- o>:</c-> <c- n>ignoring</c-> <c- k>return</c-> <c- n>value</c-> <c- n>of</c-> <c- n>function</c-> <c- n>declared</c-> <c- n>with</c-> '<c- n>nodiscard</c->' <c- n>attribute</c-><c- o>:</c-> <c- o>^</c-><c- n>Test2$</c-> <c- p>[</c-><c- o>-</c-><c- n>Wunused</c-><c- o>-</c-><c- n>result</c-><c- p>]</c->
   <c- mi>56</c-> <c- o>|</c->     <c- n>fun1</c-><c- p>();</c-> <c- n>fun2</c-><c- p>();</c-> <c- n>fun3</c-><c- p>();</c->
      <c- o>|</c->             <c- o>^~~~</c->
<c- n>propose</c-><c- p>.</c-><c- n>cpp</c-><c- o>:</c-><c- mi>56</c-><c- o>:</c-><c- mi>21</c-><c- o>:</c-> <c- n>warning</c-><c- o>:</c-> '<c- n>fun3</c->' <c- n>is</c-> <c- n>deprecated</c-><c- o>:</c-> <c- o>^</c-><c- n>Test3$</c-> <c- p>[</c-><c- o>-</c-><c- n>Wdeprecated</c-><c- o>-</c-><c- n>declarations</c-><c- p>]</c->
   <c- mi>56</c-> <c- o>|</c->     <c- n>fun1</c-><c- p>();</c-> <c- n>fun2</c-><c- p>();</c-> <c- n>fun3</c-><c- p>();</c->
      <c- o>|</c->                     <c- o>^</c->
<c- n>propose</c-><c- p>.</c-><c- n>cpp</c-><c- o>:</c-><c- mi>52</c-><c- o>:</c-><c- mi>3</c-><c- o>:</c-> <c- n>note</c-><c- o>:</c-> '<c- n>fun3</c->' <c- n>has</c-> <c- n>been</c-> <c- n>explicitly</c-> <c- n>marked</c-> <c- n>deprecated</c-> <c- n>here</c->
   <c- mi>52</c-> <c- o>|</c-> <c- p>[[</c-><c- n>deprecated</c-><c- p>(</c-><c- n>fun</c-><c- o>&lt;</c-><c- s>"Test3"</c-><c- o>></c-><c- p>())]]</c-> <c- b>void</c-> <c- n>fun3</c-><c- p>()</c-> <c- p>{}</c->
      <c- o>|</c->   <c- o>^</c->
<c- mi>2</c-> <c- n>warnings</c-> <c- k>and</c-> <c- mi>1</c-> <c- n>error</c-> <c- n>generated</c-><c- p>.</c->
</pre>
   <p>The implementation is <em>very</em> incomplete (no feature-test macro, only a few tests, etc.), so it is only aimed at proving that the vendors can support
the proposed feature relatively easily. No significant obstacles are observed during the implementation.</p>
   <h2 class="heading settled" data-level="6" id="wording"><span class="secno">6. </span><span class="content">Wording</span><a class="self-link" href="#wording"></a></h2>
   <p>The wording below is based on <a data-link-type="biblio" href="#biblio-n4988" title="Working Draft, Programming Languages — C++">[N4988]</a>.</p>
   <p>Wording notes for CWG and editor:</p>
   <ul>
    <li data-md>
     <p>The wording below renames <code class="highlight"><c- k>static_assert</c-><c- o>-</c-><c- n>message</c-></code> to <code class="highlight"><c- n>diagnostic</c-><c- o>-</c-><c- n>message</c-></code>, which is now used as the grammar for the general diagnostic message parameter.</p>
    <li data-md>
     <p>The phrase "text of the <code class="highlight"><c- n>diagnostic</c-><c- o>-</c-><c- n>message</c-></code>" is treated as a word of power, and is referenced by other sections defining <code class="highlight"><c- o>=</c-> <c- k>delete</c-></code> and attributes to simplify the wording.</p>
   </ul>
   <h3 class="heading settled" data-level="6.1" id="expr.const"><span class="secno">6.1. </span><span class="content">7.7 Constant expressions [expr.const]</span><a class="self-link" href="#expr.const"></a></h3>
   <blockquote>
    <p>[<em>Note 12</em>: Except for a <i><del>static_assert</del><ins>diagnostic</ins>-message</i>, a manifestly constant-evaluated expression is evaluated even in an
unevaluated operand ([expr.context]). — <em>end note</em>]</p>
   </blockquote>
   <h3 class="heading settled" data-level="6.2" id="dcl.pre"><span class="secno">6.2. </span><span class="content">9.1 Preamble [dcl.pre]</span><a class="self-link" href="#dcl.pre"></a></h3>
   <p>Paragraph 1:</p>
   <blockquote>
    <p>Declarations generally specify how names are to be interpreted. Declarations have the form</p>
   </blockquote>
<pre class="highlight">[...]
<i><del>static_assert</del><ins>diagnostic</ins>-message</i>:
    <i>unevaluated-string</i>
    <i>constant-expression</i>
<i>static_assert-declaration</i>:
    static_assert ( <i>constant-expression</i> ) ;
    static_assert ( <i>constant-expression</i> , <i><del>static_assert</del><ins>diagnostic</ins>-message</i> ) ;
[...]
</pre>
   <p>Paragraph 12:</p>
   <blockquote>
    <p>If a <i><del>static_assert</del><ins>diagnostic</ins>-message</i> matches the syntactic requirements of <em>unevaluated-string</em>, it is an <em>unevaluated-string</em> and the text of the <i><del>static_assert</del><ins>diagnostic</ins>-message</i> is the text of the <em>unevaluated-string</em>. Otherwise, a <i><del>static_assert</del><ins>diagnostic</ins>-message</i> shall be an expression <code class="highlight"><c- n>M</c-></code> such that [...]</p>
   </blockquote>
   <p>Paragraph 13:</p>
   <blockquote>
    <p>In a <em>static_assert-declaration</em>, the <em>constant-expression</em> <code class="highlight"><c- n>E</c-></code> is contextually converted to <code class="highlight"><c- b>bool</c-></code> and the converted expression shall be a constant expression ([expr.const]). If the value of the expression <code class="highlight"><c- n>E</c-></code> when so converted is <code class="highlight">true</code> or the expression is evaluated in the context of a template definition, the declaration has no effect and the <i><del>static_assert</del><ins>diagnostic</ins>-message</i> is an unevaluated operand ([expr.context]). Otherwise, the <em>static_assert-declaration</em> fails and</p>
    <ul>
     <li data-md>
      <p>the program is ill-formed, and</p>
     <li data-md>
      <p>if the <i><del>static_assert</del><ins>diagnostic</ins>-message</i> is a <em>constant-expression</em> <code class="highlight"><c- n>M</c-></code>,</p>
     <li data-md>
      <p><code class="highlight"><c- n>M</c-><c- p>.</c-><c- n>size</c-><c- p>()</c-></code> shall be a converted constant expression of type <code class="highlight"><c- n>std</c-><c- o>::</c-><c- b>size_t</c-></code> and let <code class="highlight"><c- n>N</c-></code> denote the value of that expression,</p>
     <li data-md>
      <p><code class="highlight"><c- n>M</c-><c- p>.</c-><c- n>data</c-><c- p>()</c-></code>, implicitly converted to the type "pointer to <code class="highlight"><c- k>const</c-> <c- b>char</c-></code>", shall be a core constant expression and let <code class="highlight"><c- n>D</c-></code> denote the converted expression,</p>
     <li data-md>
      <p>for each <code class="highlight"><c- n>i</c-></code> where <code class="highlight"><c- mi>0</c-> ≤ <c- n>i</c-> <c- o>&lt;</c-> <c- n>N</c-></code>, <code class="highlight"><c- n>D</c-><c- p>[</c-><c- n>i</c-><c- p>]</c-></code> shall be an integral constant expression, and</p>
     <li data-md>
      <p>the text of the <i><del>static_assert</del><ins>diagnostic</ins>-message</i> is formed by the sequence of <code class="highlight"><c- n>N</c-></code> code units, starting at <code class="highlight"><c- n>D</c-></code>, of the ordinary literal encoding ([lex.charset]).</p>
    </ul>
   </blockquote>
   <p>Paragraph 14:</p>
   <blockquote>
    <p><em>Recommended practice</em>: When a <em>static_assert-declaration</em> fails, the resulting diagnostic message should include the text of the <i><del>static_assert</del><ins>diagnostic</ins>-message</i>, if one is supplied.</p>
   </blockquote>
   <h3 class="heading settled" data-level="6.3" id="dcl.fct.def"><span class="secno">6.3. </span><span class="content">9.5 Function definitions [dcl.fct.def]</span><a class="self-link" href="#dcl.fct.def"></a></h3>
   <h4 class="heading settled" data-level="6.3.1" id="dcl.fct.def.general"><span class="secno">6.3.1. </span><span class="content">9.5.1 General [dcl.fct.def.general]</span><a class="self-link" href="#dcl.fct.def.general"></a></h4>
   <p>Paragraph 1:</p>
   <blockquote>
    <p>Function definitions have the form</p>
   </blockquote>
<pre class="highlight"><i>function-definition</i>:
    <i>attribute-specifier-seq<sub>opt</sub> decl-specifier-seq<sub>opt</sub> declarator virt-specifier-seq<sub>opt</sub> function-body</i>
    <i>attribute-specifier-seq<sub>opt</sub> decl-specifier-seq<sub>opt</sub> declarator requires-clause function-body</i>
<i>function-body</i>:
    <i>ctor-initializer<sub>opt</sub> compound-statement</i>
    <i>function-try-block</i>
    = default ;
    <i>deleted-function-body</i>
<i>deleted-function-body</i>:
    = delete ;
    = delete ( <i><del>unevaluated-string</del><ins>diagnostic-message</ins></i> ) ;
</pre>
   <h4 class="heading settled" data-level="6.3.2" id="dcl.fct.def.delete"><span class="secno">6.3.2. </span><span class="content">9.5.3 Deleted definitions [dcl.fct.def.delete]</span><a class="self-link" href="#dcl.fct.def.delete"></a></h4>
   <p>Paragraph 2:</p>
   <blockquote>
    <p>A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed.</p>
   </blockquote>
   <blockquote>
    <p><em>Recommended practice</em>: The resulting diagnostic message should include the text of the <i><del>unevaluated-string</del><ins>diagnostic-message ([dcl.pre])</ins></i>, if one is supplied.</p>
   </blockquote>
   <blockquote>
    <p>[<em>Note 1</em>: This includes calling the function implicitly or explicitly and forming a pointer or pointer-to-member to the function.
It applies even for references in expressions that are not potentially-evaluated. For an overload set, only the function selected by overload resolution is referenced.
The implicit odr-use ([basic.def.odr]) of a virtual function does not, by itself, constitute a reference. The <i><del>unevaluated-string</del><ins>diagnostic-message</ins></i>, if present, can be used to explain the rationale for deletion and/or to suggest an alternative. — <em>end note</em>]</p>
   </blockquote>
   <h3 class="heading settled" data-level="6.4" id="dcl.attr"><span class="secno">6.4. </span><span class="content">9.12 Attributes [dcl.attr]</span><a class="self-link" href="#dcl.attr"></a></h3>
   <h4 class="heading settled" data-level="6.4.1" id="dcl.attr.deprecated"><span class="secno">6.4.1. </span><span class="content">9.12.5 Deprecated attribute [dcl.attr.deprecated]</span><a class="self-link" href="#dcl.attr.deprecated"></a></h4>
   <p>Paragraph 1:</p>
   <blockquote>
    <p>The <em>attribute-token</em> <code class="highlight"><c- n>deprecated</c-></code> can be used to mark names and entities whose use is still allowed, but is discouraged for some reason.</p>
   </blockquote>
   <blockquote>
    <p>[<em>Note 1</em>: In particular, <code class="highlight"><c- n>deprecated</c-></code> is appropriate for names and entities that are deemed obsolescent or unsafe. — <em>end note</em>]</p>
   </blockquote>
   <blockquote>
    <p>An <em>attribute-argument-clause</em> may be present and, if present, it shall have the form:</p>
   </blockquote>
<pre class="highlight">( <i><del>unevaluated-string</del><ins>diagnostic-message</ins></i> )
</pre>
   <blockquote>
    <p>[<em>Note 2</em>: The <i><del>unevaluated-string</del><ins>diagnostic-message</ins></i> in the <em>attribute-argument-clause</em> can be used to explain the rationale for deprecation and/or to suggest a replacing entity. — <em>end note</em>]</p>
   </blockquote>
   <p>Paragraph 4:</p>
   <blockquote>
    <p>
     <em>Recommended practice</em>: Implementations should use the <code class="highlight"><c- n>deprecated</c-></code> attribute to produce a diagnostic message in case the program refers to a name or entity other than to declare it, after a declaration that specifies the attribute. The diagnostic message should include the text
     <ins> of the <em>diagnostic-message</em> ([dcl.pre])</ins>
      provided within the <em>attribute-argument-clause</em> of any <code class="highlight"><c- n>deprecated</c-></code> attribute applied to the name or entity. The value of a <em>has-attribute-expression</em> for the <code class="highlight"><c- n>deprecated</c-></code> attribute should be <code class="highlight"><c- mi>0</c-></code> unless the implementation can issue such diagnostic messages.
    </p>
   </blockquote>
   <h4 class="heading settled" data-level="6.4.2" id="dcl.attr.nodiscard"><span class="secno">6.4.2. </span><span class="content">9.12.10 Nodiscard attribute [dcl.attr.nodiscard]</span><a class="self-link" href="#dcl.attr.nodiscard"></a></h4>
   <p>Paragraph 1:</p>
   <blockquote>
    <p>The <em>attribute-token</em> <code class="highlight"><c- n>nodiscard</c-></code> may be applied to a function or a lambda call operator or to the declaration of a class or enumeration. An <em>attribute-argument-clause</em> may be present and, if present, it shall have the form:</p>
   </blockquote>
<pre class="highlight">( <i><del>unevaluated-string</del><ins>diagnostic-message</ins></i> )
</pre>
   <p>Paragraph 4:</p>
   <blockquote>
    <p><em>Recommended practice</em>: Appearance of a <code class="highlight"><c- n>nodiscard</c-></code> call as a potentially-evaluated discarded-value expression ([expr.prop]) is discouraged unless explicitly cast to <code class="highlight"><c- b>void</c-></code>. Implementations should issue a warning in such cases. The value of a <em>has-attribute-expression</em> for the <code class="highlight"><c- n>nodiscard</c-></code> attribute should be <code class="highlight"><c- mi>0</c-></code> unless the implementation can issue such warnings.</p>
   </blockquote>
   <blockquote>
    <p>[<em>Note 2</em>: This is typically because discarding the return value of a <code class="highlight"><c- n>nodiscard</c-></code> call has surprising consequences. — <em>end note</em>]</p>
   </blockquote>
   <blockquote>
    <p>
     The <i><del>unevaluated-string</del></i>
     <ins>text of the <i>diagnostic-message</i> ([dcl.pre])</ins>
      in a <code class="highlight"><c- n>nodiscard</c-></code> <em>attribute-argument-clause</em> should be used in the message of the warning as the rationale for why the result should not be discarded.
    </p>
   </blockquote>
   <h3 class="heading settled" data-level="6.5" id="cpp.cond"><span class="secno">6.5. </span><span class="content">15.2 Conditional inclusion [cpp.cond]</span><a class="self-link" href="#cpp.cond"></a></h3>
   <p>In [tab:cpp.cond.ha], modify the rows as indicated, and substituting <code class="highlight"><c- mi>20</c-><c- n>XXYYL</c-></code> by the date of adoption.</p>
   <table>
    <thead>
     <tr>
      <td>Attribute
      <td>Value
    <tbody>
     <tr>
      <td><code class="highlight"><c- n>deprecated</c-></code>
      <td>
       <del><code class="highlight"><c- mf>201309L</c-></code></del>
       <ins><code class="highlight"><c- mi>20</c-><c- n>XXYYL</c-></code></ins>
     <tr>
      <td><code class="highlight"><c- n>nodiscard</c-></code>
      <td>
       <del><code class="highlight"><c- mf>201907L</c-></code></del>
       <ins><code class="highlight"><c- mi>20</c-><c- n>XXYYL</c-></code></ins>
   </table>
   <h3 class="heading settled" data-level="6.6" id="cpp.predefined"><span class="secno">6.6. </span><span class="content">15.11 Predefined macro names [cpp.predefined]</span><a class="self-link" href="#cpp.predefined"></a></h3>
   <p>In [tab:cpp.predefined.ft], modify the rows as indicated, and substituting <code class="highlight"><c- mi>20</c-><c- n>XXYYL</c-></code> by the date of adoption.</p>
   <table>
    <thead>
     <tr>
      <td>Macro name
      <td>Value
    <tbody>
     <tr>
      <td><code class="highlight"><c- n>__cpp_deleted_function</c-></code>
      <td>
       <del><code class="highlight"><c- mf>202403L</c-></code></del>
       <ins><code class="highlight"><c- mi>20</c-><c- n>XXYYL</c-></code></ins>
   </table>
  </main>
<script>
(function() {
  "use strict";
  var collapseSidebarText = '<span aria-hidden="true">←</span> '
                          + '<span>Collapse Sidebar</span>';
  var expandSidebarText   = '<span aria-hidden="true">→</span> '
                          + '<span>Pop Out Sidebar</span>';
  var tocJumpText         = '<span aria-hidden="true">↑</span> '
                          + '<span>Jump to Table of Contents</span>';

  var sidebarMedia = window.matchMedia('screen and (min-width: 78em)');
  var autoToggle   = function(e){ toggleSidebar(e.matches) };
  if(sidebarMedia.addListener) {
    sidebarMedia.addListener(autoToggle);
  }

  function toggleSidebar(on) {
    if (on == undefined) {
      on = !document.body.classList.contains('toc-sidebar');
    }

    /* Don't scroll to compensate for the ToC if we're above it already. */
    var headY = 0;
    var head = document.querySelector('.head');
    if (head) {
      // terrible approx of "top of ToC"
      headY += head.offsetTop + head.offsetHeight;
    }
    var skipScroll = window.scrollY < headY;

    var toggle = document.getElementById('toc-toggle');
    var tocNav = document.getElementById('toc');
    if (on) {
      var tocHeight = tocNav.offsetHeight;
      document.body.classList.add('toc-sidebar');
      document.body.classList.remove('toc-inline');
      toggle.innerHTML = collapseSidebarText;
      if (!skipScroll) {
        window.scrollBy(0, 0 - tocHeight);
      }
      tocNav.focus();
      sidebarMedia.addListener(autoToggle); // auto-collapse when out of room
    }
    else {
      document.body.classList.add('toc-inline');
      document.body.classList.remove('toc-sidebar');
      toggle.innerHTML = expandSidebarText;
      if (!skipScroll) {
        window.scrollBy(0, tocNav.offsetHeight);
      }
      if (toggle.matches(':hover')) {
        /* Unfocus button when not using keyboard navigation,
           because I don't know where else to send the focus. */
        toggle.blur();
      }
    }
  }

  function createSidebarToggle() {
    /* Create the sidebar toggle in JS; it shouldn't exist when JS is off. */
    var toggle = document.createElement('a');
      /* This should probably be a button, but appearance isn't standards-track.*/
    toggle.id = 'toc-toggle';
    toggle.class = 'toc-toggle';
    toggle.href = '#toc';
    toggle.innerHTML = collapseSidebarText;

    sidebarMedia.addListener(autoToggle);
    var toggler = function(e) {
      e.preventDefault();
      sidebarMedia.removeListener(autoToggle); // persist explicit off states
      toggleSidebar();
      return false;
    }
    toggle.addEventListener('click', toggler, false);


    /* Get <nav id=toc-nav>, or make it if we don't have one. */
    var tocNav = document.getElementById('toc-nav');
    if (!tocNav) {
      tocNav = document.createElement('p');
      tocNav.id = 'toc-nav';
      /* Prepend for better keyboard navigation */
      document.body.insertBefore(tocNav, document.body.firstChild);
    }
    /* While we're at it, make sure we have a Jump to Toc link. */
    var tocJump = document.getElementById('toc-jump');
    if (!tocJump) {
      tocJump = document.createElement('a');
      tocJump.id = 'toc-jump';
      tocJump.href = '#toc';
      tocJump.innerHTML = tocJumpText;
      tocNav.appendChild(tocJump);
    }

    tocNav.appendChild(toggle);
  }

  var toc = document.getElementById('toc');
  if (toc) {
    createSidebarToggle();
    toggleSidebar(sidebarMedia.matches);

    /* If the sidebar has been manually opened and is currently overlaying the text
       (window too small for the MQ to add the margin to body),
       then auto-close the sidebar once you click on something in there. */
    toc.addEventListener('click', function(e) {
      if(e.target.tagName.toLowerCase() == "a" && document.body.classList.contains('toc-sidebar') && !sidebarMedia.matches) {
        toggleSidebar(false);
      }
    }, false);
  }
  else {
    console.warn("Can't find Table of Contents. Please use <nav id='toc'> around the ToC.");
  }

  /* Wrap tables in case they overflow */
  var tables = document.querySelectorAll(':not(.overlarge) > table.data, :not(.overlarge) > table.index');
  var numTables = tables.length;
  for (var i = 0; i < numTables; i++) {
    var table = tables[i];
    var wrapper = document.createElement('div');
    wrapper.className = 'overlarge';
    table.parentNode.insertBefore(wrapper, table);
    wrapper.appendChild(table);
  }

})();
</script>
  <h2 class="no-num no-ref heading settled" id="references"><span class="content">References</span><a class="self-link" href="#references"></a></h2>
  <h3 class="no-num no-ref heading settled" id="normative"><span class="content">Normative References</span><a class="self-link" href="#normative"></a></h3>
  <dl>
   <dt id="biblio-clang-implementation">[CLANG-IMPLEMENTATION]
   <dd>Yihe Li. <a href="https://github.com/Mick235711/llvm-project/tree/deleted-user-message"><cite>Mick235711's Clang Fork</cite></a>. URL: <a href="https://github.com/Mick235711/llvm-project/tree/deleted-user-message">https://github.com/Mick235711/llvm-project/tree/deleted-user-message</a>
   <dt id="biblio-n4988">[N4988]
   <dd>Thomas Köppe. <a href="https://wg21.link/n4988"><cite>Working Draft, Programming Languages — C++</cite></a>. 5 August 2024. URL: <a href="https://wg21.link/n4988">https://wg21.link/n4988</a>
   <dt id="biblio-p2741r3">[P2741R3]
   <dd>Corentin Jabot. <a href="https://wg21.link/p2741r3"><cite>user-generated static_assert messages</cite></a>. 16 June 2023. URL: <a href="https://wg21.link/p2741r3">https://wg21.link/p2741r3</a>
  </dl>
  <h3 class="no-num no-ref heading settled" id="informative"><span class="content">Informative References</span><a class="self-link" href="#informative"></a></h3>
  <dl>
   <dt id="biblio-cwg2518">[CWG2518]
   <dd>CWG. <a href="https://wg21.link/cwg2518"><cite>Conformance requirements and #error/#warning</cite></a>. 13 January 2022. C++23. URL: <a href="https://wg21.link/cwg2518">https://wg21.link/cwg2518</a>
   <dt id="biblio-n1720">[N1720]
   <dd>R. Klarer, J. Maddock, B. Dawes, H. Hinnant. <a href="https://wg21.link/n1720"><cite>Proposal to Add Static Assertions to the Core Language (Revision 3)</cite></a>. 20 October 2004. URL: <a href="https://wg21.link/n1720">https://wg21.link/n1720</a>
   <dt id="biblio-n3760">[N3760]
   <dd>Alberto Ganesh Barbati. <a href="https://wg21.link/n3760"><cite>[[deprecated]] attribute</cite></a>. 1 September 2013. URL: <a href="https://wg21.link/n3760">https://wg21.link/n3760</a>
   <dt id="biblio-n3928">[N3928]
   <dd>Walter E. Brown. <a href="https://wg21.link/n3928"><cite>Extending static_assert, v2</cite></a>. 14 February 2014. URL: <a href="https://wg21.link/n3928">https://wg21.link/n3928</a>
   <dt id="biblio-n4433">[N4433]
   <dd>Michael Price. <a href="https://wg21.link/n4433"><cite>Flexible static_assert messages</cite></a>. 9 April 2015. URL: <a href="https://wg21.link/n4433">https://wg21.link/n4433</a>
   <dt id="biblio-p1267r0">[P1267R0]
   <dd>Hana Dusíková, Bryce Adelstein Lelbach. <a href="https://wg21.link/p1267r0"><cite>Custom Constraint Diagnostics</cite></a>. 8 October 2018. URL: <a href="https://wg21.link/p1267r0">https://wg21.link/p1267r0</a>
   <dt id="biblio-p1301r4">[P1301R4]
   <dd>JeanHeyd Meneide, Isabella Muerte. <a href="https://wg21.link/p1301r4"><cite>[[nodiscard("should have a reason")]]</cite></a>. 5 August 2019. URL: <a href="https://wg21.link/p1301r4">https://wg21.link/p1301r4</a>
   <dt id="biblio-p1774r8">[P1774R8]
   <dd>Timur Doumler. <a href="https://wg21.link/p1774r8"><cite>Portable assumptions</cite></a>. 14 June 2022. URL: <a href="https://wg21.link/p1774r8">https://wg21.link/p1774r8</a>
   <dt id="biblio-p1887r1">[P1887R1]
   <dd>Corentin Jabot. <a href="https://wg21.link/p1887r1"><cite>Reflection on attributes</cite></a>. 13 January 2020. URL: <a href="https://wg21.link/p1887r1">https://wg21.link/p1887r1</a>
   <dt id="biblio-p2422r1">[P2422R1]
   <dd>Ville Voutilainen. <a href="https://wg21.link/p2422r1"><cite>Remove nodiscard annotations from the standard library specification</cite></a>. 28 June 2024. URL: <a href="https://wg21.link/p2422r1">https://wg21.link/p2422r1</a>
   <dt id="biblio-p2573r2">[P2573R2]
   <dd>Yihe Li. <a href="https://wg21.link/p2573r2"><cite>= delete("should have a reason");</cite></a>. 22 March 2024. URL: <a href="https://wg21.link/p2573r2">https://wg21.link/p2573r2</a>
   <dt id="biblio-p2593r1">[P2593R1]
   <dd>Barry Revzin. <a href="https://wg21.link/p2593r1"><cite>Allowing static_assert(false)</cite></a>. 20 January 2023. URL: <a href="https://wg21.link/p2593r1">https://wg21.link/p2593r1</a>
   <dt id="biblio-p2996r5">[P2996R5]
   <dd>Barry Revzin, Wyatt Childers, Peter Dimov, Andrew Sutton, Faisal Vali, Daveed Vandevoorde, Dan Katz. <a href="https://wg21.link/p2996r5"><cite>Reflection for C++26</cite></a>. 14 August 2024. URL: <a href="https://wg21.link/p2996r5">https://wg21.link/p2996r5</a>
   <dt id="biblio-p3094r3">[P3094R3]
   <dd>Mateusz Pusz. <a href="https://wg21.link/p3094r3"><cite>std::basic_fixed_string</cite></a>. 20240630. URL: <a href="https://wg21.link/p3094r3">https://wg21.link/p3094r3</a>
   <dt id="biblio-p3385r0">[P3385R0]
   <dd>Aurelien Cassagnes, Aurelien Cassagnes, Roman Khoroshikh, Anders Johansson. <a href="https://wg21.link/p3385r0"><cite>Attributes reflection</cite></a>. 16 September 2024. URL: <a href="https://wg21.link/p3385r0">https://wg21.link/p3385r0</a>
   <dt id="biblio-p3391r0">[P3391R0]
   <dd>Barry Revzin. <a href="https://wg21.link/p3391r0"><cite>constexpr std::format</cite></a>. 12 September 2024. URL: <a href="https://wg21.link/p3391r0">https://wg21.link/p3391r0</a>
  </dl>