<!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>P3279R0: CWG2463: What "trivially fooable" should mean</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://isocpp.org/favicon.ico" rel="icon">
  <meta content="dark light" name="color-scheme">
<style>
ins    {background-color: #CCFFCC; text-decoration: underline;}
del    {background-color: #FFCACA; text-decoration: line-through;}
p      {-moz-hyphens: none; -ms-hyphens: none; -webkit-hyphens: none; hyphens: none;}
</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">P3279R0<br>CWG2463: What "trivially fooable" should mean</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-05-15">2024-05-15</time></span></h2>
   <div data-fill-with="spec-metadata">
    <dl>
     <dt class="editor">Author:
     <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:arthur.j.odwyer@gmail.com">Arthur O'Dwyer</a>
     <dt>Audience:
     <dd>SG17
     <dt>Project:
     <dd>ISO/IEC 14882 Programming Languages — C++, ISO/IEC JTC1/SC22/WG21
    </dl>
   </div>
   <div data-fill-with="warning"></div>
   <hr title="Separator for header">
  </div>
  <div class="p-summary" data-fill-with="abstract">
   <h2 class="no-num no-toc no-ref heading settled" id="abstract"><span class="content">Abstract</span></h2>
   <p>The core-language specification of "trivially copyable," "trivially copy constructible," and "trivially copy assignable"
fail to match library-writers' expectations. In CWG2463, Core asked for a paper laying out the issues and proposing
a direction. This is such a paper.</p>
  </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="#changelog"><span class="secno">1</span> <span class="content">Changelog</span></a>
    <li>
     <a href="#intuition"><span class="secno">2</span> <span class="content">Three intuitions for TC</span></a>
     <ol class="toc">
      <li><a href="#intuition-lw"><span class="secno">2.1</span> <span class="content">Library-writer’s intuition</span></a>
      <li><a href="#intuition-cw"><span class="secno">2.2</span> <span class="content">Compiler-writer’s intuition</span></a>
      <li><a href="#intuition-ama"><span class="secno">2.3</span> <span class="content">Abstract-machine-lawyer’s intuition</span></a>
      <li><a href="#intuition-conclusion"><span class="secno">2.4</span> <span class="content">Bottom line</span></a>
     </ol>
    <li><a href="#status-quo"><span class="secno">3</span> <span class="content">Status quo</span></a>
    <li>
     <a href="#surprise"><span class="secno">4</span> <span class="content">Surprising behaviors</span></a>
     <ol class="toc">
      <li><a href="#surprise-cwg2463"><span class="secno">4.1</span> <span class="content">TC types can have non-TC members</span></a>
      <li><a href="#surprise-false-advertising"><span class="secno">4.2</span> <span class="content">Types can act non-trivially while publicly advertising TC</span></a>
      <li><a href="#surprise-leopard"><span class="secno">4.3</span> <span class="content">"Trivial" Rule-of-Five functions can act unlike memcpy</span></a>
     </ol>
    <li>
     <a href="#proposal"><span class="secno">5</span> <span class="content">Proposal</span></a>
     <ol class="toc">
      <li><a href="#conclusion"><span class="secno">5.1</span> <span class="content">Conclusion</span></a>
     </ol>
    <li><a href="#acknowledgments"><span class="secno">6</span> <span class="content">Acknowledgments</span></a>
    <li>
     <a href="#references"><span class="secno"></span> <span class="content">References</span></a>
     <ol class="toc">
      <li><a href="#informative"><span class="secno"></span> <span class="content">Informative References</span></a>
     </ol>
   </ol>
  </nav>
  <main>
   <h2 class="heading settled" data-level="1" id="changelog"><span class="secno">1. </span><span class="content">Changelog</span><a class="self-link" href="#changelog"></a></h2>
   <ul>
    <li data-md>
     <p>R0 (May 2024):</p>
     <ul>
      <li data-md>
       <p>Initial revision. See relevant minutes from <a href="https://wiki.edg.com/bin/view/Wg21kona2022/CoreWorkingGroup#A_2463._Trivial_copyability_and_unions_with_non_45trivial_members">Kona 2022</a>, <a href="https://wiki.edg.com/bin/view/Wg21issaquah2023/NotesEWGCWG2463">Issaquah 2023</a>.</p>
     </ul>
   </ul>
   <h2 class="heading settled" data-level="2" id="intuition"><span class="secno">2. </span><span class="content">Three intuitions for TC</span><a class="self-link" href="#intuition"></a></h2>
   <p>Different audiences think about trivial copyability (TC) in different ways.
Here are three points of view I’ve identified: the library-writer, the compiler-writer,
and the abstract-machine-lawyer.</p>
   <h3 class="heading settled" data-level="2.1" id="intuition-lw"><span class="secno">2.1. </span><span class="content">Library-writer’s intuition</span><a class="self-link" href="#intuition-lw"></a></h3>
   <p>The library-writer’s view is also shared by the trainer/instructor; it’s the view that you need
to have in order to understand most C++ codebases these days.</p>
   <blockquote>
    <p>When a type is trivially copyable, all of its Rule-of-Five operations can be lowered to simple <code class="highlight"><c- n>memcpy</c-></code>s.
Furthermore, its Rule-of-Five operations are non-throwing and have no visible side effects.</p>
   </blockquote>
   <p>This is the intuition by which every STL vendor writes things like this,
which assumes that assignment of TC types can always be lowered to <code class="highlight"><c- n>memcpy</c-></code>:</p>
<pre class="language-c++ highlight"><c- n>template</c-><c- o>&lt;</c-><c- n>class</c-> <c- n>T</c-><c- p>,</c-> <c- n>class</c-> <c- n>U</c-><c- o>></c->
<c- n>U</c-><c- o>*</c-> <c- n>std_copy</c-><c- p>(</c-><c- n>T</c-><c- o>*</c-> <c- n>first</c-><c- p>,</c-> <c- n>T</c-><c- o>*</c-> <c- n>last</c-><c- p>,</c-> <c- n>U</c-><c- o>*</c-> <c- n>dfirst</c-><c- p>)</c-> <c- p>{</c->
  <c- k>static_assert</c-><c- p>(</c-><c- n>is_assignable_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>&amp;</c-><c- p>,</c-> <c- n>U</c-><c- o>&amp;></c-><c- p>);</c->
  <c- k>if</c-> <c- n>constexpr</c-> <c- p>(</c-><c- n>same_as</c-><c- o>&lt;</c-><c- n>T</c-><c- p>,</c-> <c- n>U</c-><c- o>></c-> <c- o>&amp;&amp;</c-> <c- n>is_trivially_copyable_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>)</c-> <c- p>{</c->
    <c- n>memmove</c-><c- p>(</c-><c- n>dfirst</c-><c- p>,</c-> <c- n>first</c-><c- p>,</c-> <c- p>(</c-><c- n>last</c-> <c- o>-</c-> <c- n>first</c-><c- p>)</c-> <c- o>*</c-> <c- k>sizeof</c-><c- p>(</c-><c- n>T</c-><c- p>));</c->
    <c- k>return</c-> <c- n>dfirst</c-> <c- o>+</c-> <c- p>(</c-><c- n>last</c-> <c- o>-</c-> <c- n>first</c-><c- p>);</c->
  <c- p>}</c-> <c- k>else</c-> <c- p>{</c->
    <c- k>while</c-> <c- p>(</c-><c- n>first</c-> <c- o>!=</c-> <c- n>last</c-><c- p>)</c-> <c- o>*</c-><c- n>dfirst</c-><c- o>++</c-> <c- o>=</c-> <c- o>*</c-><c- n>first</c-><c- o>++</c-><c- p>;</c->
    <c- k>return</c-> <c- n>dfirst</c-><c- p>;</c->
  <c- p>}</c->
<c- p>}</c->
</pre>
   <p>And this, which assumes that assignment and construction can both be lowered:</p>
<pre class="language-c++ highlight"><c- n>template</c-><c- o>&lt;</c-><c- n>class</c-> <c- n>T</c-><c- o>></c->
<c- b>void</c-> <c- n>std_vector</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>::</c-><c- n>insert</c-><c- p>(</c-><c- n>std_vector</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>::</c-><c- n>const_iterator</c-> <c- n>it</c-><c- p>,</c-> <c- n>T</c-> <c- n>value</c-><c- p>)</c-> <c- p>{</c->
  <c- b>size_t</c-> <c- n>i</c-> <c- o>=</c-> <c- n>it</c-> <c- o>-</c-> <c- n>begin</c-><c- p>();</c->
  <c- n>ensure_capacity</c-><c- p>();</c->
  <c- k>if</c-> <c- n>constexpr</c-> <c- p>(</c-><c- n>is_trivially_copyable_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>)</c-> <c- p>{</c->
    <c- n>memmove</c-><c- p>(</c-><c- n>data</c-><c- p>()</c-> <c- o>+</c-> <c- n>i</c-> <c- o>+</c-> <c- mi>1</c-><c- p>,</c-> <c- n>data</c-><c- p>()</c-> <c- o>+</c-> <c- n>i</c-><c- p>,</c-> <c- n>size_</c-> <c- o>-</c-> <c- n>i</c-><c- p>);</c->
    <c- n>size_</c-> <c- o>+=</c-> <c- mi>1</c-><c- p>;</c->
  <c- p>}</c-> <c- k>else</c-> <c- p>{</c->
    <c- o>::</c-><c- n>new</c-> <c- p>(</c-><c- n>data</c-><c- p>()[</c-><c- n>size_</c-><c- p>])</c-> <c- n>T</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>data</c-><c- p>()[</c-><c- n>size_</c-> <c- o>-</c-> <c- mi>1</c-><c- p>]));</c->
    <c- n>size_</c-> <c- o>+=</c-> <c- mi>1</c-><c- p>;</c->
    <c- n>move</c-><c- p>(</c-><c- n>data</c-><c- p>()</c-> <c- o>+</c-> <c- n>i</c-><c- p>,</c-> <c- n>data</c-><c- p>()</c-> <c- o>+</c-> <c- n>size_</c-> <c- o>-</c-> <c- mi>1</c-><c- p>,</c-> <c- n>data</c-><c- p>()</c-> <c- o>+</c-> <c- n>i</c-> <c- o>+</c-> <c- mi>1</c-><c- p>);</c->
  <c- p>}</c->
  <c- n>data</c-><c- p>()[</c-><c- n>i</c-><c- p>]</c-> <c- o>=</c-> <c- n>value</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>A library might even assume that copying a TC type is "free" because it
cannot have visible side effects:</p>
<pre class="language-c++ highlight"><c- n>template</c-><c- o>&lt;</c-><c- n>class</c-> <c- n>T</c-><c- p>,</c-> <c- n>class</c-> <c- n>Compare</c-><c- o>></c->
<c- b>void</c-> <c- n>sort3</c-><c- p>(</c-><c- n>T</c-> <c- o>*</c-><c- n>x</c-><c- p>,</c-> <c- n>T</c-> <c- o>*</c-><c- n>y</c-><c- p>,</c-> <c- n>T</c-> <c- o>*</c-><c- n>z</c-><c- p>,</c-> <c- n>Compare</c-><c- o>&amp;</c-> <c- n>c</c-><c- p>)</c-> <c- p>{</c->
  <c- k>if</c-> <c- n>constexpr</c-> <c- p>(</c-><c- n>is_trivially_copyable_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;&amp;</c->
                <c- n>is_constructible_v</c-><c- o>&lt;</c-><c- n>T</c-><c- p>,</c-> <c- n>T</c-><c- o>&amp;></c-> <c- o>&amp;&amp;</c-> <c- n>is_assignable_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>&amp;</c-><c- p>,</c-> <c- n>T</c-><c- o>&amp;></c-><c- p>)</c-> <c- p>{</c->
    <c- c1>// cond swap</c->
    <c- b>bool</c-> <c- n>r</c-> <c- o>=</c-> <c- n>c</c-><c- p>(</c-><c- o>*</c-><c- n>z</c-><c- p>,</c-> <c- o>*</c-><c- n>y</c-><c- p>);</c->
    <c- n>T</c-> <c- n>tmp</c-> <c- o>=</c-> <c- n>r</c-> <c- o>?</c-> <c- o>*</c-><c- n>z</c-> <c- o>:</c-> <c- o>*</c-><c- n>y</c-><c- p>;</c->
    <c- o>*</c-><c- n>z</c-> <c- o>=</c-> <c- n>r</c-> <c- o>?</c-> <c- o>*</c-><c- n>y</c-> <c- o>:</c-> <c- o>*</c-><c- n>z</c-><c- p>;</c->
    <c- o>*</c-><c- n>y</c-> <c- o>=</c-> <c- n>tmp</c-><c- p>;</c->
    <c- c1>// partially sorted swap</c->
    <c- n>r</c-> <c- o>=</c-> <c- n>c</c-><c- p>(</c-><c- o>*</c-><c- n>z</c-><c- p>,</c-> <c- o>*</c-><c- n>x</c-><c- p>);</c->
    <c- n>tmp</c-> <c- o>=</c-> <c- n>r</c-> <c- o>?</c-> <c- o>*</c-><c- n>z</c-> <c- o>:</c-> <c- o>*</c-><c- n>x</c-><c- p>;</c->
    <c- o>*</c-><c- n>z</c-> <c- o>=</c-> <c- n>r</c-> <c- o>?</c-> <c- o>*</c-><c- n>x</c-> <c- o>:</c-> <c- o>*</c-><c- n>z</c-><c- p>;</c->
    <c- n>r</c-> <c- o>=</c-> <c- n>c</c-><c- p>(</c-><c- n>tmp</c-><c- p>,</c-> <c- o>*</c-><c- n>y</c-><c- p>);</c->
    <c- o>*</c-><c- n>x</c-> <c- o>=</c-> <c- n>r</c-> <c- o>?</c-> <c- o>*</c-><c- n>x</c-> <c- o>:</c-> <c- o>*</c-><c- n>y</c-><c- p>;</c->
    <c- o>*</c-><c- n>y</c-> <c- o>=</c-> <c- n>r</c-> <c- o>?</c-> <c- o>*</c-><c- n>y</c-> <c- o>:</c-> <c- n>tmp</c-><c- p>;</c->
  <c- p>}</c-> <c- k>else</c-> <c- p>{</c->
    <c- c1>// use swap alone, which is slower</c->
    <c- k>if</c-> <c- p>(</c-><c- n>c</c-><c- p>(</c-><c- o>*</c-><c- n>y</c-><c- p>,</c-> <c- o>*</c-><c- n>x</c-><c- p>))</c-> <c- p>{</c->
      <c- k>if</c-> <c- p>(</c-><c- n>c</c-><c- p>(</c-><c- o>*</c-><c- n>z</c-><c- p>,</c-> <c- o>*</c-><c- n>y</c-><c- p>))</c-> <c- p>{</c->
        <c- n>swap</c-><c- p>(</c-><c- o>*</c-><c- n>x</c-><c- p>,</c-> <c- o>*</c-><c- n>z</c-><c- p>);</c->
      <c- p>}</c-> <c- k>else</c-> <c- p>{</c->
        <c- n>swap</c-><c- p>(</c-><c- o>*</c-><c- n>x</c-><c- p>,</c-> <c- o>*</c-><c- n>y</c-><c- p>);</c->
        <c- k>if</c-> <c- p>(</c-><c- n>c</c-><c- p>(</c-><c- o>*</c-><c- n>z</c-><c- p>,</c-> <c- o>*</c-><c- n>y</c-><c- p>))</c-> <c- p>{</c->
          <c- n>swap</c-><c- p>(</c-><c- o>*</c-><c- n>y</c-><c- p>,</c-> <c- o>*</c-><c- n>z</c-><c- p>);</c->
        <c- p>}</c->
      <c- p>}</c->
    <c- p>}</c-> <c- k>else</c-> <c- k>if</c-> <c- p>(</c-><c- n>c</c-><c- p>(</c-><c- o>*</c-><c- n>z</c-><c- p>,</c-> <c- o>*</c-><c- n>y</c-><c- p>))</c-> <c- p>{</c->
      <c- n>swap</c-><c- p>(</c-><c- o>*</c-><c- n>y</c-><c- p>,</c-> <c- o>*</c-><c- n>z</c-><c- p>);</c->
      <c- k>if</c-> <c- p>(</c-><c- n>c</c-><c- p>(</c-><c- o>*</c-><c- n>y</c-><c- p>,</c-> <c- o>*</c-><c- n>x</c-><c- p>))</c-> <c- p>{</c->
        <c- n>swap</c-><c- p>(</c-><c- o>*</c-><c- n>x</c-><c- p>,</c-> <c- o>*</c-><c- n>y</c-><c- p>);</c->
      <c- p>}</c->
    <c- p>}</c->
  <c- p>}</c->
</pre>
   <p>The library-writer’s intuition is the most fruitful, because it leads to all these cool optimizations.
Unfortunately, we’ll see that each of these optimizations has corner cases today which are unsafe, because
the set of types actually considered TC by C++ includes some types for which these optimizations are unsafe.</p>
   <h3 class="heading settled" data-level="2.2" id="intuition-cw"><span class="secno">2.2. </span><span class="content">Compiler-writer’s intuition</span><a class="self-link" href="#intuition-cw"></a></h3>
   <p>The compiler-writer’s intuition is that all types start out "naturally" TC, and then get "made non-TC"
in various ways. For example, if we see that any of <code class="highlight"><c- n>T</c-></code>’s Rule-of-Five members are user-defined, we mark <code class="highlight"><c- n>T</c-></code> as non-TC.
If it has a subobject of non-TC type, we mark it non-TC. If it has a virtual base class, we mark it non-TC.
And so on.</p>
   <p>This paradigm is extremely easy to implement. It’s also powerful and general: the compiler-writer
can use the same technique to track "trivial relocatability," "trivial equality-comparability,"
"trivial value-initializability," etc.
Unfortunately, we’ll see that this paradigm doesn’t work perfectly without some tweaks, because
the set of types actually considered TC by C++ includes some types violating this paradigm.
(For example, a TC type <em>can</em> have a non-TC type as a data member.)</p>
   <h3 class="heading settled" data-level="2.3" id="intuition-ama"><span class="secno">2.3. </span><span class="content">Abstract-machine-lawyer’s intuition</span><a class="self-link" href="#intuition-ama"></a></h3>
   <p>Our previous two intuitions were driven by the physics of TC: what library operations can we do efficiently for TC types,
and how can we efficiently compute the TC-ness of a type inside the compiler.
The abstract-machine-lawyer’s intuition is not driven by physics, but by the circular logic of the Standard itself. <a href="https://eel.is/c++draft/basic.types#general-2">[basic.types.general]/2–3</a> says:</p>
   <p><small></small></p>
   <blockquote>
    <p></p>
    <small> <p>2. For any [complete object] of TC type <code class="highlight"><c- n>T</c-></code> [...]
the underlying bytes making up the object can be copied into an array of char[, and when]
that array is copied back into the object, the object shall subsequently hold its original value. </p><p>3. For two distinct [complete] objects <code class="highlight"><c- n>obj1</c-></code> and <code class="highlight"><c- n>obj2</c-></code> of TC type <code class="highlight"><c- n>T</c-></code>,
if the underlying bytes making up <code class="highlight"><c- n>obj1</c-></code> are copied into <code class="highlight"><c- n>obj2</c-></code>, <code class="highlight"><c- n>obj2</c-></code> shall subsequently hold the same value as <code class="highlight"><c- n>obj1</c-></code>. </p></small>
   </blockquote>
   <p>This means that (by some mystical process) you can use <code class="highlight"><c- n>memcpy</c-></code> to perform the same Platonic operation as assignment,
even when <code class="highlight"><c- n>T</c-></code> itself is not assignable. For example:</p>
<pre class="language-c++ highlight"><c- k>struct</c-> <c- nc>Stone</c-> <c- p>{</c->
  <c- b>int</c-> <c- n>i</c-><c- p>;</c->
  <c- n>Stone</c-><c- p>()</c-> <c- p>{}</c->
  <c- n>Stone</c-><c- p>(</c-><c- n>Stone</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
  <c- b>void</c-> <c- n>operator</c-><c- o>=</c-><c- p>(</c-><c- k>const</c-> <c- n>Stone</c-><c- o>&amp;</c-><c- p>)</c-> <c- o>=</c-> <c- n>delete</c-><c- p>;</c->
  <c- b>void</c-> <c- n>operator</c-><c- o>=</c-><c- p>(</c-><c- n>Stone</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- o>=</c-> <c- n>delete</c-><c- p>;</c->
  <c- o>~</c-><c- n>Stone</c-><c- p>()</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
<c- p>};</c->

<c- b>void</c-> <c- nf>via_assign</c-><c- p>(</c-><c- n>Stone</c-><c- o>&amp;</c-> <c- n>a</c-><c- p>,</c-> <c- n>Stone</c-><c- o>&amp;</c-> <c- n>b</c-><c- p>)</c-> <c- p>{</c->
  <c- n>a</c-> <c- o>=</c-> <c- n>b</c-><c- p>;</c->  <c- c1>// ill-formed</c->
<c- p>}</c->

<c- b>void</c-> <c- nf>via_memcpy</c-><c- p>(</c-><c- n>Stone</c-><c- o>&amp;</c-> <c- n>a</c-><c- p>,</c-> <c- n>Stone</c-><c- o>&amp;</c-> <c- n>b</c-><c- p>)</c-> <c- p>{</c->
  <c- n>std</c-><c- o>::</c-><c- n>memcpy</c-><c- p>(</c-><c- o>&amp;</c-><c- n>b</c-><c- p>,</c-> <c- o>&amp;</c-><c- n>a</c-><c- p>,</c-> <c- k>sizeof</c-><c- p>(</c-><c- n>Stone</c-><c- p>));</c->  <c- c1>// OK, b now holds the same value as a, by [basic.types.general]/3</c->
<c- p>}</c->
</pre>
   <p>Over the years, CWG participants have suggested different metaphysical explanations for how <code class="highlight"><c- n>memcpy</c-></code> does its job in such cases. For example, <code class="highlight"><c- n>memcpy</c-></code> could "observe" that <code class="highlight"><c- n>Stone</c-></code> is a TC type, and
decide to perform the abstract-machine operations</p>
<pre class="language-c++ highlight"><c- n>b</c-><c- p>.</c-><c- o>~</c-><c- n>Stone</c-><c- p>();</c->  <c- c1>// trivial</c->
<c- o>::</c-><c- n>new</c-> <c- p>(</c-><c- o>&amp;</c-><c- n>b</c-><c- p>)</c-> <c- n>Stone</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>a</c-><c- p>));</c-> <c- c1>// trivial</c->
</pre>
   <p>Moving-from <code class="highlight"><c- n>a</c-></code> doesn’t modify <code class="highlight"><c- n>a</c-></code>’s value, because its move constructor is trivial.</p>
   <p>The abstract-machine-lawyer doesn’t care about whether that trivial move-constructor is
selectable by overload resolution, whether it’s ambiguous, or private, or anything else;
it suffices for the abstract machine that we have sufficient non-deleted Rule-of-Five members
for the abstract machine’s <code class="highlight"><c- n>memcpy</c-></code> to <em>somehow</em> take us from one state to the other.</p>
   <p><a href="https://wiki.edg.com/bin/view/Wg21kona2022/CoreWorkingGroup#A_2463._Trivial_copyability_and_unions_with_non_45trivial_members">The minutes of CWG2463 discussion in Kona, November 2022</a> capture the abstract-machine-lawyer’s position perfectly:
"A class should be TC if there is a way [i.e., any way] to trivially copy or move it."</p>
   <p>Consider again our <code class="highlight"><c- n>vector</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>::</c-><c- n>insert</c-></code> from above, which in the library-writer’s mind
"uses <code class="highlight"><c- n>memmove</c-></code> to create an object." The abstract-machine-lawyer knows that what "really"
happens here is that <code class="highlight"><c- n>memmove</c-></code> implicitly creates an object (<a href="https://eel.is/c++draft/cstring.syn#3">[cstring.syn]/3</a>, <a href="https://eel.is/c++draft/intro.object#11">[intro.object]/11</a> so that when it copies the
bytes into that object, the new object will take on the proper value (<a href="https://eel.is/c++draft/basic.types#general-3">[basic.types.general]/3</a>).
The copying-of-bytes can still take place by destroying the implicitly created object
and reconstructing a new object; the implicitly created object is
"transparently replaceable" (<a href="https://eel.is/c++draft/basic.life#8">[basic.life]/8</a>)
by the new object.</p>
   <p>Now, if our TC type is not an implicit-lifetime type (<a href="https://eel.is/c++draft/class.prop#9">[class.prop]/9</a>),
i.e. it is TC but has no eligible trivial constructors, then the above logic doesn’t work;
but in that case we <em>must</em> have an eligible trivial copy- or move-assignment operator
(so <code class="highlight"><c- n>memcpy</c-></code> can do its job by simply calling that assignment operator).</p>
   <p>Unfortunately, as we’ll see below, today it is possible to create a TC type that is copy-constructible
without giving it an eligible copy constructor. Such a TC type can be put into a <code class="highlight"><c- n>vector</c-></code>,
and used with <code class="highlight"><c- n>vector</c-><c- o>::</c-><c- n>insert</c-></code>, even though it is not an implicit-lifetime type.
This will be a problem for the abstract-machine-lawyer’s intuition.</p>
   <h3 class="heading settled" data-level="2.4" id="intuition-conclusion"><span class="secno">2.4. </span><span class="content">Bottom line</span><a class="self-link" href="#intuition-conclusion"></a></h3>
   <p>There is a tension between the library-writer’s intuition and the abstract-machine-lawyer’s intuition.</p>
   <p>The library-writer wants C++ to report types as "TC" only if their Rule-of-Five operations
can be safely lowered to <code class="highlight"><c- n>memcpy</c-></code>. False positives are deadly. Basically, the "TC" label
tells the library-writer that shuffling bytes instead of objects <em>preserves all library-relevant value-semantic behavior.</em></p>
   <p>The abstract-machine-lawyer wants C++ to report types as "non-TC" only if it would
never make sense to <code class="highlight"><c- n>memcpy</c-></code> them at all, because today it is UB to <code class="highlight"><c- n>memcpy</c-></code> anything
unless it’s TC. Basically, the "TC" label is what permits legally shuffling bytes instead of objects <em>for any reason.</em></p>
   <p>The library-writer wants a strictly conservative "TC" label, with no false positives,
because each false positive means misbehavior at runtime.
(We’ll see some false positives below.)
The abstract-machine-lawyer tends to want a liberal "TC" label, with as few as possible false negatives,
because each false negative means a program that works correctly in practice, but formally has UB.</p>
   <h2 class="heading settled" data-level="3" id="status-quo"><span class="secno">3. </span><span class="content">Status quo</span><a class="self-link" href="#status-quo"></a></h2>
   <p>The Standard defines several kinds of "triviality." Let’s cover each of them quickly.</p>
   <p><b>1.</b> <code class="highlight"><c- n>is_trivial</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code> (<a href="https://eel.is/c++draft/class.prop#def:class,trivial">[class.prop]/2</a>, <a href="https://eel.is/c++draft/basic#def:type,trivial">[basic.types.general]/9</a>, <a href="https://eel.is/c++draft/meta#tab:meta.unary.prop">[meta.unary.prop]</a>).
This is just TC plus an eligible trivial default constructor.
It is not useful in practice (like <code class="highlight"><c- n>is_literal</c-></code>) and we’re getting rid of it via <a data-link-type="biblio" href="#biblio-p3247" title="Deprecate the notion of trivial types">[P3247]</a>. It doesn’t need to change.</p>
   <p><b>2.</b> <code class="highlight"><c- n>is_trivially_copyable</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code> (<a href="https://eel.is/c++draft/class.prop#1">[class.prop]/1</a>, <a href="https://eel.is/c++draft/basic#def:type,trivially_copyable">[basic.types.general]/9</a>, <a href="https://eel.is/c++draft/meta#tab:meta.unary.prop">[meta.unary.prop]</a>).</p>
   <p><small></small></p>
   <blockquote><small> A <em>trivially copyable class</em> is a class:<p></p> <ul><li data-md><p>that has at least one eligible copy constructor, move constructor, copy assignment operator, or move assignment operator,</p> </li><li data-md><p>where each eligible copy constructor, move constructor, copy assignment operator, and move assignment operator is trivial, and</p> </li><li data-md><p>that has a trivial, non-deleted destructor.</p> </li></ul> <p>Scalar types, trivially copyable class types, arrays of such types, and cv-qualified versions of these types
are collectively called <em>trivially copyable types.</em></p> </small></blockquote>
   <p><b>3.</b> <code class="highlight"><c- n>is_trivially_constructible</c-><c- o>&lt;</c-><c- n>T</c-><c- p>,</c-> <c- n>Args</c-><c- p>...</c-><c- o>></c-></code> (<a href="https://eel.is/c++draft/meta#tab:meta.unary.prop">[meta.unary.prop]</a>, <a href="https://eel.is/c++draft/meta#unary.prop-9">[meta.unary.prop]/9</a>) and <code class="highlight"><c- n>is_trivially_assignable</c-><c- o>&lt;</c-><c- n>T</c-><c- p>,</c-> <c- n>U</c-><c- o>></c-></code> (<a href="https://eel.is/c++draft/meta#tab:meta.unary.prop">[meta.unary.prop]</a>).</p>
   <p><small></small></p>
   <blockquote><small> [<code class="highlight"><c- n>is_trivially_constructible</c-><c- o>&lt;</c-><c- n>T</c-><c- p>,</c-> <c- n>Args</c-><c- p>...</c-><c- o>></c-></code> is true whenever]
the variable definition <code class="highlight"><c- n>T</c-> <c- nf>t</c-><c- p>(</c-><c- n>declval</c-><c- o>&lt;</c-><c- n>Args</c-><c- o>></c-><c- p>()...);</c-></code> is well-formed
and is known to call no operation that is not trivial.
Access checking is performed as if in a context unrelated to <code class="highlight"><c- n>T</c-></code> and any of the <code class="highlight"><c- n>Args</c-></code>.<p></p> <p>[<code class="highlight"><c- n>is_trivially_assignable</c-><c- o>&lt;</c-><c- n>T</c-><c- p>,</c-> <c- n>U</c-><c- o>></c-></code> is true whenever]
the expression <code class="highlight"><c- n>declval</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>()</c-> <c- o>=</c-> <c- n>declval</c-><c- o>&lt;</c-><c- n>U</c-><c- o>></c-><c- p>()</c-></code> is well-formed when treated as an unevaluated operand.
and is known to call no operation that is not trivial.
Access checking is performed as if in a context unrelated to <code class="highlight"><c- n>T</c-></code> and <code class="highlight"><c- n>U</c-></code>.</p> </small></blockquote>
   <p>Now, this wording depends on the definition of "trivial operation," which the Standard conspicuously fails to define.
In practice, compiler vendors treat every operation as trivial <em>unless</em> it is a function call, in which case it
is trivial if-and-only-if it calls a trivial special member function (as defined below).
Notably, <code class="highlight"><c- n>is_trivially_constructible</c-><c- o>&lt;</c-><c- b>int</c-><c- p>,</c-> <c- b>float</c-><c- o>></c-></code> and <code class="highlight"><c- n>is_trivially_constructible</c-><c- o>&lt;</c-><c- b>bool</c-><c- p>,</c-> <c- b>int</c-><c- o>></c-></code> are true
(because they do not call functions) despite not doing anything like a memcpy. Aggregate initialization is
also trivial:</p>
<pre class="language-c++ highlight"><c- k>struct</c-> <c- nc>Agg</c-> <c- p>{</c-> <c- b>int</c-> <c- n>i</c-><c- p>;</c-> <c- p>};</c->
<c- k>static_assert</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>is_trivially_constructible_v</c-><c- o>&lt;</c-><c- n>Agg</c-><c- p>,</c-> <c- b>int</c-><c- o>></c-><c- p>);</c->
<c- k>static_assert</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>is_trivially_constructible_v</c-><c- o>&lt;</c-><c- n>Agg</c-><c- p>,</c-> <c- b>float</c-><c- o>></c-><c- p>);</c->
</pre>
   <p class="note" role="note"><span class="marker">Note:</span> There is implementation divergence on lambda conversions, which are arguably "known" to the compiler
despite acting like user-defined conversion functions.
EDG+MSVC say that <code class="highlight"><c- n>is_trivially_constructible</c-><c- o>&lt;</c-><c- b>void</c-><c- p>(</c-><c- o>*</c-><c- p>)(),</c-> <c- k>decltype</c-><c- p>([]{})</c-><c- o>></c-></code> is true; Clang+GCC say false.
EDG+MSVC say that <code class="highlight"><c- n>is_trivially_assignable</c-><c- o>&lt;</c-><c- b>void</c-><c- p>(</c-><c- o>*&amp;</c-><c- p>)(),</c-> <c- k>decltype</c-><c- p>([]{})</c-><c- o>></c-></code> is true; Clang+GCC say false.</p>
   <p class="note" role="note"><span class="marker">Note:</span> There is implementation divergence on NSDMIs, which are arguably "known" to the compiler.
Given <code class="highlight"><c- k>struct</c-> <c- nc>X</c-> <c- p>{</c-> <c- b>int</c-> <c- n>a</c-><c- o>=</c-><c- mi>42</c-><c- p>;</c-> <c- p>}</c-></code> and <code class="highlight"><c- k>struct</c-> <c- nc>Q</c-> <c- p>{</c-> <c- n>X</c-> <c- n>a</c-><c- p>,</c-> <c- n>b</c-><c- p>;</c-> <c- p>}</c-></code>,
EDG+GCC+MSVC say that <code class="highlight"><c- n>is_trivially_constructible</c-><c- o>&lt;</c-><c- n>Q</c-><c- p>,</c-> <c- n>X</c-><c- o>></c-></code> is true; Clang says that it’s false.
(EDG keeps it true even when you change <code class="highlight"><c- mi>42</c-></code> to any arbitrary computation <code class="highlight"><c- n>f</c-><c- p>()</c-></code>; that’s likely accidental.) <br>Given <code class="highlight"><c- k>struct</c-> <c- nc>E</c-> <c- p>{}</c-></code> and <code class="highlight"><c- k>struct</c-> <c- nc>R</c-> <c- p>{</c-> <c- n>E</c-> <c- n>a</c-><c- p>;</c-> <c- b>int</c-> <c- n>b</c-><c- o>=</c-><c- mi>42</c-><c- p>;</c-> <c- p>}</c-></code>,
all vendors agree that <code class="highlight"><c- n>is_trivially_constructible</c-><c- o>&lt;</c-><c- n>R</c-><c- p>,</c-> <c- n>E</c-><c- o>></c-></code> is true. Yet <code class="highlight"><c- n>is_trivially_constructible</c-><c- o>&lt;</c-><c- n>R</c-><c- o>></c-></code> is false, because it calls a non-trivial default constructor
(<a href="https://eel.is/c++draft/class.mem#class.default.ctor-3">[class.default.ctor]/3</a>).</p>
   <p class="note" role="note"><span class="marker">Note:</span> There is likely-accidental implementation divergence on aggregate initialization from
multiple arguments.
Given <code class="highlight"><c- k>struct</c-> <c- nc>P</c-> <c- p>{</c-> <c- b>int</c-> <c- n>a</c-><c- p>,</c-> <c- n>b</c-><c- p>;</c-> <c- p>}</c-></code>,
EDG says that <code class="highlight"><c- n>is_trivially_constructible</c-><c- o>&lt;</c-><c- n>P</c-><c- p>,</c-> <c- b>int</c-><c- p>,</c-> <c- b>int</c-><c- o>></c-></code> is false; Clang+GCC+MSVC say true.
We propose to deprecate the three-argument type trait, anyway.</p>
   <p><b>5.</b> A special member function is <em>trivial</em> in specific circumstances
(<a href="https://eel.is/c++draft/class.mem#class.default.ctor-3">[class.default.ctor]/3</a>, <a href="https://eel.is/c++draft/class.mem#class.copy.ctor-11">[class.copy.ctor]/11</a>, <a href="https://eel.is/c++draft/class.mem#class.copy.assign-9">[class.copy.assign]/9</a>, <a href="https://eel.is/c++draft/class.mem#class.dtor-8">[class.dtor]/8</a>).</p>
   <p><small></small></p>
   <blockquote><small> A default constructor is <em>trivial</em> if it is not user-provided and if:<p></p> <ul><li data-md><p>its class has no virtual functions and no virtual base classes, and</p> </li><li data-md><p>no non-static data member of its class has a default member initializer, and</p> </li><li data-md><p>all the direct base classes of its class have trivial default constructors, and</p> </li><li data-md><p>for all the non-static data members of its class that are of class type (or array thereof),
each such class has a trivial default constructor.</p> </li></ul> <p>A copy/move constructor for class <code class="highlight"><c- n>X</c-></code> is <em>trivial</em> if it is not user-provided and if:</p> <ul><li data-md><p>class <code class="highlight"><c- n>X</c-></code> has no virtual functions and no virtual base classes, and</p> </li><li data-md><p>the constructor selected to copy/move each direct base class subobject is trivial, and</p> </li><li data-md><p>for each non-static data member of <code class="highlight"><c- n>X</c-></code> that is of class type (or array thereof),
the constructor selected to copy/move that member is trivial.</p> </li></ul> <p>A copy/move assignment operator for class <code class="highlight"><c- n>X</c-></code> is <em>trivial</em> if it is not user-provided and if:</p> <ul><li data-md><p>class <code class="highlight"><c- n>X</c-></code> has no virtual functions and no virtual base classes, and</p> </li><li data-md><p>the assignment operator selected to copy/move each direct base class subobject is trivial, and</p> </li><li data-md><p>for each non-static data member of <code class="highlight"><c- n>X</c-></code> that is of class type (or array thereof), the assignment
operator selected to copy/move that member is trivial.</p> </li></ul> <p>A destructor is <em>trivial</em> if it is not user-provided and if:</p> <ul><li data-md><p>the destructor is not virtual,</p> </li><li data-md><p>all of the direct base classes of its class have trivial destructors, and</p> </li><li data-md><p>for all of the non-static data members of its class that are of class type (or array thereof),
each such class has a trivial destructor.</p> </li></ul> </small></blockquote>
   <p class="note" role="note"><span class="marker">Note:</span> [class.default.ctor] conspicuously doesn’t require that "the constructor selected to initialize
that member is trivial"; it simply requires that each base and member have a (possibly ineligible)
trivial default constructor. Naturally, there is implementation divergence here (<a href="https://godbolt.org/z/1sYo5z8xq">Godbolt</a>).
EDG seems to follow the letter of the law; Clang+GCC+MSVC hew closer to the library-writer’s intuition.</p>
   <p>Notice that <code class="highlight"><c- n>is_trivially_constructible</c-></code>, <code class="highlight"><c- n>is_trivially_assignable</c-></code>, [class.copy.ctor], and [class.copy.assign]
check the results of overload resolution,
i.e., they are friendly to the library-writer’s intuition that what matters is not what <em>special member functions</em> happen to be defined, but which (possibly non-special) functions are actually called by overload resolution for
a given C++ expression. Vice versa, <code class="highlight"><c- n>is_trivially_copyable</c-></code> and [class.default.ctor] are hostile to the
library-writer’s intuition; they are defined only in terms of special member functions, ignoring overload resolution.</p>
   <p>Two more critical things to keep in mind for the following examples:</p>
   <ul>
    <li data-md>
     <p>A copy constructor, copy assignment operator, etc, is never a template. So you can have a poorly-matching
trivial copy constructor living alongside a non-trivial constructor template that is a better match;
yet this will not cause <code class="highlight"><c- n>is_trivially_copyable</c-></code> to become false, because a constructor template
is not a copy constructor. All of your copy constructors remain trivial.</p>
    <li data-md>
     <p>The rule for calling a special member function "trivial" is context-independent. Once trivial, always trivial.
So if you inherit a member function from your base class, it will continue to "be trivial" for you,
just like it was trivial for your base class.</p>
   </ul>
   <h2 class="heading settled" data-level="4" id="surprise"><span class="secno">4. </span><span class="content">Surprising behaviors</span><a class="self-link" href="#surprise"></a></h2>
   <h3 class="heading settled" data-level="4.1" id="surprise-cwg2463"><span class="secno">4.1. </span><span class="content">TC types can have non-TC members</span><a class="self-link" href="#surprise-cwg2463"></a></h3>
   <p>This is <a data-link-type="biblio" href="#biblio-cwg2463" title="Trivial copyability and unions with non-trivial members">[CWG2463]</a> (<a href="https://godbolt.org/z/jhaEd6YYY">Godbolt</a>):</p>
<pre class="language-c++ highlight"><c- k>struct</c-> <c- nc>Hamlet</c-> <c- p>{</c->
  <c- n>Hamlet</c-><c- p>(</c-><c- k>const</c-> <c- n>Hamlet</c-><c- o>&amp;</c-><c- p>)</c-> <c- p>{</c-> <c- n>puts</c-><c- p>(</c-><c- s>"copied"</c-><c- p>);</c-> <c- p>}</c->
  <c- n>Hamlet</c-><c- p>(</c-><c- n>Hamlet</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
  <c- n>Hamlet</c-><c- o>&amp;</c-> <c- n>operator</c-><c- o>=</c-><c- p>(</c-><c- n>Hamlet</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
<c- p>};</c->
<c- k>struct</c-> <c- nc>Nutshell</c-> <c- p>{</c->
  <c- n>Hamlet</c-> <c- n>h_</c-><c- p>;</c->
  <c- n>Nutshell</c-><c- p>(</c-><c- n>Nutshell</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
  <c- n>Nutshell</c-><c- o>&amp;</c-> <c- n>operator</c-><c- o>=</c-><c- p>(</c-><c- n>Nutshell</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
<c- p>};</c->
<c- k>static_assert</c-><c- p>(</c-><c- o>!</c-><c- n>std</c-><c- o>::</c-><c- n>is_trivially_copyable_v</c-><c- o>&lt;</c-><c- n>Hamlet</c-><c- o>></c-><c- p>);</c->
<c- k>static_assert</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>is_trivially_copyable_v</c-><c- o>&lt;</c-><c- n>Nutshell</c-><c- o>></c-><c- p>);</c->
</pre>
   <p class="note" role="note"><span class="marker">Note:</span> There is implementation divergence. EDG+MSVC say <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>is_trivially_copyable</c-><c- o>&lt;</c-><c- n>Nutshell</c-><c- o>></c-></code> is true; Clang+GCC say false.
EDG+MSVC are certainly correct according to the Standard.</p>
   <p>To paraphrase Daveed Vandevoorde’s comment on that issue:
"It is unclear why a complete object of type <code class="highlight"><c- n>Hamlet</c-></code> cannot be memcpyed but such an object can be memcpyed when embedded in a <code class="highlight"><c- n>Nutshell</c-></code>."
That is, this example is problematic to the abstract-machine-lawyer intuition that TC-ness ought to follow the <em>definedness</em> of <code class="highlight"><c- n>memcpy</c-></code>.
It doesn’t really make sense to say that <code class="highlight"><c- n>memcpy</c-></code> is capable of transferring the value of a <code class="highlight"><c- n>Hamlet</c-></code> object only
when it’s a subobject of a <code class="highlight"><c- n>Nutshell</c-></code> and not otherwise.</p>
   <p>But to the library-writer intuition, this example is perfectly sane: TC means "all provided operations are tantamount to <code class="highlight"><c- n>memcpy</c-></code>,"
which is clearly untrue of <code class="highlight"><c- n>Hamlet</c-></code> and clearly true of <code class="highlight"><c- n>Nutshell</c-></code> — because <code class="highlight"><c- n>Nutshell</c-></code> provides fewer operations. <code class="highlight"><c- n>Nutshell</c-></code> snips away <code class="highlight"><c- n>Hamlet</c-></code>’s non-trivial copy constructor, so that all the remaining operations are in fact trivial.
We need <code class="highlight"><c- n>Hamlet</c-></code> to remain non-TC so that we don’t misoptimize <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>uninitialized_copy</c-><c- p>(</c-><c- n>Hamlet</c-><c- p>)</c-></code>; but we are
happy for <code class="highlight"><c- n>Nutshell</c-></code> to be TC so that we can optimize <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>uninitialized_move</c-><c- p>(</c-><c- n>Nutshell</c-><c- p>)</c-></code>. We aren’t worried about misoptimizing <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>uninitialized_copy</c-><c- p>(</c-><c- n>Nutshell</c-><c- p>)</c-></code> because that’s already ill-formed diagnostic required.</p>
   <p>Finally, this example is problematic for the compiler-writer intuition. We want to be able to track a single bit, "<code class="highlight"><c- n>Hamlet</c-></code> is non-TC,"
and propagate that down into <code class="highlight"><c- n>Nutshell</c-></code>. But this example shows that we must track <em>exactly why</em> <code class="highlight"><c- n>Hamlet</c-></code> is non-TC!
This <code class="highlight"><c- n>Hamlet2</c-></code> differs only in that it has a non-trivial move-assignment operator (<a href="https://godbolt.org/z/a86Kd1Y73">Godbolt</a>):</p>
<pre class="language-c++ highlight"><c- k>struct</c-> <c- nc>Hamlet2</c-> <c- p>{</c->
  <c- n>Hamlet2</c-><c- p>(</c-><c- k>const</c-> <c- n>Hamlet2</c-><c- o>&amp;</c-><c- p>)</c-> <c- p>{</c-> <c- n>puts</c-><c- p>(</c-><c- s>"copied"</c-><c- p>);</c-> <c- p>}</c->
  <c- n>Hamlet2</c-><c- p>(</c-><c- n>Hamlet2</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
  <c- n>Hamlet2</c-><c- o>&amp;</c-> <c- n>operator</c-><c- o>=</c-><c- p>(</c-><c- n>Hamlet2</c-><c- o>&amp;&amp;</c-><c- p>);</c-> <c- c1>// not defaulted</c->
<c- p>};</c->
<c- k>struct</c-> <c- nc>Nutshell</c-> <c- p>{</c->
  <c- n>Hamlet2</c-> <c- n>h_</c-><c- p>;</c->
  <c- n>Nutshell</c-><c- p>(</c-><c- n>Nutshell</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
  <c- n>Nutshell</c-><c- o>&amp;</c-> <c- n>operator</c-><c- o>=</c-><c- p>(</c-><c- n>Nutshell</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
<c- p>};</c->
<c- k>static_assert</c-><c- p>(</c-><c- o>!</c-><c- n>std</c-><c- o>::</c-><c- n>is_trivially_copyable_v</c-><c- o>&lt;</c-><c- n>Hamlet2</c-><c- o>></c-><c- p>);</c->
<c- k>static_assert</c-><c- p>(</c-><c- o>!</c-><c- n>std</c-><c- o>::</c-><c- n>is_trivially_copyable_v</c-><c- o>&lt;</c-><c- n>Nutshell</c-><c- o>></c-><c- p>);</c->
</pre>
   <p>Non-TC <code class="highlight"><c- n>Hamlet</c-></code> embedded in a <code class="highlight"><c- n>Nutshell</c-></code> becomes TC; non-TC <code class="highlight"><c- n>Hamlet2</c-></code> embedded in the same <code class="highlight"><c- n>Nutshell</c-></code> stubbornly remains non-TC.
So it’s not the TC-ness of <code class="highlight"><c- n>Hamlet</c-></code> that matters; it’s something else — something that takes more than one bit to represent
in the compiler.</p>
   <h3 class="heading settled" data-level="4.2" id="surprise-false-advertising"><span class="secno">4.2. </span><span class="content">Types can act non-trivially while publicly advertising TC</span><a class="self-link" href="#surprise-false-advertising"></a></h3>
   <p>Microsoft STL’s <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>pair</c-><c- o>&lt;</c-><c- b>int</c-><c- o>&amp;</c-><c- p>,</c-> <c- b>int</c-><c- o>&amp;></c-></code> advertises itself as TC, despite not modeling trivial copyability.
To falsely advertise yourself as TC, recall that there are several possible signatures for a "copy assignment operator,"
and user-declaring any such signature (even an out-of-the-way one, even deleted) suffices to keep the compiler
from implicitly generating any defaulted <code class="highlight"><c- k>operator</c-><c- o>=</c-></code> for your class. Meanwhile, you provide assignment from <code class="highlight"><c- k>const</c-> <c- n>Plum</c-><c- o>&amp;</c-></code> via a template (recall that the compiler never considers a template to be a Rule-of-Five special
member). <a href="https://godbolt.org/z/Mo95zjTsc">Godbolt</a>:</p>
<pre class="language-c++ highlight"><c- k>struct</c-> <c- nc>Plum</c-> <c- p>{</c->
  <c- b>int</c-> <c- o>*</c-><c- n>ptr_</c-><c- p>;</c->
  <c- n>explicit</c-> <c- nf>Plum</c-><c- p>(</c-><c- b>int</c-><c- o>&amp;</c-> <c- n>i</c-><c- p>)</c-> <c- o>:</c-> <c- n>ptr_</c-><c- p>(</c-><c- o>&amp;</c-><c- n>i</c-><c- p>)</c-> <c- p>{}</c->
  <c- n>Plum</c-><c- p>(</c-><c- k>const</c-> <c- n>Plum</c-><c- o>&amp;</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
  <c- b>void</c-> <c- n>operator</c-><c- o>=</c-><c- p>(</c-><c- k>const</c-> <c- k>volatile</c-> <c- n>Plum</c-><c- o>&amp;</c-><c- p>)</c-> <c- o>=</c-> <c- n>delete</c-><c- p>;</c->
  <c- n>template</c-><c- o>&lt;</c-><c- n>class</c-><c- o>=</c-><c- b>void</c-><c- o>></c-> <c- b>void</c-> <c- n>operator</c-><c- o>=</c-><c- p>(</c-><c- k>const</c-> <c- n>Plum</c-><c- o>&amp;</c-> <c- n>rhs</c-><c- p>)</c-> <c- p>{</c->
    <c- o>*</c-><c- n>ptr_</c-> <c- o>=</c-> <c- o>*</c-><c- n>rhs</c-><c- p>.</c-><c- n>ptr_</c-><c- p>;</c->
  <c- p>}</c->
<c- p>};</c->
<c- k>static_assert</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>is_trivially_copyable_v</c-><c- o>&lt;</c-><c- n>Plum</c-><c- o>></c-><c- p>);</c->
<c- k>static_assert</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>is_assignable_v</c-><c- o>&lt;</c-><c- n>Plum</c-><c- o>&amp;</c-><c- p>,</c-> <c- k>const</c-> <c- n>Plum</c-><c- o>&amp;></c-><c- p>);</c->
<c- k>static_assert</c-><c- p>(</c-><c- o>!</c-><c- n>std</c-><c- o>::</c-><c- n>is_trivially_assignable_v</c-><c- o>&lt;</c-><c- n>Plum</c-><c- o>&amp;</c-><c- p>,</c-> <c- k>const</c-> <c- n>Plum</c-><c- o>&amp;></c-><c- p>);</c->
</pre>
   <p>Microsoft STL’s <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>reverse_copy</c-></code> will see that <code class="highlight"><c- n>Plum</c-></code> is trivially copyable and assume (following the library-writer’s
intuition) that it can be lowered to <code class="highlight"><c- n>memcpy</c-></code>. So <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>reverse_copy</c-><c- p>(</c-><c- n>Plum</c-><c- p>)</c-></code> is miscompiled. (By luck, <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>reverse_copy</c-><c- p>(</c-><c- n>pair</c-><c- p>)</c-></code> is
miscompiled only on 32-bit platforms, because Microsoft’s <code class="highlight"><c- n>reverse_copy</c-></code> optimization is also gated on <code class="highlight"><c- k>sizeof</c-><c- p>(</c-><c- n>T</c-><c- p>)</c-> <c- o>&lt;=</c-> <c- mi>8</c-></code>.)
libstdc++ will miscompile <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>copy</c-><c- p>(</c-><c- n>Plum</c-><c- p>)</c-></code> (<a href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114817">bug #114817</a>)
and several other algorithms.</p>
   <p>This example isn’t problematic for the compiler-writer nor the abstract-machine-lawyer. But it is shocking to
everyone’s intuition because it shows that we can easily use corner cases in the wording to decouple the
"advertised" TC-ness of a type from its "proper" semantic TC-ness. (See <a data-link-type="biblio" href="#biblio-mller" title="Trivially copyable does not mean trivially copy constructible">[Müller]</a> and <a data-link-type="biblio" href="#biblio-odwyer" title="Types that falsely advertise trivial copyability">[ODwyer]</a>.)</p>
   <p>Show this example to the library-writer and when they recover from the shock they’ll say:
"Okay, so we shouldn’t gate our <code class="highlight"><c- n>copy</c-></code> and <code class="highlight"><c- n>reverse_copy</c-></code> optimizations on TC. We’ll gate them on
the more granular <code class="highlight"><c- n>is_trivially_copy_assignable</c-></code> trait, instead." The next section shows how that
gate, also, is broken.</p>
   <h3 class="heading settled" data-level="4.3" id="surprise-leopard"><span class="secno">4.3. </span><span class="content">"Trivial" Rule-of-Five functions can act unlike memcpy</span><a class="self-link" href="#surprise-leopard"></a></h3>
   <p>The rule for calling a special member function "trivial" lacks context. Once trivial, always trivial.
So if you inherit a member function from your base class, it will continue to "be trivial" for you,
just like it was trivial for your base class. This allows us to make class <code class="highlight"><c- n>Leopard</c-></code> which never
changes its <code class="highlight"><c- n>spots_</c-></code> — and yet, the type-traits report that everything about it is trivial
(<a href="https://godbolt.org/z/GGP4e7Wqz">Godbolt</a>):</p>
<pre class="language-c++ highlight"><c- k>struct</c-> <c- nc>Cat</c-> <c- p>{};</c->
<c- k>struct</c-> <c- nc>Leopard</c-> <c- o>:</c-> <c- n>Cat</c-> <c- p>{</c->
    <c- b>int</c-> <c- n>spots_</c-><c- p>;</c->
    <c- n>Leopard</c-><c- o>&amp;</c-> <c- n>operator</c-><c- o>=</c-><c- p>(</c-><c- n>Leopard</c-><c- o>&amp;</c-><c- p>)</c-> <c- o>=</c-> <c- n>delete</c-><c- p>;</c->
    <c- n>using</c-> <c- n>Cat</c-><c- o>::</c-><c- n>operator</c-><c- o>=</c-><c- p>;</c->
<c- p>};</c->
<c- k>static_assert</c-><c- p>(</c-><c- n>is_trivially_copyable_v</c-><c- o>&lt;</c-><c- n>Leopard</c-><c- o>></c-><c- p>);</c->
<c- k>static_assert</c-><c- p>(</c-><c- n>is_trivially_assignable_v</c-><c- o>&lt;</c-><c- n>Leopard</c-><c- o>&amp;</c-><c- p>,</c-> <c- k>const</c-> <c- n>Leopard</c-><c- o>&amp;></c-><c- p>);</c->

<c- b>void</c-> <c- nf>test</c-><c- p>(</c-><c- n>Leopard</c-><c- o>&amp;</c-> <c- n>a</c-><c- p>,</c-> <c- k>const</c-> <c- n>Leopard</c-><c- o>&amp;</c-> <c- n>b</c-><c- p>)</c-> <c- p>{</c->
  <c- n>a</c-> <c- o>=</c-> <c- n>b</c-><c- p>;</c-> <c- c1>// absolutely no data is copied</c->
<c- p>}</c->
</pre>
   <p>This is supremely problematic for the library-writer. Every STL vendor miscompiles <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>copy</c-><c- p>(</c-><c- n>Leopard</c-><c- p>)</c-></code> —​they assume that because <code class="highlight"><c- n>is_trivially_copy_assignable_v</c-><c- o>&lt;</c-><c- n>Leopard</c-><c- o>></c-></code>, therefore copying a contiguous range
of <code class="highlight"><c- n>Leopard</c-></code> can be lowered to <code class="highlight"><c- n>memmove</c-></code>. But in fact that’s wrong.</p>
   <p>I see no way to fix everybody’s <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>copy</c-><c- p>(</c-><c- n>Leopard</c-><c- p>)</c-></code> on the library side. The only way forward
is to fix the definition of triviality in the core language.</p>
   <h2 class="heading settled" data-level="5" id="proposal"><span class="secno">5. </span><span class="content">Proposal</span><a class="self-link" href="#proposal"></a></h2>
   <p>Basically, we propose to respecify all of the traits to conform with the library-writer’s intuition.
(For each case below, read "can be" as "is known to the compiler to be able to be".)</p>
   <ul>
    <li data-md>
     <p><code class="highlight"><c- n>is_trivially_constructible</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code> should mean precisely that constructing a <code class="highlight"><c- n>T</c-></code> from no arguments
can be lowered to a no-op. (This is basically the status quo in practice.)</p>
    <li data-md>
     <p><code class="highlight"><c- n>is_trivially_constructible</c-><c- o>&lt;</c-><c- n>To</c-><c- p>,</c-> <c- n>From</c-><c- o>></c-></code> should mean precisely that constructing a (complete) <code class="highlight"><c- n>To</c-></code> from a <code class="highlight"><c- n>From</c-></code> can be lowered to memcpy. (E.g. <code class="highlight"><c- n>is_trivially_constructible</c-><c- o>&lt;</c-><c- b>float</c-><c- p>,</c-> <c- b>int</c-><c- o>></c-></code> should become false; but <code class="highlight"><c- n>is_trivially_copy_constructible</c-><c- o>&lt;</c-><c- n>Polymorphic</c-><c- o>></c-></code> should become frequently true.)</p>
    <li data-md>
     <p><code class="highlight"><c- n>is_trivially_constructible</c-><c- o>&lt;</c-><c- n>To</c-><c- p>,</c-> <c- n>Args</c-><c- p>...</c-><c- o>></c-></code> for any number of <code class="highlight"><c- n>Args</c-><c- p>...</c-></code> greater than 1 should be invariably false,
and we should deprecate it. That trait is useless because it corresponds to nothing physical.</p>
    <li data-md>
     <p><code class="highlight"><c- n>is_trivially_destructible</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code> should mean precisely that destroying a <code class="highlight"><c- n>T</c-></code> can be lowered to a no-op.
(This is the status quo in practice.)</p>
    <li data-md>
     <p><code class="highlight"><c- n>is_trivially_assignable</c-><c- o>&lt;</c-><c- n>To</c-><c- p>,</c-> <c- n>From</c-><c- o>></c-></code> should mean precisely that assigning a (complete) <code class="highlight"><c- n>To</c-></code> from a <code class="highlight"><c- n>From</c-></code> can be lowered to memcpy. (E.g. <code class="highlight"><c- n>is_trivially_assignable</c-><c- o>&lt;</c-><c- b>float</c-><c- o>&amp;</c-><c- p>,</c-> <c- b>int</c-><c- o>&amp;></c-></code> should become false.)</p>
    <li data-md>
     <p><code class="highlight"><c- n>is_trivially_copyable</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code> should mean that all the Rule-of-Five operations that <code class="highlight"><c- n>T</c-></code> supports,
no matter the cvref-qualification of the arguments, can be lowered to memcpy. That is,
it should mean exactly:</p>
   </ul>
   <p><small></small></p>
   <small> <pre class="language-c++ highlight"><c- n>constexpr</c-> <c- b>bool</c-> <c- n>implies</c-><c- p>(</c-><c- b>bool</c-> <c- n>a</c-><c- p>,</c-> <c- b>bool</c-> <c- n>b</c-><c- p>)</c-> <c- p>{</c-> <c- k>return</c-> <c- n>b</c-> <c- o>||</c-> <c- o>!</c-><c- n>a</c-><c- p>;</c-> <c- p>}</c->
<c- n>template</c-><c- o>&lt;</c-><c- n>class</c-> <c- n>T</c-><c- o>></c->
<c- kr>inline</c-> <c- n>constexpr</c-> <c- b>bool</c-> <c- n>is_trivially_copyable_v</c-> <c- o>=</c-> 
  <c- n>implies</c-><c- p>(</c-><c- n>is_constructible_v</c-><c- o>&lt;</c-><c- n>T</c-><c- p>,</c-> <c- n>T</c-><c- o>&amp;></c-><c- p>,</c->        <c- n>is_trivially_constructible_v</c-><c- o>&lt;</c-><c- n>T</c-><c- p>,</c-> <c- n>T</c-><c- o>&amp;></c-><c- p>)</c-> <c- o>&amp;&amp;</c->
  <c- n>implies</c-><c- p>(</c-><c- n>is_constructible_v</c-><c- o>&lt;</c-><c- n>T</c-><c- p>,</c-> <c- n>T</c-><c- o>&amp;&amp;></c-><c- p>,</c->       <c- n>is_trivially_constructible_v</c-><c- o>&lt;</c-><c- n>T</c-><c- p>,</c-> <c- n>T</c-><c- o>&amp;&amp;></c-><c- p>)</c-> <c- o>&amp;&amp;</c->
  <c- n>implies</c-><c- p>(</c-><c- n>is_constructible_v</c-><c- o>&lt;</c-><c- n>T</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;></c-><c- p>,</c->  <c- n>is_trivially_constructible_v</c-><c- o>&lt;</c-><c- n>T</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;></c-><c- p>)</c-> <c- o>&amp;&amp;</c->
  <c- n>implies</c-><c- p>(</c-><c- n>is_constructible_v</c-><c- o>&lt;</c-><c- n>T</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;&amp;></c-><c- p>,</c-> <c- n>is_trivially_constructible_v</c-><c- o>&lt;</c-><c- n>T</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;&amp;></c-><c- p>)</c-> <c- o>&amp;&amp;</c->
  <c- n>implies</c-><c- p>(</c-><c- n>is_assignable_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>&amp;</c-><c- p>,</c-> <c- n>T</c-><c- o>&amp;></c-><c- p>,</c->          <c- n>is_trivially_assignable_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>&amp;</c-><c- p>,</c-> <c- n>T</c-><c- o>&amp;></c-><c- p>)</c-> <c- o>&amp;&amp;</c->
  <c- n>implies</c-><c- p>(</c-><c- n>is_assignable_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>&amp;</c-><c- p>,</c-> <c- n>T</c-><c- o>&amp;&amp;></c-><c- p>,</c->         <c- n>is_trivially_assignable_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>&amp;</c-><c- p>,</c-> <c- n>T</c-><c- o>&amp;&amp;></c-><c- p>)</c-> <c- o>&amp;&amp;</c->
  <c- n>implies</c-><c- p>(</c-><c- n>is_assignable_v</c-><c- o>&lt;</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- n>is_trivially_assignable_v</c-><c- o>&lt;</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- o>&amp;&amp;</c->
  <c- n>implies</c-><c- p>(</c-><c- n>is_assignable_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>&amp;</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;&amp;></c-><c- p>,</c->   <c- n>is_trivially_assignable_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>&amp;</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;&amp;></c-><c- p>)</c-> <c- o>&amp;&amp;</c->
  <c- n>implies</c-><c- p>(</c-><c- n>is_destructible_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>,</c->             <c- n>is_trivially_destructible_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>);</c->
</pre></small>
   <p><small></small></p>
   <p>Each of the above definitions models the library-writer’s intuition that "<code class="highlight"><c- n>T</c-></code> is trivially fooable"
means no more or less than "the foo operation on <code class="highlight"><c- n>T</c-></code> can be lowered to the foo operation on <code class="highlight"><c- n>T</c-></code>’s object
representation." (With the special case that TC refers to <em>all</em> supported value-semantic operations, as a package deal.
Something like this definition of TC was independently suggested by Casey Carter in <a href="https://reviews.llvm.org/D86126#2223156">an August 2020 PR comment</a>.)
This intuition applies uniformly to every "triviality" trait in today’s Standard Library,
and several more that have been proposed and/or implemented by vendors:</p>
   <p><small></small></p>
   <small> <ul><li data-md><p>trivially default-constructible (<em>sic</em>; read "default-initializable")</p> </li><li data-md><p>trivially value-initializable (<a data-link-type="biblio" href="#biblio-p2782" title="A type trait to detect if value initialization can be achieved by zero-filling">[P2782]</a>)</p> </li><li data-md><p>trivially (copy|move)-constructible</p> </li><li data-md><p>trivially (copy|move)-assignable</p> </li><li data-md><p>trivially destructible</p> </li><li data-md><p>trivially equality-comparable (Clang’s <code class="highlight"><c- n>__is_trivially_equality_comparable</c-></code> builtin)</p> </li><li data-md><p>trivially lexicographically-comparable (defined internally by libc++)</p> </li><li data-md><p>trivially swappable</p> </li></ul> </small>
   <p><small></small></p>
   <p>The wording might look like:</p>
   <blockquote>
    <small> [<code class="highlight"><c- n>is_trivially_constructible</c-><c- o>&lt;</c-><c- n>T</c-><c- p>,</c-> <c- n>Args</c-><c- p>...</c-><c- o>></c-></code> is true if and only if] <code class="highlight"><c- n>is_constructible_v</c-><c- o>&lt;</c-><c- n>T</c-><c- p>,</c-> <c- n>Args</c-><c- p>...</c-><c- o>></c-></code> is <code class="highlight">true</code> and the variable definition for <code class="highlight"><c- n>is_constructible</c-></code>,
as defined below, is known to <del>call no operation that is not trivial</del> <ins>be equivalent
in its observable effects to a simple copy of the complete object representation (when <code class="highlight"><c- k>sizeof</c-><c- p>...(</c-><c- n>Args</c-><c- p>)</c-> <c- o>==</c-> <c- mi>1</c-></code>)
or to have no observable effects (when <code class="highlight"><c- k>sizeof</c-><c- p>...(</c-><c- n>Args</c-><c- p>)</c-> <c- o>==</c-> <c- mi>0</c-></code>)</ins>. <ins>When <code class="highlight"><c- k>sizeof</c-><c- p>...(</c-><c- n>Args</c-><c- p>)</c-> <c- o>>=</c-> <c- mi>2</c-></code>, yields <code class="highlight">false</code>; this usage is deprecated.</ins> <p>[<code class="highlight"><c- n>is_trivially_assignable</c-><c- o>&lt;</c-><c- n>T</c-><c- p>,</c-> <c- n>U</c-><c- o>></c-></code> is true if and only if] <code class="highlight"><c- n>is_assignable_v</c-><c- o>&lt;</c-><c- n>T</c-><c- p>,</c-> <c- n>U</c-><c- o>></c-></code> is <code class="highlight">true</code> and the assignment, as defined by <code class="highlight"><c- n>is_assignable</c-></code>,
is known to <del>call no operation that is not trivial</del> <ins>be equivalent
in its observable effects to a simple copy of the complete object representation</ins>.</p> </small>
    <p><small>[<code class="highlight"><c- n>is_trivially_destructible</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code> is true if and only if] <code class="highlight"><c- n>is_destructible_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code> is <code class="highlight">true</code> and <code class="highlight"><c- n>remove_all_extents_t</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code> is <del>either a non-class type
or a class type with a trivial destructor</del> <ins>a type whose destructor is known to have
no observable effects</ins>. </small></p>
   </blockquote>
   <p></p>
   <p class="note" role="note"><span class="marker">Note:</span> I haven’t found a way to break <code class="highlight"><c- n>is_trivially_destructible</c-></code> yet, so maybe it doesn’t
need to change. Here I’m just making it consistent with the others.</p>
   <p>This proposal breaks a lot of eggs, but it makes a good omelet.</p>
   <p>It would allow the following naïve code to Just Work, even though it is buggy today
(<a href="https://godbolt.org/z/6o388YTzd">Godbolt</a>):</p>
<pre class="language-c++ highlight"><c- n>template</c-><c- o>&lt;</c-><c- n>class</c-> <c- n>T</c-><c- p>,</c-> <c- n>class</c-> <c- n>U</c-><c- o>></c->
<c- n>U</c-> <c- o>*</c-><c- n>simple_copy</c-><c- p>(</c-><c- n>T</c-> <c- o>*</c-><c- n>first</c-><c- p>,</c-> <c- n>T</c-> <c- o>*</c-><c- n>last</c-><c- p>,</c-> <c- n>U</c-> <c- o>*</c-><c- n>dfirst</c-><c- p>)</c-> <c- p>{</c->
  <c- k>static_assert</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>is_assignable_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>&amp;</c-><c- p>,</c-> <c- n>U</c-><c- o>&amp;></c-><c- p>);</c->
  <c- k>if</c-> <c- n>constexpr</c-> <c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>is_trivially_assignable_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>&amp;</c-><c- p>,</c-> <c- n>U</c-><c- o>&amp;></c-><c- p>)</c-> <c- p>{</c->
    <c- k>static_assert</c-><c- p>(</c-><c- k>sizeof</c-><c- p>(</c-><c- n>T</c-><c- p>)</c-> <c- o>==</c-> <c- k>sizeof</c-><c- p>(</c-><c- n>U</c-><c- p>));</c->
    <c- n>std</c-><c- o>::</c-><c- n>memmove</c-><c- p>(</c-><c- n>dfirst</c-><c- p>,</c-> <c- n>first</c-><c- p>,</c-> <c- p>(</c-><c- n>last</c-> <c- o>-</c-> <c- n>first</c-><c- p>)</c-> <c- o>*</c-> <c- k>sizeof</c-><c- p>(</c-><c- n>T</c-><c- p>));</c->
    <c- k>return</c-> <c- n>dfirst</c-> <c- o>+</c-> <c- p>(</c-><c- n>last</c-> <c- o>-</c-> <c- n>first</c-><c- p>);</c->
  <c- p>}</c-> <c- k>else</c-> <c- p>{</c->
    <c- k>while</c-> <c- p>(</c-><c- n>first</c-> <c- o>!=</c-> <c- n>last</c-><c- p>)</c-> <c- o>*</c-><c- n>dfirst</c-><c- o>++</c-> <c- o>=</c-> <c- o>*</c-><c- n>first</c-><c- o>++</c-><c- p>;</c->
  <c- p>}</c->
<c- p>}</c->

<c- b>int</c-> <c- n>main</c-><c- p>()</c-> <c- p>{</c->
  <c- b>int</c-> <c- n>source</c-><c- p>[]</c-> <c- o>=</c-> <c- p>{</c-><c- mi>1</c-><c- p>,</c-><c- mi>2</c-><c- p>,</c-><c- mi>3</c-><c- p>};</c->
  <c- b>float</c-> <c- n>dest</c-><c- p>[]</c-> <c- o>=</c-> <c- p>{</c-><c- mi>1</c-><c- p>,</c-><c- mi>2</c-><c- p>,</c-><c- mi>3</c-><c- p>};</c->
  <c- n>simple_copy</c-><c- p>(</c-><c- n>source</c-><c- p>,</c-> <c- n>source</c-><c- o>+</c-><c- mi>3</c-><c- p>,</c-> <c- n>dest</c-><c- p>);</c->
  <c- n>printf</c-><c- p>(</c-><c- s>"%f %f %f</c-><c- se>\n</c-><c- s>"</c-><c- p>,</c-> <c- n>dest</c-><c- p>[</c-><c- mi>0</c-><c- p>],</c-> <c- n>dest</c-><c- p>[</c-><c- mi>1</c-><c- p>],</c-> <c- n>dest</c-><c- p>[</c-><c- mi>2</c-><c- p>]);</c->
<c- p>}</c->
</pre>
   <p class="note" role="note"><span class="marker">Note:</span> Okay, to really make <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>copy</c-></code> work, you also need a special case for <code class="highlight"><c- n>n</c-> <c- o>==</c-> <c- mi>1</c-></code> and/or <code class="highlight"><c- n>__datasizeof</c-></code>,
because a single-object range might consist of a single potentially overlapping subobject. But vendors already
know that pitfall, and deal with it. See <a href="https://quuxplusone.github.io/blog/2018/07/13/trivially-copyable-corner-cases/">my blog post of July 2018</a>.</p>
   <p>This proposal opens the door for vendor-specific extensions to permit e.g. <code class="highlight"><c- n>is_trivially_constructible</c-><c- o>&lt;</c-><c- n>unique_ptr</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-><c- p>,</c-> <c- b>int</c-><c- o>*></c-></code>.
This is perfectly safe by the library-writer’s intuition, since <code class="highlight"><c- n>uninitialized_copy</c-></code>’ing a range
of <code class="highlight"><c- n>unique_ptr</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-></code> from a range of <code class="highlight"><c- b>int</c-><c- o>*</c-></code> can indeed be safely lowered to memcpy. How should the author of <code class="highlight"><c- n>unique_ptr</c-></code> warrant triviality to the compiler, so that the compiler can reflect it back to the author of <code class="highlight"><c- n>uninitialized_copy</c-></code>?—​We should leave that up to the vendor to figure out; but one possible extension would be</p>
<pre class="language-c++ highlight"><c- k>struct</c-> <c- nc>UniquePtr</c-> <c- p>{</c->
  <c- b>int</c-> <c- o>*</c-><c- n>p_</c-><c- p>;</c->
  <c- p>[[</c-><c- n>clang</c-><c- o>::</c-><c- n>trivial</c-><c- p>]]</c-> <c- n>explicit</c-> <c- n>UniquePtr</c-><c- p>(</c-><c- b>int</c-> <c- o>*</c-><c- n>p</c-><c- p>);</c->
  <c- o>~</c-><c- n>UniquePtr</c-><c- p>();</c->
<c- p>};</c->
</pre>
   <p>I believe this proposal completely eliminates all references to "trivial operations" and "trivial functions"
(other than trivial special members). That’s nice, because the Standard never defines what those are.
By removing all references to them, we <em>never</em> have to define what they are.</p>
   <p>By permitting vendors to define <code class="highlight"><c- n>is_trivially_copy_constructible</c-><c- o>&lt;</c-><c- n>FinalPolymorphic</c-><c- o>></c-></code>, this proposal solves an issue
recently raised for Clang by Haojian Wu; see <a data-link-type="biblio" href="#biblio-bitwisecopyable" title="[clang] Implement a bitwise_copyable builtin type trait">[BitwiseCopyable]</a>. Library authors really want to be able to
memcpy and/or start-the-lifetime-of polymorphic types. That works in practice, but today it’s technically UB
because polymorphic types never have any trivial constructors and therefore are never implicit-lifetime types
(<a href="https://eel.is/c++draft/class.prop#9">[class.prop]/9</a>). But the compiler knows that a <code class="highlight"><c- k>final</c-></code> polymorphic type can be trivially copied, and therefore could consider it to be implicit-lifetime. This
could solve a large swath of Haojian’s problem without needing Clang to provide a separate builtin,
although it probably doesn’t solve the whole problem.</p>
   <p class="note" role="note"><span class="marker">Note:</span> Non-<code class="highlight"><c- k>final</c-></code> polymorphic types can never be trivially copied nor trivially assigned, because of slicing.
See <a href="https://quuxplusone.github.io/blog/2023/06/24/polymorphic-types-arent-trivially-relocatable/">my blog post of June 2023</a>.</p>
   <p>Finally, we need to do something with <a href="https://eel.is/c++draft/basic.types#general-2">[basic.types.general]/2–3</a>.
Given the proposed wording above, I think we could just
strike [basic.types.general]/2–3 as redundant:
obviously, <em>if</em> a type is trivially copy-assignable by the new wording (let alone TC), then copying its object representation
also copies its value, by definition. Striking those two paragraphs would also save us from having to define
what the "[original] value" of an object means, standardese-wise.</p>
   <p><a href="https://eel.is/c++draft/basic.types#general-4">[basic.types.general]/4</a> says:
"For trivially copyable types, the <em>value representation</em> is a set of bits in the object representation
that determines a value, which is one discrete element of an implementation-defined set of values."
This sentence doesn’t seem useful, but also isn’t harmful; we can let it be.</p>
   <h3 class="heading settled" data-level="5.1" id="conclusion"><span class="secno">5.1. </span><span class="content">Conclusion</span><a class="self-link" href="#conclusion"></a></h3>
   <p>This proposal is drastic and breaks a lot of eggs, but makes a good omelet.
We would come out the other side with a type-traits library that is actually usable
by library-writers. Library-writers are already quietly assuming that the traits
work this way, so bringing the Standard into line with those assumptions would
immediately close a lot of library bugs.</p>
   <p>I plan to bring an R1 with formal wording, and hope to also gain some implementation
experience in my fork of Clang. Assistance will be gratefully accepted.</p>
   <h2 class="heading settled" data-level="6" id="acknowledgments"><span class="secno">6. </span><span class="content">Acknowledgments</span><a class="self-link" href="#acknowledgments"></a></h2>
   <p>Thanks to Ville Voutilainen and Giuseppe D’Angelo for their encouragement and discussion.</p>
   <p>Thanks to the regulars on the cpplang Slack for rubber-ducking a lot of these examples.</p>
  </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="informative"><span class="content">Informative References</span><a class="self-link" href="#informative"></a></h3>
  <dl>
   <dt id="biblio-bitwisecopyable">[BitwiseCopyable]
   <dd>Haojian Wu. <a href="https://github.com/llvm/llvm-project/pull/86512"><cite>[clang] Implement a bitwise_copyable builtin type trait</cite></a>. March 2024—. URL: <a href="https://github.com/llvm/llvm-project/pull/86512">https://github.com/llvm/llvm-project/pull/86512</a>
   <dt id="biblio-cwg2463">[CWG2463]
   <dd>Daveed Vandevoorde. <a href="https://cplusplus.github.io/CWG/issues/2463.html"><cite>Trivial copyability and unions with non-trivial members</cite></a>. November 2020—. URL: <a href="https://cplusplus.github.io/CWG/issues/2463.html">https://cplusplus.github.io/CWG/issues/2463.html</a>
   <dt id="biblio-mller">[Müller]
   <dd>Jonathan Müller. <a href="https://www.foonathan.net/2021/03/trivially-copyable/"><cite>Trivially copyable does not mean trivially copy constructible</cite></a>. March 2021. URL: <a href="https://www.foonathan.net/2021/03/trivially-copyable/">https://www.foonathan.net/2021/03/trivially-copyable/</a>
   <dt id="biblio-odwyer">[ODwyer]
   <dd>Arthur O'Dwyer. <a href="https://quuxplusone.github.io/blog/2024/05/15/false-advertising/"><cite>Types that falsely advertise trivial copyability</cite></a>. May 2024. URL: <a href="https://quuxplusone.github.io/blog/2024/05/15/false-advertising/">https://quuxplusone.github.io/blog/2024/05/15/false-advertising/</a>
   <dt id="biblio-p2782">[P2782]
   <dd>Giuseppe D'Angelo. <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2782r0.html"><cite>A type trait to detect if value initialization can be achieved by zero-filling</cite></a>. January 2023. URL: <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2782r0.html">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2782r0.html</a>
   <dt id="biblio-p3247">[P3247]
   <dd>Jens Maurer. <a href="https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3247r0.html"><cite>Deprecate the notion of trivial types</cite></a>. April 2024. URL: <a href="https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3247r0.html">https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3247r0.html</a>
  </dl>