<!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>P2025R0: Guaranteed copy elision for named return objects</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
 *
 * 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)
 *   - .assertion  for assertions                    (div, p, span)
 *   - .advisement for loud normative statements     (div, p, strong)
 *   - .annoying-warning for spec obsoletion notices (div, aside, details)
 *
 * 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
 *
 * 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)
 *
 ******************************************************************************/

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

	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;

		/* Colors */
		color: black;
		background: white 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-width: .65rem .7rem .6rem;
		border-radius: .4rem;
		background: #1a5e9a;
		color: white;
		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;
		border-color: #c00;
	}

	/* 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: 2;
			bottom: 0; left: 0;
			margin: 0;
			min-width: 1.33em;
			border-top-right-radius: 2rem;
			box-shadow: 0 0 2px;
			font-size: 1.5em;
			color: black;
		}
		#toc-nav > a {
			display: block;
			white-space: nowrap;

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

			background: white;
			box-shadow: 0 0 2px;
			border: none;
			border-top-right-radius: 1.33em;
			background: white;
		}
		#toc-nav > #toc-jump {
			padding-bottom: 2em;
			margin-bottom: -1.9em;
		}

		#toc-nav > a:hover,
		#toc-nav > a:focus {
			background: #f8f8f8;
		}
		#toc-nav > a:not(:hover):not(:focus) {
			color: #707070;
		}

		/* 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-toggle-inline {
			vertical-align: 0.05em;
			font-size: 80%;
			color: gray;
			color: hsla(203,20%,40%,.7);
			border-style: none;
			background: transparent;
			position: relative;
		}
		#toc-toggle-inline:hover:not(:active),
		#toc-toggle-inline:focus:not(:active) {
			text-shadow: 1px 1px silver;
			top: -1px;
			left: -1px;
		}

		#toc-nav :active {
			color: #C00;
		}
	}

/** 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);
			background: inherit;
			background-color: #f7f8f9;
			z-index: 1;
			box-shadow: -.1em 0 .25em rgba(0,0,0,.1) 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);
		}
		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);
			background: inherit;
			background-color: #f7f8f9;
			z-index: 1;
			box-shadow: -.1em 0 .25em rgba(0,0,0,.1) 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);
		}

		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;
		background: transparent;
	}

	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,
	#subtitle {
		/* #subtitle 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) > hr {
		font-size: 1.5em;
		text-align: center;
		margin: 1em auto;
		height: auto;
		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;
	}

	/* Put nice boxes around each algorithm. */
	[data-algorithm]:not(.heading) {
	  padding: .5em;
	  border: thin solid #ddd; 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: medium;
	}
	dfn var {
		font-style: normal;
	}

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

	del { color: red;  text-decoration: line-through; }
	ins { color: #080; text-decoration: underline;    }

/** 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;
		page-break-inside: avoid;
		hyphens: none;
		text-transform: none;
	}
	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;
		text-decoration: none;
		border-bottom: 1px solid #707070;
		/* Need a bit of extending for it to look okay */
		padding: 0 1px 0;
		margin: 0 -1px 0;
	}
	a:visited {
		border-bottom-color: #BBB;
	}

	/* Use distinguishing colors when user is interacting with the link */
	a[href]:focus,
	a[href]:hover {
		background: #f8f8f8;
		background: rgba(75%, 75%, 75%, .25);
		border-bottom-width: 3px;
		margin-bottom: -2px;
	}
	a[href]:active {
		color: #C00;
		border-color: #C00;
	}

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

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

	img {
		border-style: none;
	}

	/* 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;
	}
	.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 {
		padding: .5em;
		border: .5em;
		border-left-style: solid;
		page-break-inside: avoid;
	}
	span.issue, span.note {
		padding: .1em .5em .15em;
		border-right-style: solid;
	}

	.issue,
	.note,
	.example,
	.advisement,
	.assertion,
	blockquote {
		margin: 1em auto;
	}
	.note  > p:first-child,
	.issue > p:first-child,
	blockquote > :first-child {
		margin-top: 0;
	}
	blockquote > :last-child {
		margin-bottom: 0;
	}

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

	blockquote {
		border-color: silver;
	}

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

	.issue {
		border-color: #E05252;
		background: #FBE9E9;
		counter-increment: issue;
		overflow: auto;
	}
	.issue::before, .issue > .marker {
		text-transform: uppercase;
		color: #AE1E1E;
		padding-right: 1em;
		text-transform: uppercase;
	}
	/* 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;
		background: #FCFAEE;
		counter-increment: example;
		overflow: auto;
		clear: both;
	}
	.example::before, .example > .marker {
		text-transform: uppercase;
		color: #827017;
		min-width: 7.5em;
		display: block;
	}
	/* 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;
		background: #E9FBE9;
		overflow: auto;
	}

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

	details.note > summary {
		display: block;
		color: hsl(120, 70%, 30%);
	}
	details.note[open] > summary {
		border-bottom: 1px silver solid;
	}

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

	.assertion {
		border-color: #AAA;
		background: #EEE;
	}

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

	.advisement {
		border-color: orange;
		border-style: none solid;
		background: #FFEECC;
	}
	strong.advisement {
		display: block;
		text-align: center;
	}
	.advisement > .marker {
		color: #B35F00;
	}

/** 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: #fdd;
		color: red;
		font-weight: bold;
		padding: .75em 1em;
		border: thick red;
		border-style: solid;
		border-radius: 1em;
	}
	.annoying-warning :last-child {
		margin-bottom: 0;
	}

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

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

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

	.def {
		padding: .5em 1em;
		background: #DEF;
		margin: 1.2em 0;
		border-left: 0.5em solid #8CCBF2;
	}

/******************************************************************************/
/*                                    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;
	}

	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-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;
		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;
		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-top: 0.1rem;
		/* Larger, more consistently-sized click target */
		display: block;
		/* Reverse color scheme */
		color: black;
		border-color: #3980B5;
		border-bottom-width: 3px !important;
		margin-bottom: 0px !important;
	}
	.toc a:visited {
		border-color: #054572;
	}
	.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;
		line-height: 1.1rem; /* consistent spacing */
	}

	/* 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 .secno { font-size: 85%; }
	.toc > li li li li li { font-size:   85%;    }
	.toc > li li li li li .secno { font-size: 100%; }

	/* @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 {
			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; }
		}
	/* } */

	@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;
		}
		#toc .content:hover {
			background: rgba(75%, 75%, 75%, .25);
			border-bottom: 3px solid #054572;
			margin-bottom: -3px;
		}
		#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 span {
			white-space: nowrap;
			color: transparent; }
		ul.index li a:hover + span,
		ul.index li a:focus + span {
			color: #707070;
		}
	}

/** 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]) {
		background: #f7f8f9;
	}

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

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

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

/******************************************************************************/
/*                                    Legacy                                  */
/******************************************************************************/

	/* This rule is inherited from past style sheets. No idea what it's for. */
	.hide { display: none }



/******************************************************************************/
/*                             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 table positioning:
		   "content column" is 50ems wide at max; less on smaller screens.
		   Extra space (after ToC + content) is empty on the right.

		   1. When table < content column, centers table in column.
		   2. When content < table < available, left-aligns.
		   3. When table > 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 type="text/css">
    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 2a881f0ee698433d75c6a1555514334adb37d8c7" name="generator">
  <link href="https://isocpp.org/favicon.ico" rel="icon">
<style>
ins {
  background-color: #CCFFCC;
  text-decoration: underline;
}
del {
  background-color: #FFCACA;
  text-decoration: line-through;
}
.warning-note {
  background-color: #FCFAEE;
  border-color: #E0CB52;
  overflow-x: auto;
  overflow-y: auto;
  clear: both;
}
</style>
<style>/* 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>/* style-selflinks */

.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%;
}
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: gray;
    color: white;
    font-style: normal;
    transition: opacity .2s, background-color .2s, color .2s;
}
dfn:hover > a.self-link {
    opacity: 1;
}
dfn > a.self-link:hover {
    color: black;
}

a.self-link::before            { content: "¶"; }
.heading > a.self-link::before { content: "§"; }
dfn > a.self-link::before      { content: "#"; }</style>
<style>/* 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>/* style-autolinks */

.css.css, .property.property, .descriptor.descriptor {
    color: #005a9c;
    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;
}</style>
<style>/* style-dfn-panel */

.dfn-panel {
    position: absolute;
    z-index: 35;
    height: auto;
    width: -webkit-fit-content;
    width: fit-content;
    max-width: 300px;
    max-height: 500px;
    overflow: auto;
    padding: 0.5em 0.75em;
    font: small Helvetica Neue, sans-serif, Droid Sans Fallback;
    background: #DDDDDD;
    color: black;
    border: outset 0.2em;
}
.dfn-panel:not(.on) { display: none; }
.dfn-panel * { margin: 0; padding: 0; text-indent: 0; }
.dfn-panel > b { display: block; }
.dfn-panel a { color: black; }
.dfn-panel a:not(:hover) { text-decoration: none !important; border-bottom: none !important; }
.dfn-panel > b + b { margin-top: 0.25em; }
.dfn-panel ul { padding: 0; }
.dfn-panel li { list-style: inside; }
.dfn-panel.activated {
    display: inline-block;
    position: fixed;
    left: .5em;
    bottom: 2em;
    margin: 0 auto;
    max-width: calc(100vw - 1.5em - .4em - .5em);
    max-height: 30vh;
}

.dfn-paneled { cursor: pointer; }
</style>
<style>/* style-syntax-highlighting */

.highlight:not(.idl) { background: hsl(24, 20%, 95%); }
code.highlight { padding: .1em; border-radius: .3em; }
pre.highlight, pre > code.highlight { display: block; padding: 1em; margin: .5em 0; overflow: auto; border-radius: 0; }
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 */
</style>
 <body class="h-entry">
  <div class="head">
   <p data-fill-with="logo"></p>
   <h1 class="p-name no-ref" id="title">P2025R0<br>Guaranteed copy elision for named return objects</h1>
   <h2 class="no-num no-toc no-ref heading settled" id="subtitle"><span class="content">Published Proposal, <time class="dt-updated" datetime="2020-01-08">2020-01-08</time></span></h2>
   <div data-fill-with="spec-metadata">
    <dl>
     <dt>Issue Tracking:
     <dd><a href="#issues-index">Inline In Spec</a>
     <dt>Author:
     <dd>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:antonyzhilin@gmail.com">Anton Zhilin</a>
     <dt>Audience:
     <dd>SG17, EWG
     <dt>Project:
     <dd>ISO/IEC JTC1/SC22/WG21 14882: Programming Language — C++
     <dt>Current Source:
     <dd><a href="https://github.com/Anton3/cpp-proposals/blob/master/published/p2025r0.bs">https://github.com/Anton3/cpp-proposals/blob/master/published/p2025r0.bs</a>
     <dt>Current:
     <dd><a href="https://github.com/Anton3/cpp-proposals/blob/master/published/p2025r0.html">https://github.com/Anton3/cpp-proposals/blob/master/published/p2025r0.html</a>
    </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>This proposal aims to provide guaranteed copy elision for common cases of local variables being returned from a function.</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="#motivation"><span class="secno">1</span> <span class="content">Motivation</span></a>
    <li>
     <a href="#proposal"><span class="secno">2</span> <span class="content">Proposed solution</span></a>
     <ol class="toc">
      <li><a href="#examples"><span class="secno">2.1</span> <span class="content">Examples</span></a>
      <li><a href="#wording"><span class="secno">2.2</span> <span class="content">Proposed wording</span></a>
     </ol>
    <li>
     <a href="#faq"><span class="secno">3</span> <span class="content">Frequently Asked Questions</span></a>
     <ol class="toc">
      <li><a href="#abi"><span class="secno">3.1</span> <span class="content">Are the proposed changes source or ABI breaking?</span></a>
      <li><a href="#costs"><span class="secno">3.2</span> <span class="content">What are the costs associated with the proposed changes?</span></a>
      <li><a href="#trivial-temporaries"><span class="secno">3.3</span> <span class="content">What about trivially-copyable temporaries?</span></a>
      <li><a href="#term"><span class="secno">3.4</span> <span class="content">Is "named return object" a good term choice?</span></a>
     </ol>
    <li>
     <a href="#alternatives"><span class="secno">4</span> <span class="content">Alternative solutions</span></a>
     <ol class="toc">
      <li><a href="#existing-features"><span class="secno">4.1</span> <span class="content">Implement similar functionality using existing features</span></a>
      <li><a href="#more-nrvo"><span class="secno">4.2</span> <span class="content">Guarantee NRVO in more cases</span></a>
      <li><a href="#explicit-mark"><span class="secno">4.3</span> <span class="content">Require an explicit mark for named return objects</span></a>
      <li><a href="#alias-expressions"><span class="secno">4.4</span> <span class="content">Alias expressions</span></a>
     </ol>
    <li>
     <a href="#future-work"><span class="secno">5</span> <span class="content">Future work</span></a>
     <ol class="toc">
      <li><a href="#more-elision"><span class="secno">5.1</span> <span class="content">Guarantee some other types of copy elision</span></a>
      <li><a href="#disallowed-elision"><span class="secno">5.2</span> <span class="content">Guarantee currently disallowed types of copy elision</span></a>
      <li><a href="#other-moves"><span class="secno">5.3</span> <span class="content">Reduce the number of moves performed in other cases</span></a>
     </ol>
    <li><a href="#acknowledgements"><span class="secno">6</span> <span class="content">Acknowledgements</span></a>
    <li>
     <a href="#index"><span class="secno"></span> <span class="content">Index</span></a>
     <ol class="toc">
      <li><a href="#index-defined-here"><span class="secno"></span> <span class="content">Terms defined by this specification</span></a>
     </ol>
    <li>
     <a href="#references"><span class="secno"></span> <span class="content">References</span></a>
     <ol class="toc">
      <li><a href="#normative"><span class="secno"></span> <span class="content">Normative References</span></a>
      <li><a href="#informative"><span class="secno"></span> <span class="content">Informative References</span></a>
     </ol>
    <li><a href="#issues-index"><span class="secno"></span> <span class="content">Issues Index</span></a>
   </ol>
  </nav>
  <main>
   <h2 class="heading settled" data-level="1" id="motivation"><span class="secno">1. </span><span class="content">Motivation</span><a class="self-link" href="#motivation"></a></h2>
   <p>The accepted <a data-link-type="biblio" href="#biblio-p0135r0">[P0135R0]</a> proposal already provides guaranteed copy elision for when a prvalue is returned from a function by stating that the result object of that prvalue (and not a temporary) is directly copy-initialized. It de-facto mandates what was known as Return Value Optimization (RVO) and allows non-copyable, non-movable objects to be returned in such a way.</p>
   <p>Meanwhile, the other cases of copy elision are still optional. For example, sometimes we want to create an object, set it up and return it.</p>
<pre class="language-cpp highlight"><c- n>widget</c-> <c- nf>setup_widget</c-><c- p>(</c-><c- b>int</c-> <c- n>x</c-><c- p>)</c-> <c- p>{</c->
  <c- n>widget</c-> <c- n>w</c-><c- p>;</c->
  <c- n>w</c-><c- p>.</c-><c- n>set_x</c-><c- p>(</c-><c- n>x</c-><c- p>);</c->
  <c- k>return</c-> <c- n>w</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p><code class="highlight"><c- n>setup_widget</c-></code> will copy or move <code class="highlight"><c- n>w</c-></code> out. Compilers often perform Named Return Value Optimization (NRVO) in such cases, but it is not guaranteed. This situation is unacceptable in these cases, among others:</p>
   <ul>
    <li data-md>
     <p>If the setup process includes taking a pointer to <code class="highlight"><c- n>w</c-></code> and storing it elsewhere</p>
    <li data-md>
     <p>If <code class="highlight"><c- n>widget</c-></code> is non-copyable non-movable, because its memory location is critically important to its functionality, e.g. <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>mutex</c-></code></p>
    <li data-md>
     <p>If <code class="highlight"><c- n>widget</c-></code> is non-copyable, because it manages resources that are not easy to copy, and non-movable, because it does not have an empty state, e.g. <code class="highlight"><c- n>open_file</c-></code> and <code class="highlight"><c- n>not_null_ptr</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code></p>
   </ul>
   <p>On practice, the workaround can be either:</p>
   <ul>
    <li data-md>
     <p>Two-stage initialization, where a local variable is constructed in its destination (e.g. using the default constructor) and is then immediately passed to function(s) by reference in order to complete the setup of the object</p>
    <li data-md>
     <p>Always storing the object on heap, e.g. by returning <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>unique_ptr</c-><c- o>&lt;</c-><c- n>widget</c-><c- o>></c-></code> instead of <code class="highlight"><c- n>widget</c-></code> from factory functions</p>
   </ul>
   <p>Both "solutions" are often viewed as anti-patterns.</p>
   <p>A proper solution should allow for the construct-cook-return pattern, even if a copy or move is not affordable.</p>
   <h2 class="heading settled" data-level="2" id="proposal"><span class="secno">2. </span><span class="content">Proposed solution</span><a class="self-link" href="#proposal"></a></h2>
   <p>If copy elision for a returned variable is allowed, and all <a href="http://eel.is/c++draft/stmt.if#def:discarded_statement">non-discarded</a> <code class="highlight"><c- k>return</c-></code> statements in its <a href="http://eel.is/c++draft/basic.scope#def:potential_scope">potential scope</a> <a data-link-type="abstract-op" href="#abstract-opdef-to-return-a-variable" id="ref-for-abstract-opdef-to-return-a-variable">return</a> the variable, then copy elision is guaranteed.</p>
   <p>(For the purposes of brevity, the explanation above is not rigorous; see <a href="#wording">§ 2.2 Proposed wording</a> for a rigorous explanation.)</p>
   <h3 class="heading settled" data-level="2.1" id="examples"><span class="secno">2.1. </span><span class="content">Examples</span><a class="self-link" href="#examples"></a></h3>
   <p>Constructing and returning a <code class="highlight"><c- n>widget</c-></code>, guaranteed copy elision applies (since C++17):</p>
<pre class="language-cpp highlight"><c- n>widget</c-> <c- nf>setup_widget</c-><c- p>(</c-><c- b>int</c-> <c- n>x</c-><c- p>)</c-> <c- p>{</c->
  <c- k>return</c-> <c- n>widget</c-><c- p>(</c-><c- n>x</c-><c- p>);</c->
<c- p>}</c->
</pre>
   <p>Constructing, "cooking" and returning a <code class="highlight"><c- n>widget</c-></code>, guaranteed copy elision applies:</p>
<pre class="language-cpp highlight"><c- n>widget</c-> <c- nf>setup_widget</c-><c- p>(</c-><c- b>int</c-> <c- n>x</c-><c- p>)</c-> <c- p>{</c->
  <c- k>auto</c-> <c- n>w</c-> <c- o>=</c-> <c- n>widget</c-><c- p>(</c-><c- n>x</c-><c- p>);</c->
  <c- b>int</c-> <c- n>y</c-> <c- o>=</c-> <c- n>process</c-><c- p>(</c-><c- n>x</c-><c- p>);</c->
  <c- n>w</c-><c- p>.</c-><c- n>set_y</c-><c- p>(</c-><c- n>y</c-><c- p>);</c->
  <c- k>return</c-> <c- n>w</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>A more contrived example where guaranteed copy elision applies:</p>
<pre class="language-cpp highlight"><c- n>widget</c-> <c- nf>setup_widget</c-><c- p>()</c-> <c- p>{</c->
  <c- k>while</c-> <c- p>(</c->…<c- p>)</c-> <c- p>{</c->
    <c- k>auto</c-> <c- n>w</c-> <c- o>=</c-> <c- n>widget</c-><c- p>(</c-><c- mi>1</c-><c- p>);</c->
    <c- k>if</c-> <c- p>(</c->…<c- p>)</c-> <c- k>return</c-> <c- n>w</c-><c- p>;</c->
    <c- k>if</c-> <c- p>(</c->…<c- p>)</c-> <c- k>break</c-><c- p>;</c->
    <c- k>if</c-> <c- p>(</c->…<c- p>)</c-> <c- k>throw</c-> …<c- p>;</c->
    <c- k>if</c-> <c- p>(</c->…<c- p>)</c-> <c- k>return</c-> <c- n>w</c-><c- p>;</c->
  <c- p>}</c->
  <c- k>return</c-> <c- n>widget</c-><c- p>(</c-><c- mi>2</c-><c- p>);</c->
<c- p>}</c->
</pre>
   <p>An example where guaranteed copy elision does not apply:</p>
<pre class="highlight"><c- n>widget</c-> <c- nf>setup_widget</c-><c- p>()</c-> <c- p>{</c->
  <c- k>auto</c-> <c- n>w</c-> <c- o>=</c-> <c- n>widget</c-><c- p>(</c-><c- mi>1</c-><c- p>);</c->
  <c- k>if</c-> <c- p>(</c->…<c- p>)</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>w</c-><c- p>;</c->  <c- c1>//!</c->
  <c- p>}</c-> <c- k>else</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>widget</c-><c- p>(</c-><c- mi>2</c-><c- p>);</c->
  <c- p>}</c->
<c- p>}</c->
</pre>
   <p>The example above can be "fixed" so that guaranteed copy elision does apply:</p>
<pre class="language-cpp highlight"><c- n>widget</c-> <c- nf>setup_widget</c-><c- p>()</c-> <c- p>{</c->
  <c- k>if</c-> <c- p>(</c->…<c- p>)</c-> <c- p>{</c->
    <c- k>auto</c-> <c- n>w</c-> <c- o>=</c-> <c- n>widget</c-><c- p>(</c-><c- mi>1</c-><c- p>);</c->
    <c- k>return</c-> <c- n>w</c-><c- p>;</c->
  <c- p>}</c-> <c- k>else</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>widget</c-><c- p>(</c-><c- mi>2</c-><c- p>);</c->
  <c- p>}</c->
<c- p>}</c->
</pre>
   <p>In the following example, <code class="highlight"><c- k>return</c-> <c- n>two</c-><c- p>;</c-></code> lies in the potential scope of <code class="highlight"><c- n>one</c-></code>, so guaranteed copy elision does not apply to <code class="highlight"><c- n>one</c-></code>:</p>
<pre class="highlight"><c- n>widget</c-> <c- nf>test</c-><c- p>()</c-> <c- p>{</c->
  <c- n>widget</c-> <c- n>one</c-><c- p>;</c->
  <c- k>return</c-> <c- n>one</c-><c- p>;</c->  <c- c1>//!</c->
  <c- n>widget</c-> <c- n>two</c-><c- p>;</c->
  <c- k>return</c-> <c- n>two</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>Constructing, setting up and passing an object as a parameter using an immediately invoked lambda expression (<code class="highlight"><c- n>consume_widget</c-></code>'s parameter is directly initialized with <code class="highlight"><c- n>x</c-></code>):</p>
<pre class="language-cpp highlight"><c- b>void</c-> <c- nf>consume_widget</c-><c- p>(</c-><c- n>widget</c-><c- p>);</c->

<c- b>void</c-> <c- nf>test</c-><c- p>(</c-><c- b>int</c-> <c- n>x</c-><c- p>)</c-> <c- p>{</c->
  <c- b>int</c-> <c- n>y</c-> <c- o>=</c-> <c- n>process</c-><c- p>(</c-><c- n>x</c-><c- p>);</c->
  <c- n>consume_widget</c-><c- p>([</c-><c- o>&amp;</c-><c- p>]</c-> <c- p>{</c->
    <c- k>auto</c-> <c- n>w</c-> <c- o>=</c-> <c- n>widget</c-><c- p>(</c-><c- n>x</c-><c- p>);</c->
    <c- n>w</c-><c- p>.</c-><c- n>set_y</c-><c- p>(</c-><c- n>y</c-><c- p>);</c->
    <c- k>return</c-> <c- n>w</c-><c- p>;</c->
  <c- p>}());</c->
<c- p>}</c->
</pre>
   <h3 class="heading settled" data-level="2.2" id="wording"><span class="secno">2.2. </span><span class="content">Proposed wording</span><a class="self-link" href="#wording"></a></h3>
   <p>The wording in this section is relative to WG21 draft <a data-link-type="biblio" href="#biblio-n4842">[N4842]</a>.</p>
   <p>Add a new subclause of <a href="http://eel.is/c++draft/stmt.return">[stmt.return]</a>, <dfn class="dfn-paneled" data-dfn-type="dfn" data-noexport id="stmtreturnnamed">[stmt.return.named]</dfn>:</p>
   <blockquote>
     It is said that a <code class="highlight"><c- k>return</c-></code> statement <dfn class="dfn-paneled" data-dfn-type="abstract-op" data-export data-lt="to return a variable" id="abstract-opdef-to-return-a-variable">returns</dfn> a variable when its operand is a (possibly parenthesized) <em>id-expression</em>, for which the name lookup (<a href="http://eel.is/c++draft/basic.lookup">[basic.lookup]</a>) finds the variable. 
    <p>A variable with automatic storage duration is called a <dfn class="dfn-paneled" data-dfn-type="abstract-op" data-export id="abstract-opdef-named-return-object">named return object</dfn> when all of the following conditions are satisfied:</p>
    <ul>
     <li data-md>
      <p>the variable is not a function parameter and is not introduced by the <em>exception-declaration</em> of a handler (<a href="http://eel.is/c++draft/except.handle">[except.handle]</a>),</p>
     <li data-md>
      <p>the type of the variable is a class type, is not <code class="highlight"><c- k>volatile</c-></code>-qualified, and is the same (ignoring cv-qualification) as the return type of the enclosing function, and</p>
     <li data-md>
      <p>all non-discarded (<a href="http://eel.is/c++draft/stmt.if">[stmt.if]</a>) <code class="highlight"><c- k>return</c-></code> statements in its potential scope (<a href="http://eel.is/c++draft/basic.scope">[basic.scope]</a>), of which there is at least one, <a data-link-type="abstract-op" href="#abstract-opdef-to-return-a-variable" id="ref-for-abstract-opdef-to-return-a-variable①">return</a> the variable. [ <em>Note:</em> The enclosing function cannot be a coroutine. — <em>end note</em> ]</p>
    </ul>
    <p>A <a data-link-type="abstract-op" href="#abstract-opdef-named-return-object" id="ref-for-abstract-opdef-named-return-object">named return object</a> denotes the result object of the function call expression. Statements that <a data-link-type="abstract-op" href="#abstract-opdef-to-return-a-variable" id="ref-for-abstract-opdef-to-return-a-variable②">return</a> a named return object perform no copy-initialization (<a href="http://eel.is/c++draft/stmt.return">[stmt.return]</a>) and do not cause the destruction of the object (<a href="http://eel.is/c++draft/stmt.jump">[stmt.jump]</a>). [ <em>Note:</em> The <em>declaration-statement</em> of a named return object initializes the object denoted by it, see <a href="http://eel.is/c++draft/stmt.dcl">[stmt.dcl]</a>. On exit from the scope of a named return object, other than by executing a statement that <a data-link-type="abstract-op" href="#abstract-opdef-to-return-a-variable" id="ref-for-abstract-opdef-to-return-a-variable③">returns</a> it, the object denoted by it is destroyed, see <a href="http://eel.is/c++draft/stmt.jump">[stmt.jump]</a>. During stack unwinding, the object denoted by a named return object is destroyed, see <a href="http://eel.is/c++draft/except.ctor">[except.ctor]</a>. — <em>end note</em> ]</p>
   </blockquote>
   <blockquote class="note warning-note"> Note:
The relationship "statement <a data-link-type="abstract-op" href="#abstract-opdef-to-return-a-variable" id="ref-for-abstract-opdef-to-return-a-variable④">returns</a> a variable" may be useful in other parts of the standard, e.g. in <a href="http://eel.is/c++draft/class.copy.elision#3">[class.copy.elision]/3</a>. </blockquote>
   <blockquote class="note warning-note"> Note:
A <a data-link-type="abstract-op" href="#abstract-opdef-named-return-object" id="ref-for-abstract-opdef-named-return-object①">named return object</a> is a variable. The definition carefully avoids mentioning the object it names before stating that the object is the result object of the function call expression (the "return object"). </blockquote>
   <blockquote class="note warning-note"> Note:
The requirements on a <a data-link-type="abstract-op" href="#abstract-opdef-named-return-object" id="ref-for-abstract-opdef-named-return-object②">named return object</a> are intended to be the same as for the optional copy elision in <code class="highlight"><c- k>return</c-></code> statements (<a href="http://eel.is/c++draft/class.copy.elision">[class.copy.elision]</a>), except for the last restriction mentioning <code class="highlight"><c- k>return</c-></code> statements in the potential scope. </blockquote>
   <p>Modify <a href="http://eel.is/c++draft/stmt.jump#2">[stmt.jump]/2</a>:</p>
   <blockquote>
     On exit from a scope (however accomplished), objects with automatic storage duration that have been constructed in that scope 
    <ins>(excluding the case described in <a data-link-type="dfn" href="#stmtreturnnamed" id="ref-for-stmtreturnnamed">[stmt.return.named]</a>)</ins>
     are destroyed in the reverse order of their construction. [ <em>Note:</em> For temporaries, see <a href="http://eel.is/c++draft/class.temporary">[class.temporary]</a>. — <em>end note</em> ] Transfer out of a loop, out of a block, or back past an initialized variable with automatic storage duration involves the destruction of objects with automatic storage duration that are in scope at the point transferred from but not at the point transferred to. (See <a href="http://eel.is/c++draft/stmt.dcl">[stmt.dcl]</a> for transfers into blocks). […] 
   </blockquote>
   <p>Modify <a href="http://eel.is/c++draft/stmt.return#2">[stmt.return]/2</a>:</p>
   <blockquote>
     […] A <code class="highlight"><c- k>return</c-></code> statement with any other operand shall be used only in a function whose return type is not cv <code class="highlight"><c- b>void</c-></code>; the <code class="highlight"><c- k>return</c-></code> statement initializes the glvalue result or prvalue result object of the (explicit or implicit) function call by copy-initialization from the operand 
    <ins>(excluding the case described in <a data-link-type="dfn" href="#stmtreturnnamed" id="ref-for-stmtreturnnamed①">[stmt.return.named]</a>)</ins>
    . […] 
   </blockquote>
   <p>Modify <a href="http://eel.is/c++draft/stmt.dcl#2">[stmt.dcl]/2</a>:</p>
   <blockquote>
    <p>
     Variables with automatic storage duration are initialized each time their <em>declaration-statement</em> is executed. 
     <ins>[ <em>Note:</em></ins>
      Variables with automatic storage duration declared in the block are destroyed on exit from the block 
     <ins>as described in</ins>
     <del>(</del>
      <a href="http://eel.is/c++draft/stmt.jump">[stmt.jump]</a> 
     <del>)</del>
     . 
     <ins>— <em>end note</em> ]</ins>
    </p>
   </blockquote>
   <blockquote class="note warning-note"> Note:
The modified sentence currently duplicates the specification in <a href="http://eel.is/c++draft/stmt.jump#2">[stmt.jump]/2</a>. If the sentence is turned into a reference, it will not have to duplicate the exception for named return objects. </blockquote>
   <p>Modify <a href="http://eel.is/c++draft/class.copy.elision#1">[class.copy.elision]/1</a>:</p>
   <blockquote>
    <p>
     Copy elision is not permitted where an expression is evaluated in a context requiring a constant expression (<a href="http://eel.is/c++draft/expr.const">[expr.const]</a>) and in constant initialization (<a href="http://eel.is/c++draft/basic.start.static">[basic.start.static]</a>). [ <em>Note:</em> Copy elision might be performed if the same expression is evaluated in another context. 
     <ins><a data-link-type="dfn" href="#stmtreturnnamed" id="ref-for-stmtreturnnamed②">[stmt.return.named]</a> requires in all contexts what would otherwise be copy elision.</ins>
      — <em>end note</em> ]
    </p>
   </blockquote>
   <blockquote class="note warning-note"> Note:
As with "Guaranteed RVO" of <a data-link-type="biblio" href="#biblio-p0135r0">[P0135R0]</a>, "Guaranteed NRVO" is not specified as a special case of copy elision. Nevertheless, the proposed changes will affect the code constructs currently eligible for copy elision. Such copy elision is currently <em>prohibited</em> in <code class="highlight"><c- k>constexpr</c-></code>-related contexts and is <em>optional</em> otherwise. With proposed changes, <a data-link-type="dfn" href="#stmtreturnnamed" id="ref-for-stmtreturnnamed③">[stmt.return.named]</a>, when applies, <em>requires</em> copies not to occur, unless the object type is <a href="http://eel.is/c++draft/class.temporary#1">trivially-copyable</a>. </blockquote>
   <h2 class="heading settled" data-level="3" id="faq"><span class="secno">3. </span><span class="content">Frequently Asked Questions</span><a class="self-link" href="#faq"></a></h2>
   <h3 class="heading settled" data-level="3.1" id="abi"><span class="secno">3.1. </span><span class="content">Are the proposed changes source or ABI breaking?</span><a class="self-link" href="#abi"></a></h3>
   <p>The proposal does affect and <strong>can break</strong> constant expressions that rely on effects of the copy-initialization and destruction that are proposed to be elided. The defect report <a data-link-type="biblio" href="#biblio-cwg2278">[CWG2278]</a>, requiring that copy elision is not performed in constant expressions, has been presented in March, 2018.</p>
   <p>However, relying on the effects of copy-initialization and destruction in constant expressions is considered exotic, and real-world code breakage is deemed to be minimal.</p>
   <p>The proposal is <em>not</em> source-breaking outside of constant expressions, because it mandates copy elision in some of the cases that are currently optional.</p>
   <p>The proposal is <em>not</em> ABI-breaking, because, in all known implementations, whether NRVO is applied for a function does not impact its calling convention.</p>
   <h3 class="heading settled" data-level="3.2" id="costs"><span class="secno">3.2. </span><span class="content">What are the costs associated with the proposed changes?</span><a class="self-link" href="#costs"></a></h3>
   <p>There is no runtime cost associated with the proposed copy elision, because storage for the return object is allocated on stack before the function body starts executing, in all known implementations.</p>
   <p>The proposal will make declarations of local variables with automatic storage duration context-dependent: storage of a variable will depend on <code class="highlight"><c- k>return</c-></code> statements in its potential scope. However, this analysis is local and purely syntactic. The impact on compilation times is thus deemed to be minimal.</p>
   <p>Compilers that already do NRVO will enable it (or at least the required part of it) in all compilation modes. The proposal might even have a positive impact on compilation time, because such implementations will not have to check whether copy-initialization on the return type can be performed.</p>
   <h3 class="heading settled" data-level="3.3" id="trivial-temporaries"><span class="secno">3.3. </span><span class="content">What about trivially-copyable temporaries?</span><a class="self-link" href="#trivial-temporaries"></a></h3>
   <p>According to <a href="http://eel.is/c++draft/class.temporary">[class.temporary]</a>, the implementation is allowed to create a copy when the object of a trivially-copyable type is returned. That is also the case when the copied object participates in "guaranteed RVO" (C++17) or "guaranteed NRVO" (proposed). If the address of such an object is saved to a pointer variable, the pointer will become dangling on return from the function:</p>
<pre class="language-cpp highlight"><c- k>class</c-> <c- nc>A</c-> <c- p>{</c->
<c- k>public</c-><c- o>:</c->
  <c- n>A</c-><c- o>*</c-> <c- n>p</c-><c- p>;</c->
  <c- n>A</c-><c- p>()</c-> <c- o>:</c-> <c- n>p</c-><c- p>(</c-><c- k>this</c-><c- p>)</c-> <c- p>{}</c->
<c- p>}</c->

<c- n>A</c-> <c- n>rvo</c-><c- p>()</c-> <c- p>{</c->
  <c- k>return</c-> <c- n>A</c-><c- p>();</c->
<c- p>}</c->
<c- n>A</c-> <c- n>x</c-> <c- o>=</c-> <c- n>rvo</c-><c- p>();</c->   <c- c1>// a.p may be dangling</c->

<c- n>A</c-><c- o>*</c-> <c- n>q</c-><c- p>{};</c->
<c- n>A</c-> <c- nf>nrvo</c-><c- p>()</c-> <c- p>{</c->
  <c- n>A</c-> <c- n>y</c-> <c- o>=</c-> <c- n>A</c-><c- p>();</c->
  <c- n>q</c-> <c- o>=</c-> <c- o>&amp;</c-><c- n>y</c-><c- p>;</c->
  <c- k>return</c-> <c- n>y</c-><c- p>;</c->
<c- p>}</c->
<c- n>A</c-> <c- n>z</c-> <c- o>=</c-> <c- n>nrvo</c-><c- p>();</c->  <c- c1>// z.p may be dangling</c->
               <c- c1>// q may be dangling</c->
</pre>
   <p>Changing <a href="http://eel.is/c++draft/class.temporary">[class.temporary]</a> and prohibiting such temporaries would cause ABI breakage, and is infeasible.</p>
   <h3 class="heading settled" data-level="3.4" id="term"><span class="secno">3.4. </span><span class="content">Is "named return object" a good term choice?</span><a class="self-link" href="#term"></a></h3>
   <blockquote class="issue" id="issue-913101d7"><a class="self-link" href="#issue-913101d7"></a> "<a data-link-type="abstract-op" href="#abstract-opdef-named-return-object" id="ref-for-abstract-opdef-named-return-object③">Named return object</a>" may not be the best term for our purposes. </blockquote>
   <p>It is a mixture of two terms:</p>
   <ul>
    <li data-md>
     <p>On the one hand, the object subject to NRVO optimization is called a "named return value". However, the term does not belong to the standard. And strictly speaking, a variable names an object, not a value.</p>
    <li data-md>
     <p>On the other hand, if we allow to shorten "result object of the function call expression" to "returned object" or "return object", then we could say that the variable in question "names the return object". To be precise, it is not an object <em>named</em> by something, it is a variable <em>naming</em> the return object.</p>
   </ul>
   <p>None of those choices is perfect. We could potentially find a better one. Alternatively, the proposed changes could be reworded in a way that does not require the term "named return object".</p>
   <h2 class="heading settled" data-level="4" id="alternatives"><span class="secno">4. </span><span class="content">Alternative solutions</span><a class="self-link" href="#alternatives"></a></h2>
   <h3 class="heading settled" data-level="4.1" id="existing-features"><span class="secno">4.1. </span><span class="content">Implement similar functionality using existing features</span><a class="self-link" href="#existing-features"></a></h3>
   <p>We can implement similar functionality, with cooperation from the returned object type, in some cases.</p>
   <p>Suppose the <code class="highlight"><c- n>widget</c-></code> class defines the following constructor, among others:</p>
<pre class="language-cpp highlight"><c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-><c- p>...</c-> <c- n>Args</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>invocable</c-><c- o>&lt;</c-><c- n>widget</c-><c- o>&amp;></c-> <c- n>Func</c-><c- o>></c->
<c- n>widget</c-><c- p>(</c-><c- n>Args</c-><c- o>&amp;&amp;</c-><c- p>...</c-> <c- n>args</c-><c- p>,</c-> <c- n>Func</c-><c- o>&amp;&amp;</c-> <c- n>func</c-><c- p>)</c->
  <c- o>:</c-> <c- n>widget</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>forward</c-><c- o>&lt;</c-><c- n>Args</c-><c- o>></c-><c- p>(</c-><c- n>args</c-><c- p>)...)</c->
  <c- p>{</c-> <c- n>std</c-><c- o>::</c-><c- n>invoke</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>forward</c-><c- o>&lt;</c-><c- n>Func</c-><c- o>></c-><c- p>(</c-><c- n>func</c-><c- p>)),</c-> <c- o>*</c-><c- k>this</c-><c- p>);</c-> <c- p>}</c->
</pre>
   <p>We can then use it to observe the result object of a prvalue through a reference before returning it:</p>
<pre class="language-cpp highlight"><c- n>widget</c-> <c- nf>setup_widget</c-><c- p>(</c-><c- b>int</c-> <c- n>x</c-><c- p>)</c-> <c- p>{</c->
  <c- b>int</c-> <c- n>y</c-> <c- o>=</c-> <c- n>process</c-><c- p>(</c-><c- n>x</c-><c- p>);</c->

  <c- k>return</c-> <c- n>widget</c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- p>[</c-><c- o>&amp;</c-><c- p>](</c-><c- n>widget</c-><c- o>&amp;</c-> <c- n>w</c-><c- p>)</c-> <c- p>{</c->
    <c- n>w</c-><c- p>.</c-><c- n>set_y</c-><c- p>(</c-><c- n>y</c-><c- p>);</c->
  <c- p>});</c->
<c- p>}</c->
</pre>
   <p>However, it requires cooperation from <code class="highlight"><c- n>widget</c-></code> and breaks when some of its other constructors accept an invocable parameter. We cannot implement this functionality in general.</p>
   <h3 class="heading settled" data-level="4.2" id="more-nrvo"><span class="secno">4.2. </span><span class="content">Guarantee NRVO in more cases</span><a class="self-link" href="#more-nrvo"></a></h3>
<pre class="language-cpp highlight"><c- k>class</c-> <c- nc>builder</c-> <c- p>{</c->
<c- k>public</c-><c- o>:</c->
  <c- n>builder</c-><c- p>();</c->
  <c- n>widget</c-> <c- nf>build</c-><c- p>();</c->
  <c- n>widget</c-> <c- nf>rebuild</c-><c- p>();</c->
  …
<c- p>};</c->

<c- n>widget</c-> <c- nf>foo</c-><c- p>()</c-> <c- p>{</c->
  <c- n>builder</c-> <c- n>b</c-><c- p>;</c->
  <c- n>widget</c-> <c- n>w</c-> <c- o>=</c-> <c- n>b</c-><c- p>.</c-><c- n>build</c-><c- p>();</c->
  <c- k>if</c-> <c- p>(</c->…<c- p>)</c-> <c- k>return</c-> <c- n>b</c-><c- p>.</c-><c- n>rebuild</c-><c- p>();</c->
  <c- k>return</c-> <c- n>w</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>NRVO will <strong>not</strong> be guaranteed for <code class="highlight"><c- n>w</c-></code>, according to this proposal. Meanwhile, one could say that it could be guaranteed: if the condition is true, then we could arrange it so that <code class="highlight"><c- n>w</c-></code> (which is stored as the return object) is destroyed before <code class="highlight"><c- n>b</c-><c- p>.</c-><c- n>rebuild</c-><c- p>()</c-></code> is called.</p>
   <p>However, what if <code class="highlight"><c- n>build</c-></code> saves a pointer to the returned object, which is then used in <code class="highlight"><c- n>rebuild</c-></code>? Then the <code class="highlight"><c- n>b</c-><c- p>.</c-><c- n>rebuild</c-><c- p>()</c-></code> call will try to reach for <code class="highlight"><c- n>w</c-></code>, which will lead to undefined behavior.</p>
   <p>While the compiler can in some cases analyze the control flow and usage patterns (usually after inlining is performed), this is impossible in general. (This is why a previous attempt at guaranteeing NRVO was shut down, see <a data-link-type="biblio" href="#biblio-cwg2278">[CWG2278]</a>.) The limitations of the proposed solution describe the cases where correctness can always be guaranteed without overhead and non-local reasoning.</p>
   <h3 class="heading settled" data-level="4.3" id="explicit-mark"><span class="secno">4.3. </span><span class="content">Require an explicit mark for named return objects</span><a class="self-link" href="#explicit-mark"></a></h3>
   <p>As an alternative, <a data-link-type="abstract-op" href="#abstract-opdef-named-return-object" id="ref-for-abstract-opdef-named-return-object④">named return objects</a> could require a specific attribute or a mark of some sort in order to be eligible for guaranteed copy elision:</p>
<pre class="language-cpp highlight"><c- n>widget</c-> <c- nf>setup_widget</c-><c- p>(</c-><c- b>int</c-> <c- n>x</c-><c- p>)</c-> <c- p>{</c->
  <c- k>auto</c-> <c- n>w</c-> <c- o>=</c-> <c- n>widget</c-><c- p>(</c-><c- n>x</c-><c- p>)</c-> <c- p>[[</c-><c- n>nrvo</c-><c- p>]];</c->
  <c- n>w</c-><c- p>.</c-><c- n>set_x</c-><c- p>(</c-><c- n>x</c-><c- p>);</c->
  <c- k>return</c-> <c- n>w</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>The benefit of requiring the mark is that the compiler would not have to determine for each local variable whether it could be a named return object. However, the cost of the compile-time checks is deemed to be low, while there would be some language complexity cost associated with the mark.</p>
   <h3 class="heading settled" data-level="4.4" id="alias-expressions"><span class="secno">4.4. </span><span class="content">Alias expressions</span><a class="self-link" href="#alias-expressions"></a></h3>
   <p>Alias expressions would be a new type of expression. An <dfn data-dfn-type="abstract-op" data-export id="abstract-opdef-alias-expression">alias expression<a class="self-link" href="#abstract-opdef-alias-expression"></a></dfn> would accept a prvalue, execute a block, providing that block a "magical" reference to the result object of that prvalue, and the alias expression would itself be a prvalue with the original result object:</p>
<pre class="language-cpp highlight"><c- n>widget</c-> <c- nf>setup_widget</c-><c- p>(</c-><c- b>int</c-> <c- n>x</c-><c- p>)</c-> <c- p>{</c->
  <c- k>return</c-> <c- k>using</c-> <c- p>(</c-><c- n>w</c-> <c- o>=</c-> <c- n>widget</c-><c- p>())</c-> <c- p>{</c->
    <c- n>w</c-><c- p>.</c-><c- n>set_x</c-><c- p>(</c-><c- n>x</c-><c- p>);</c->
  <c- p>};</c->
<c- p>}</c->
</pre>
   <p>Such a construct would require more wording and special cases on the behavior of the "magical" reference <code class="highlight"><c- n>w</c-></code> and the underlying object. It would be prohibited to <code class="highlight"><c- k>return</c-></code> from inside the block of the alias expression. More importantly, alias expressions would introduce the precedent of an expression that contains statements, which has issues with a lot of the standard. And as with <a href="#explicit-mark">explicit marks</a>, it introduces more syntax, which the proposed solution avoids.</p>
   <p>Alias expressions could also be used to get rid of copies in places other than the return expressions, e.g. when passing a function argument by value:</p>
<pre class="language-cpp highlight"><c- b>void</c-> <c- nf>consume_widget</c-><c- p>(</c-><c- n>widget</c-><c- p>);</c->

<c- b>void</c-> <c- nf>test</c-><c- p>(</c-><c- b>int</c-> <c- n>x</c-><c- p>)</c-> <c- p>{</c->
  <c- n>consume_widget</c-><c- p>(</c-><c- k>using</c-> <c- p>(</c-><c- n>w</c-> <c- o>=</c-> <c- n>widget</c-><c- p>())</c-> <c- p>{</c->
    <c- n>w</c-><c- p>.</c-><c- n>set_x</c-><c- p>(</c-><c- n>x</c-><c- p>);</c->
  <c- p>});</c->
<c- p>}</c->
</pre>
   <p>The proposed solution can be used with an immediately invoked lambda expression to perform the same task:</p>
<pre class="language-cpp highlight"><c- b>void</c-> <c- nf>consume_widget</c-><c- p>(</c-><c- n>widget</c-><c- p>);</c->

<c- b>void</c-> <c- nf>test</c-><c- p>(</c-><c- b>int</c-> <c- n>x</c-><c- p>)</c-> <c- p>{</c->
  <c- n>consume_widget</c-><c- p>([</c-><c- o>&amp;</c-><c- p>]</c-> <c- p>{</c->
    <c- n>widget</c-> <c- n>w</c-><c- p>;</c->
    <c- n>w</c-><c- p>.</c-><c- n>set_x</c-><c- p>(</c-><c- n>x</c-><c- p>);</c->
    <c- k>return</c-> <c- n>w</c-><c- p>;</c->
  <c- p>}());</c->
<c- p>}</c->
</pre>
   <h2 class="heading settled" data-level="5" id="future-work"><span class="secno">5. </span><span class="content">Future work</span><a class="self-link" href="#future-work"></a></h2>
   <h3 class="heading settled" data-level="5.1" id="more-elision"><span class="secno">5.1. </span><span class="content">Guarantee some other types of copy elision</span><a class="self-link" href="#more-elision"></a></h3>
   <p><a href="http://eel.is/c++draft/class.copy.elision#1">[class.copy.elision]/1</a> describes 4 cases where copy elision is allowed. Let us review whether it is feasible to guarantee copy elision in those cases:</p>
   <ul>
    <li data-md>
     <p>(1.1) is feasible to guarantee with the limitations described in this proposal, because such an "optimization" is always correct, does not introduce overhead and does not require non-local reasoning.</p>
    <li data-md>
     <p>(1.2) leads to an extra allocation in case the control flow escapes the scope before the throw-expression is executed. It would only be feasible to guarantee when the scope contains no other jump statements, and all the functions called are <code class="highlight"><c- k>noexcept</c-></code>. Those cases are deemed highly specific, but <strong>can</strong> be tackled in a separate proposal.</p>
    <li data-md>
     <p>(1.3) requires non-local reasoning and is therefore infeasible to guarantee.</p>
    <li data-md>
     <p>(1.4) covers two cases:</p>
     <ul>
      <li data-md>
       <p>When the throw-expression and the try-block reside in different functions. In this case copy elision requires non-local reasoning and is infeasible to guarantee.</p>
      <li data-md>
       <p>When they reside in the same function. Such code can be refactored so that this copy elision is unnecessary, unlike (1.1). This use case, if found beneficial enough, <strong>can</strong> be tackled in a separate proposal.</p>
     </ul>
   </ul>
   <h3 class="heading settled" data-level="5.2" id="disallowed-elision"><span class="secno">5.2. </span><span class="content">Guarantee currently disallowed types of copy elision</span><a class="self-link" href="#disallowed-elision"></a></h3>
   <p>Requiring copy elision in more cases than is currently allowed by the standard is a breaking change and is out of scope of this proposal. If another proposal that guarantees copy elision in more cases is accepted, those cases could also be reviewed for feasibility of guaranteed copy elision. This proposal will not be influenced by that future work.</p>
   <h3 class="heading settled" data-level="5.3" id="other-moves"><span class="secno">5.3. </span><span class="content">Reduce the number of moves performed in other cases</span><a class="self-link" href="#other-moves"></a></h3>
   <p>This proposal belongs to a group of proposals that aim to reduce the number of moves performed in C++ programs. Within that group, there are two subgroups:</p>
   <ul>
    <li data-md>
     <p>Some proposals allow to replace moves with operations that are yet cheaper than moves (known as relocation or destructive move): <a data-link-type="biblio" href="#biblio-n4158">[N4158]</a>, <a data-link-type="biblio" href="#biblio-p0023r0">[P0023R0]</a>, <a data-link-type="biblio" href="#biblio-p1144r4">[P1144R4]</a>.</p>
    <li data-md>
     <p>Other proposals aim to remove the need for moving altogether. This proposal, as well as <a data-link-type="biblio" href="#biblio-p0927r2">[P0927R2]</a>, belongs to that group.</p>
   </ul>
   <p>The problem solved by the current proposal is orthogonal to the problems dealt with by relocation proposals, as well as to the problem dealt with by P0927R2.</p>
   <p>The current proposal combines with <a data-link-type="biblio" href="#biblio-p0927r2">[P0927R2]</a> nicely. That proposal requires that the lazy parameter is only used once (and forwarded to another lazy parameter or to its final destination), while in some cases it may be desirable to acquire and use it for some time before forwarding. This proposal would allow to achieve it in a clean way, see the immediately invoked lambda expression example.</p>
   <p>The changes proposed by this proposal and <a data-link-type="biblio" href="#biblio-p0927r2">[P0927R2]</a>, combined, would allow to implement alias expressions (see the corresponding section) without any extra help from the language:</p>
<pre class="language-cpp highlight"><c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- p>,</c-> <c- n>invokable</c-><c- o>&lt;</c-><c- n>T</c-><c- o>&amp;></c-> <c- n>Func</c-><c- o>></c->
<c- n>T</c-> <c- n>also</c-><c- p>([]</c-> <c- o>-></c-> <c- n>T</c-> <c- n>value</c-><c- p>,</c-> <c- n>Func</c-><c- o>&amp;&amp;</c-> <c- n>func</c-><c- p>)</c-> <c- p>{</c->
  <c- n>T</c-> <c- n>computed</c-> <c- o>=</c-> <c- n>value</c-><c- p>();</c->
  <c- n>func</c-><c- p>(</c-><c- n>computed</c-><c- p>);</c->
  <c- k>return</c-> <c- n>computed</c-><c- p>;</c->
<c- p>}</c->

<c- b>void</c-> <c- n>consume_widget</c-><c- p>(</c-><c- n>widget</c-><c- p>);</c->

<c- b>void</c-> <c- nf>test</c-><c- p>(</c-><c- b>int</c-> <c- n>x</c-><c- p>)</c-> <c- p>{</c->
  <c- n>consume_widget</c-><c- p>(</c-><c- n>also</c-><c- p>(</c-><c- n>widget</c-><c- p>(</c-><c- n>x</c-><c- p>),</c-> <c- p>[</c-><c- o>&amp;</c-><c- p>](</c-><c- k>auto</c-><c- o>&amp;</c-> <c- n>w</c-><c- p>)</c-> <c- p>{</c->
    <c- n>w</c-><c- p>.</c-><c- n>set_x</c-><c- p>(</c-><c- n>x</c-><c- p>);</c->
  <c- p>}));</c->
<c- p>}</c->
</pre>
   <h2 class="heading settled" data-level="6" id="acknowledgements"><span class="secno">6. </span><span class="content">Acknowledgements</span><a class="self-link" href="#acknowledgements"></a></h2>
   <p>Thanks to Agustín Bergé, Arthur O’Dwyer, Krystian Stasiowski and everyone else who provided feedback on a draft of this proposal.</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="index"><span class="content">Index</span><a class="self-link" href="#index"></a></h2>
  <h3 class="no-num no-ref heading settled" id="index-defined-here"><span class="content">Terms defined by this specification</span><a class="self-link" href="#index-defined-here"></a></h3>
  <ul class="index">
   <li><a href="#abstract-opdef-alias-expression">alias expression</a><span>, in §4.4</span>
   <li><a href="#abstract-opdef-named-return-object">named return object</a><span>, in §2.2</span>
   <li><a href="#stmtreturnnamed">[stmt.return.named]</a><span>, in §2.2</span>
   <li><a href="#abstract-opdef-to-return-a-variable">to return a variable</a><span>, in §2.2</span>
  </ul>
  <h2 class="no-num no-ref heading settled" id="references"><span class="content">References</span><a class="self-link" href="#references"></a></h2>
  <h3 class="no-num no-ref heading settled" id="normative"><span class="content">Normative References</span><a class="self-link" href="#normative"></a></h3>
  <dl>
   <dt id="biblio-n4842">[N4842]
   <dd>Richard Smith. <a href="https://wg21.link/n4842">Working Draft, Standard for Programming Language C++</a>. 27 November 2019. URL: <a href="https://wg21.link/n4842">https://wg21.link/n4842</a>
  </dl>
  <h3 class="no-num no-ref heading settled" id="informative"><span class="content">Informative References</span><a class="self-link" href="#informative"></a></h3>
  <dl>
   <dt id="biblio-cwg2278">[CWG2278]
   <dd>Richard Smith. <a href="https://wg21.link/cwg2278">Copy elision in constant expressions reconsidered</a>. 27 June 2016. drafting. URL: <a href="https://wg21.link/cwg2278">https://wg21.link/cwg2278</a>
   <dt id="biblio-n4158">[N4158]
   <dd>Pablo Halpern. <a href="https://wg21.link/n4158">Destructive Move (Rev 1)</a>. 12 October 2014. URL: <a href="https://wg21.link/n4158">https://wg21.link/n4158</a>
   <dt id="biblio-p0023r0">[P0023R0]
   <dd>Denis Bider. <a href="https://wg21.link/p0023r0">Relocator: Efficiently moving objects</a>. 8 April 2016. URL: <a href="https://wg21.link/p0023r0">https://wg21.link/p0023r0</a>
   <dt id="biblio-p0135r0">[P0135R0]
   <dd>Richard Smith. <a href="https://wg21.link/p0135r0">Guaranteed copy elision through simplified value categories</a>. 27 September 2015. URL: <a href="https://wg21.link/p0135r0">https://wg21.link/p0135r0</a>
   <dt id="biblio-p0927r2">[P0927R2]
   <dd>James Dennett, Geoff Romer. <a href="https://wg21.link/p0927r2">Towards A (Lazy) Forwarding Mechanism for C++</a>. 5 October 2018. URL: <a href="https://wg21.link/p0927r2">https://wg21.link/p0927r2</a>
   <dt id="biblio-p1144r4">[P1144R4]
   <dd>Arthur O'Dwyer. <a href="https://wg21.link/p1144r4">Object relocation in terms of move plus destroy</a>. 17 June 2019. URL: <a href="https://wg21.link/p1144r4">https://wg21.link/p1144r4</a>
  </dl>
  <h2 class="no-num no-ref heading settled" id="issues-index"><span class="content">Issues Index</span><a class="self-link" href="#issues-index"></a></h2>
  <div style="counter-reset:issue">
   <div class="issue"> "<a data-link-type="abstract-op" href="#abstract-opdef-named-return-object">Named return object</a>" may not be the best term for our purposes. <a href="#issue-913101d7"> ↵ </a></div>
  </div>
  <aside class="dfn-panel" data-for="stmtreturnnamed">
   <b><a href="#stmtreturnnamed">#stmtreturnnamed</a></b><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-stmtreturnnamed">2.2. Proposed wording</a> <a href="#ref-for-stmtreturnnamed①">(2)</a> <a href="#ref-for-stmtreturnnamed②">(3)</a> <a href="#ref-for-stmtreturnnamed③">(4)</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="abstract-opdef-to-return-a-variable">
   <b><a href="#abstract-opdef-to-return-a-variable">#abstract-opdef-to-return-a-variable</a></b><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-abstract-opdef-to-return-a-variable">2. Proposed solution</a>
    <li><a href="#ref-for-abstract-opdef-to-return-a-variable①">2.2. Proposed wording</a> <a href="#ref-for-abstract-opdef-to-return-a-variable②">(2)</a> <a href="#ref-for-abstract-opdef-to-return-a-variable③">(3)</a> <a href="#ref-for-abstract-opdef-to-return-a-variable④">(4)</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="abstract-opdef-named-return-object">
   <b><a href="#abstract-opdef-named-return-object">#abstract-opdef-named-return-object</a></b><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-abstract-opdef-named-return-object">2.2. Proposed wording</a> <a href="#ref-for-abstract-opdef-named-return-object①">(2)</a> <a href="#ref-for-abstract-opdef-named-return-object②">(3)</a>
    <li><a href="#ref-for-abstract-opdef-named-return-object③">3.4. Is "named return object" a good term choice?</a>
    <li><a href="#ref-for-abstract-opdef-named-return-object④">4.3. Require an explicit mark for named return objects</a>
   </ul>
  </aside>
<script>/* script-dfn-panel */

document.body.addEventListener("click", function(e) {
    var queryAll = function(sel) { return [].slice.call(document.querySelectorAll(sel)); }
    // Find the dfn element or panel, if any, that was clicked on.
    var el = e.target;
    var target;
    var hitALink = false;
    while(el.parentElement) {
        if(el.tagName == "A") {
            // Clicking on a link in a <dfn> shouldn't summon the panel
            hitALink = true;
        }
        if(el.classList.contains("dfn-paneled")) {
            target = "dfn";
            break;
        }
        if(el.classList.contains("dfn-panel")) {
            target = "dfn-panel";
            break;
        }
        el = el.parentElement;
    }
    if(target != "dfn-panel") {
        // Turn off any currently "on" or "activated" panels.
        queryAll(".dfn-panel.on, .dfn-panel.activated").forEach(function(el){
            el.classList.remove("on");
            el.classList.remove("activated");
        });
    }
    if(target == "dfn" && !hitALink) {
        // open the panel
        var dfnPanel = document.querySelector(".dfn-panel[data-for='" + el.id + "']");
        if(dfnPanel) {
            dfnPanel.classList.add("on");
            var rect = el.getBoundingClientRect();
            dfnPanel.style.left = window.scrollX + rect.right + 5 + "px";
            dfnPanel.style.top = window.scrollY + rect.top + "px";
            var panelRect = dfnPanel.getBoundingClientRect();
            var panelWidth = panelRect.right - panelRect.left;
            if(panelRect.right > document.body.scrollWidth && (rect.left - (panelWidth + 5)) > 0) {
                // Reposition, because the panel is overflowing
                dfnPanel.style.left = window.scrollX + rect.left - (panelWidth + 5) + "px";
            }
        } else {
            console.log("Couldn't find .dfn-panel[data-for='" + el.id + "']");
        }
    } else if(target == "dfn-panel") {
        // Switch it to "activated" state, which pins it.
        el.classList.add("activated");
        el.style.left = null;
        el.style.top = null;
    }

});
</script>