<!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>P1155R2: More implicit moves</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) {
		/* 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 > table {
		/* limit preferred width of table */
		max-width: 50em;
		margin-left: auto;
		margin-right: auto;
	}

	@media (min-width: 55em) {
		.overlarge {
			margin-left: calc(13px + 26.5rem - 50vw);
			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-left: calc(40em - 50vw) !important;
			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-left: 0 !important;
			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;
    }
  </style>
  <meta content="Bikeshed version 9c6ae748322940994300e90a77c34437364b40a6" name="generator">
  <link href="https://isocpp.org/favicon.ico" rel="icon">
<style>
hilite  {background-color: #FFFF00; font-weight: bold;}
ins  {background-color: #CCFFCC; text-decoration: underline;}
del  {background-color: #FFCACA; text-decoration: line-through;}
</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-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-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>
<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-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>
 <body class="h-entry">
  <div class="head">
   <p data-fill-with="logo"></p>
   <h1 class="p-name no-ref" id="title">P1155R2<br>More implicit moves</h1>
   <h2 class="no-num no-toc no-ref heading settled" id="subtitle"><span class="content">Published Proposal, <time class="dt-updated" datetime="2019-01-19">2019-01-19</time></span></h2>
   <div data-fill-with="spec-metadata">
    <dl>
     <dt>Authors:
     <dd>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:arthur.j.odwyer@gmail.com">Arthur O'Dwyer</a>
     <dd>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:davidmstone@google.com">David Stone</a>
     <dt>Audience:
     <dd>EWG
     <dt>Project:
     <dd>ISO/IEC JTC1/SC22/WG21 14882: Programming Language — C++
     <dt>Draft Revision:
     <dd>11
     <dt>Current Source:
     <dd><a href="https://github.com/Quuxplusone/draft/blob/gh-pages/d1155-more-implicit-moves.bs">github.com/Quuxplusone/draft/blob/gh-pages/d1155-more-implicit-moves.bs</a>
     <dt>Current:
     <dd><a href="https://rawgit.com/Quuxplusone/draft/gh-pages/d1155-more-implicit-moves.html">rawgit.com/Quuxplusone/draft/gh-pages/d1155-more-implicit-moves.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>Programmers expect <code class="highlight"><c- k>return</c-> <c- n>x</c-><c- p>;</c-></code> to trigger copy elision; or, at worst, to <i>implicitly move</i> from <code class="highlight"><c- n>x</c-></code> instead of copying. Occasionally, C++ violates their expectations and performs
  an expensive copy anyway.
  Based on our experience using Clang to diagnose unexpected copies in Chromium, Mozilla,
  and LibreOffice, we propose to change the standard so that these copies will be replaced with <i>implicit moves</i>.</p>
   <p>In a separate section, we tentatively propose a new special case to permit efficient codegen

  for <code class="highlight"><c- k>return</c-> <c- n>x</c-> <c- o>+=</c-> <c- n>y</c-></code>.</p>
   <p>This paper was presented as <a data-link-type="biblio" href="#biblio-rvoharder">[RVOHarder]</a> at CppCon 2018.</p>
  </div>
  <nav data-fill-with="table-of-contents" id="toc">
   <h2 class="no-num no-toc no-ref" id="contents">Table of Contents</h2>
   <ol class="toc" role="directory">
    <li><a href="#changelog"><span class="secno">1</span> <span class="content">Changelog</span></a>
    <li>
     <a href="#background"><span class="secno">2</span> <span class="content">Background</span></a>
     <ol class="toc">
      <li><a href="#throwing"><span class="secno">2.1</span> <span class="content">Throwing is pessimized</span></a>
      <li><a href="#conversion"><span class="secno">2.2</span> <span class="content">Non-constructor conversion is pessimized</span></a>
      <li><a href="#sinks"><span class="secno">2.3</span> <span class="content">By-value sinks are pessimized</span></a>
      <li><a href="#slicing"><span class="secno">2.4</span> <span class="content">Slicing is pessimized</span></a>
     </ol>
    <li><a href="#wording"><span class="secno">3</span> <span class="content">Proposed wording relative to N4762</span></a>
    <li><a href="#wording-alt"><span class="secno">4</span> <span class="content">Proposed wording relative to P0527r1</span></a>
    <li>
     <a href="#implementation"><span class="secno">5</span> <span class="content">Implementation experience</span></a>
     <ol class="toc">
      <li><a href="#true-positives"><span class="secno">5.1</span> <span class="content">Plenitude of true positives</span></a>
      <li><a href="#false-positives"><span class="secno">5.2</span> <span class="content">Lack of false positives</span></a>
     </ol>
    <li><a href="#further"><span class="secno">6</span> <span class="content">Further proposal to handle assignment operators specially</span></a>
    <li><a href="#acknowledgments"><span class="secno">7</span> <span class="content">Acknowledgments</span></a>
    <li>
     <a href="#references"><span class="secno"></span> <span class="content">References</span></a>
     <ol class="toc">
      <li><a href="#informative"><span class="secno"></span> <span class="content">Informative References</span></a>
     </ol>
   </ol>
  </nav>
  <main>
   <h2 class="heading settled" data-level="1" id="changelog"><span class="secno">1. </span><span class="content">Changelog</span><a class="self-link" href="#changelog"></a></h2>
   <ul>
    <li data-md>
     <p>R2: Added discussion of <code class="highlight"><c- k>return</c-> <c- o>++</c-><c- n>x</c-></code>.</p>
    <li data-md>
     <p>R1: Added discussion of <code class="highlight"><c- k>return</c-> <c- n>x</c-> <c- o>+=</c-> <c- n>y</c-></code>.</p>
   </ul>
   <h2 class="heading settled" data-level="2" id="background"><span class="secno">2. </span><span class="content">Background</span><a class="self-link" href="#background"></a></h2>
   <p>Each version of C++ has improved the efficiency of returning objects by value. By the middle of the last
decade, copy elision was reliable (if not technically guaranteed) in situations like this:</p>
<pre class="language-c++ highlight"><c- n>Widget</c-> <c- nf>one</c-><c- p>()</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>Widget</c-><c- p>();</c->  <c- c1>// copy elision</c->
<c- p>}</c->
<c- n>Widget</c-> <c- nf>two</c-><c- p>()</c-> <c- p>{</c->
    <c- n>Widget</c-> <c- n>result</c-><c- p>;</c->
    <c- k>return</c-> <c- n>result</c-><c- p>;</c->  <c- c1>// copy elision</c->
<c- p>}</c->
</pre>
   <p>In C++11, a completely new feature was added: a change to overload resolution which I will call <em>implicit move</em>. Even when copy elision is impossible, the compiler is sometimes
required to <em>implicitly move</em> the <code class="highlight"><c- k>return</c-></code> statement’s operand into the result object:</p>
<pre class="language-c++ highlight"><c- n>std</c-><c- o>::</c-><c- n>shared_ptr</c-><c- o>&lt;</c-><c- n>Base</c-><c- o>></c-> <c- n>three</c-><c- p>()</c-> <c- p>{</c->
    <c- n>std</c-><c- o>::</c-><c- n>shared_ptr</c-><c- o>&lt;</c-><c- n>Base</c-><c- o>></c-> <c- n>result</c-><c- p>;</c->
    <c- k>return</c-> <c- n>result</c-><c- p>;</c->  <c- c1>// copy elision</c->
<c- p>}</c->
<c- n>std</c-><c- o>::</c-><c- n>shared_ptr</c-><c- o>&lt;</c-><c- n>Base</c-><c- o>></c-> <c- n>four</c-><c- p>()</c-> <c- p>{</c->
    <c- n>std</c-><c- o>::</c-><c- n>shared_ptr</c-><c- o>&lt;</c-><c- n>Derived</c-><c- o>></c-> <c- n>result</c-><c- p>;</c->
    <c- k>return</c-> <c- n>result</c-><c- p>;</c->  <c- c1>// no copy elision, but implicitly moved (not copied)</c->
<c- p>}</c->
</pre>
   <p>The wording for this optimization was amended by <a data-link-type="biblio" href="#biblio-cwg1579">[CWG1579]</a>. The current wording in <a href="http://eel.is/c++draft/class.copy.elision#3">[class.copy.elision]/3</a> says:</p>
   <blockquote>
    <p>In the following copy-initialization contexts, a move operation might be used instead of a copy operation:</p>
    <ul>
     <li data-md>
      <p>If the <em>expression</em> in a <code class="highlight"><c- k>return</c-></code> statement is a (possibly parenthesized) <em>id-expression</em> that
names an object with automatic storage duration declared in the body or <em>parameter-declaration-clause</em> of the innermost enclosing function or <em>lambda-expression</em>, or</p>
     <li data-md>
      <p>
       if the operand of a <em>throw-expression</em> is the name of a non-volatile automatic object
(other than a 
       <hilite>function</hilite>
        or catch-clause parameter) whose scope does not extend beyond
the end of the innermost enclosing <em>try-block</em> (if there is one),
      </p>
    </ul>
    <p>
     overload resolution to select the constructor for the copy is first performed as if the object were
designated by an rvalue. If the first overload resolution fails or was not performed, or if the type
of the first parameter of the selected 
     <hilite>constructor</hilite>
      is not an 
     <hilite>rvalue
reference</hilite>
      to 
     <hilite>the object’s</hilite>
      type
(possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue.
    </p>
   </blockquote>
   <p>The highlighted phrases above indicate places where the wording diverges from a naïve programmer’s intuition.
Consider the following <a href="https://godbolt.org/g/9n8cwh">examples</a>...</p>
   <h3 class="heading settled" data-level="2.1" id="throwing"><span class="secno">2.1. </span><span class="content">Throwing is pessimized</span><a class="self-link" href="#throwing"></a></h3>
   <p>
    Throwing is pessimized because of the highlighted word 
    <hilite>function</hilite>
     [parameter].
   </p>
<pre class="language-c++ highlight"><c- b>void</c-> <c- nf>five</c-><c- p>()</c-> <c- p>{</c->
    <c- n>Widget</c-> <c- n>w</c-><c- p>;</c->
    <c- n>throw</c-> <c- n>w</c-><c- p>;</c->  <c- c1>// non-guaranteed copy elision, but implicitly moved (never copied)</c->
<c- p>}</c->
<c- n>Widget</c-> <c- nf>six</c-><c- p>(</c-><c- n>Widget</c-> <c- n>w</c-><c- p>)</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>w</c-><c- p>;</c->  <c- c1>// no copy elision, but implicitly moved (never copied)</c->
<c- p>}</c->
<c- b>void</c-> <c- nf>seven</c-><c- p>(</c-><c- n>Widget</c-> <c- n>w</c-><c- p>)</c-> <c- p>{</c->
    <c- n>throw</c-> <c- n>w</c-><c- p>;</c->  <c- c1>// no copy elision, and no implicit move (the object is copied)</c->
<c- p>}</c->
</pre>
   <p class="note" role="note"><span>Note:</span> The comment in <code class="highlight"><c- n>seven</c-></code> matches the current Standard wording, and matches the behavior of GCC.
Most compilers (Clang 4.0.1+, MSVC 2015+, ICC 16.0.3+) already do this implicit move.</p>
   <h3 class="heading settled" data-level="2.2" id="conversion"><span class="secno">2.2. </span><span class="content">Non-constructor conversion is pessimized</span><a class="self-link" href="#conversion"></a></h3>
   <p>
    Non-constructor conversion is pessimized because of the highlighted word 
    <hilite>constructor</hilite>
    .
   </p>
<pre class="language-c++ highlight"><c- k>struct</c-> <c- n>From</c-> <c- p>{</c->
    <c- n>From</c-><c- p>(</c-><c- n>Widget</c-> <c- k>const</c-> <c- o>&amp;</c-><c- p>);</c->
    <c- n>From</c-><c- p>(</c-><c- n>Widget</c-><c- o>&amp;&amp;</c-><c- p>);</c->
<c- p>};</c->

<c- k>struct</c-> <c- n>To</c-> <c- p>{</c->
    <c- n>operator</c-> <c- n>Widget</c-><c- p>()</c-> <c- k>const</c-> <c- o>&amp;</c-><c- p>;</c->
    <c- n>operator</c-> <c- nf>Widget</c-><c- p>()</c-> <c- o>&amp;&amp;</c-><c- p>;</c->
<c- p>};</c->

<c- n>From</c-> <c- nf>eight</c-><c- p>()</c-> <c- p>{</c->
    <c- n>Widget</c-> <c- n>w</c-><c- p>;</c->
    <c- k>return</c-> <c- n>w</c-><c- p>;</c->  <c- c1>// no copy elision, but implicitly moved (never copied)</c->
<c- p>}</c->
<c- n>Widget</c-> <c- nf>nine</c-><c- p>()</c-> <c- p>{</c->
    <c- n>To</c-> <c- n>t</c-><c- p>;</c->
    <c- k>return</c-> <c- n>t</c-><c- p>;</c->  <c- c1>// no copy elision, and no implicit move (the object is copied)</c->
<c- p>}</c->
</pre>
   <h3 class="heading settled" data-level="2.3" id="sinks"><span class="secno">2.3. </span><span class="content">By-value sinks are pessimized</span><a class="self-link" href="#sinks"></a></h3>
   <p>
    By-value sinks are pessimized because of the highlighted phrase 
    <hilite>rvalue reference</hilite>
    .
   </p>
<pre class="language-c++ highlight"><c- k>struct</c-> <c- n>Fish</c-> <c- p>{</c->
    <c- n>Fish</c-><c- p>(</c-><c- n>Widget</c-> <c- k>const</c-> <c- o>&amp;</c-><c- p>);</c->
    <c- n>Fish</c-><c- p>(</c-><c- n>Widget</c-><c- o>&amp;&amp;</c-><c- p>);</c->
<c- p>};</c->

<c- k>struct</c-> <c- n>Fowl</c-> <c- p>{</c->
    <c- n>Fowl</c-><c- p>(</c-><c- n>Widget</c-><c- p>);</c->
<c- p>};</c->

<c- n>Fish</c-> <c- nf>ten</c-><c- p>()</c-> <c- p>{</c->
    <c- n>Widget</c-> <c- n>w</c-><c- p>;</c->
    <c- k>return</c-> <c- n>w</c-><c- p>;</c->  <c- c1>// no copy elision, but implicitly moved (never copied)</c->
<c- p>}</c->
<c- n>Fowl</c-> <c- nf>eleven</c-><c- p>()</c-> <c- p>{</c->
    <c- n>Widget</c-> <c- n>w</c-><c- p>;</c->
    <c- k>return</c-> <c- n>w</c-><c- p>;</c->  <c- c1>// no copy elision, and no implicit move (the Widget object is copied)</c->
<c- p>}</c->
</pre>
   <p class="note" role="note"><span>Note:</span> The comment in <code class="highlight"><c- n>eleven</c-></code> matches the current Standard wording, and matches the behavior of
Clang, ICC, and MSVC. One compiler (GCC 5.1+) already does this implicit move.</p>
   <h3 class="heading settled" data-level="2.4" id="slicing"><span class="secno">2.4. </span><span class="content">Slicing is pessimized</span><a class="self-link" href="#slicing"></a></h3>
   <p>
    Slicing is pessimized because of the highlighted phrase 
    <hilite>the object’s</hilite>
    .
   </p>
<pre class="language-c++ highlight"><c- n>std</c-><c- o>::</c-><c- n>shared_ptr</c-><c- o>&lt;</c-><c- n>Base</c-><c- o>></c-> <c- n>twelve</c-><c- p>()</c-> <c- p>{</c->
    <c- n>std</c-><c- o>::</c-><c- n>shared_ptr</c-><c- o>&lt;</c-><c- n>Derived</c-><c- o>></c-> <c- n>result</c-><c- p>;</c->
    <c- k>return</c-> <c- n>result</c-><c- p>;</c->  <c- c1>// no copy elision, but implicitly moved (never copied)</c->
<c- p>}</c->
<c- n>Base</c-> <c- n>thirteen</c-><c- p>()</c-> <c- p>{</c->
    <c- n>Derived</c-> <c- n>result</c-><c- p>;</c->
    <c- k>return</c-> <c- n>result</c-><c- p>;</c->  <c- c1>// no copy elision, and no implicit move (the object is copied)</c->
<c- p>}</c->
</pre>
   <p class="note" role="note"><span>Note:</span> The comment in <code class="highlight"><c- n>thirteen</c-></code> matches the current Standard wording, and matches the behavior
of Clang and MSVC. Some compilers (GCC 8.1+, ICC 18.0.0+) already do this implicit move.</p>
   <p>We propose to remove all four of these unnecessary limitations.</p>
   <h2 class="heading settled" data-level="3" id="wording"><span class="secno">3. </span><span class="content">Proposed wording relative to N4762</span><a class="self-link" href="#wording"></a></h2>
   <p>Modify <a href="http://eel.is/c++draft/class.copy.elision#3">[class.copy.elision]/3</a> as follows:</p>
   <blockquote>
    <p>In the following copy-initialization contexts, a move operation might be used instead of a copy operation:</p>
    <ul>
     <li data-md>
      <p>If the <em>expression</em> in a <code class="highlight"><c- k>return</c-></code> statement is a (possibly parenthesized) <em>id-expression</em> that
names an object with automatic storage duration declared in the body or <em>parameter-declaration-clause</em> of the innermost enclosing function or <em>lambda-expression</em>, or</p>
     <li data-md>
      <p>
       if the operand of a <em>throw-expression</em> is the name of a non-volatile automatic object
(other than a 
       <del>function or</del>
        catch-clause parameter) whose scope does not extend beyond
the end of the innermost enclosing <em>try-block</em> (if there is one),
      </p>
    </ul>
    <p>
     overload resolution to select the constructor for the copy is first performed as if the object were
designated by an rvalue. If the first overload resolution fails or was not performed, 
     <del>or if the type
of the first parameter of the selected constructor is not an rvalue reference to the object’s type
(possibly cv-qualified),</del>
      overload resolution is performed again, considering the object as an lvalue.
[<em>Note:</em> This two-stage overload resolution must be performed regardless of whether copy elision will occur.
It determines the constructor to be called if elision is not performed, and the selected constructor
must be accessible even if the call is elided. —<em>end note</em>]
    </p>
   </blockquote>
   <p class="note" role="note"><span>Note:</span> I believe that the two instances of the word "constructor" in the quoted note remain correct. They
refer to the constructor selected to initialize the result object, as the very last step of the conversion
sequence. This proposed change merely permits the conversion sequence to be longer than a single step; for
example, it might involve a derived-to-base conversion followed by a move-constructor, or a user-defined
conversion operator followed by a move-constructor. In either case, as far as the quoted note is concerned,
that ultimate move-constructor is the "constructor to be called," and indeed it must be accessible
even if elision is performed.</p>
   <h2 class="heading settled" data-level="4" id="wording-alt"><span class="secno">4. </span><span class="content">Proposed wording relative to P0527r1</span><a class="self-link" href="#wording-alt"></a></h2>
   <p>David Stone’s <a data-link-type="biblio" href="#biblio-p0527">[P0527]</a> "Implicitly move from rvalue references in return statements" proposes to
alter the current rules "references are never implicitly moved-from" and "catch-clause parameters
are never implicitly moved-from." It accomplishes this by significantly refactoring clause <a href="http://eel.is/c++draft/class.copy.elision#3">[class.copy.elision]/3</a>.</p>
   <p>In the case that <a data-link-type="biblio" href="#biblio-p0527">[P0527]</a>'s changes are adopted into C++2a, we propose to modify the new <a href="http://eel.is/c++draft/class.copy.elision#3">[class.copy.elision]/3</a> as follows:</p>
   <blockquote>
    <p>
     A <em>movable entity</em> is a non-volatile object or an rvalue reference to a non-volatile type,
in either case with automatic storage duration. 
     <del>The underlying type of a movable entity is
the type of the object or the referenced type, respectively.</del>
      In the following
copy-initialization contexts, a move operation might be used instead of a copy operation:
    </p>
    <ul>
     <li data-md>
      <p>If the <em>expression</em> in a <code class="highlight"><c- k>return</c-></code> statement is a (possibly parenthesized) <em>id-expression</em> that
names a movable entity declared in the body or <em>parameter-declaration-clause</em> of the innermost enclosing function or <em>lambda-expression</em>, or</p>
     <li data-md>
      <p>if the operand of a <em>throw-expression</em> is a (possibly parenthesized) <em>id-expression</em> that
names a movable entity whose scope does not extend beyond
the end of the innermost enclosing <em>try-block</em> (if there is one),</p>
    </ul>
    <p>
     overload resolution to select the constructor for the copy is first performed as if the entity were
designated by an rvalue. If the first overload resolution fails or was not performed, 
     <del>or if the type
of the first parameter of the selected constructor is not an rvalue reference to the (possibly cv-qualified)
underlying type of the movable entity,</del>
      overload resolution is performed again, considering the entity as an lvalue.
[<em>Note:</em> This two-stage overload resolution must be performed regardless of whether copy elision will occur.
It determines the constructor to be called if elision is not performed, and the selected constructor
must be accessible even if the call is elided. —<em>end note</em>]
    </p>
   </blockquote>
   <h2 class="heading settled" data-level="5" id="implementation"><span class="secno">5. </span><span class="content">Implementation experience</span><a class="self-link" href="#implementation"></a></h2>
   <p>This feature has effectively already been implemented in Clang since February 2018; see <a data-link-type="biblio" href="#biblio-d43322">[D43322]</a>.
Under the diagnostic option <code class="highlight"><c- o>-</c-><c- n>Wreturn</c-><c- o>-</c-><c- n>std</c-><c- o>-</c-><c- n>move</c-></code> (which is enabled as part of <code class="highlight"><c- o>-</c-><c- n>Wmove</c-></code>, <code class="highlight"><c- o>-</c-><c- n>Wmost</c-></code>, and <code class="highlight"><c- o>-</c-><c- n>Wall</c-></code>),
the compiler performs overload resolution according to <em>both</em> rules — the standard rule and also
a rule similar to the one proposed in this proposal. If the two resolutions produce different results,
then Clang emits a warning diagnostic explaining that the return value will not be implicitly moved and
suggesting that the programmer add an explicit <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>move</c-></code>.</p>
   <p>However, Clang does not diagnose the examples from <a href="#sinks">§1.3 By-value sinks</a>.</p>
   <h3 class="heading settled" data-level="5.1" id="true-positives"><span class="secno">5.1. </span><span class="content">Plenitude of true positives</span><a class="self-link" href="#true-positives"></a></h3>
   <p>These warning diagnostics have proven helpful on real code.
Many instances have been reported of code that is currently accidentally pessimized,
and which would become optimized (with no loss of correctness) if this proposal were adopted:</p>
   <ul>
    <li data-md>
     <p><a data-link-type="biblio" href="#biblio-sg14">[SG14]</a>: a clever trick to reduce code duplication by using conversion operators,
rather than converting constructors, turned out to cause unnecessary copying in a common use-case.</p>
    <li data-md>
     <p><a data-link-type="biblio" href="#biblio-chromium">[Chromium]</a>: a non-standard container library used <code class="highlight"><c- n>iterator</c-><c- o>::</c-><c- k>operator</c-> <c- n>const_iterator</c-><c- p>()</c-> <c- o>&amp;&amp;</c-></code> instead of <code class="highlight"><c- n>const_iterator</c-><c- o>::</c-><c- n>const_iterator</c-><c- p>(</c-><c- n>iterator</c-><c- o>&amp;&amp;</c-><c- p>)</c-></code>.
(The actual committed diff is <a href="https://chromium-review.googlesource.com/c/chromium/src/+/1025435">here</a>.)</p>
    <li data-md>
     <p><a data-link-type="biblio" href="#biblio-libreoffice">[LibreOffice]</a>: "An explicit std::move would be needed in the return statements, as there’s a
conversion from <code class="highlight"><c- n>VclPtrInstance</c-></code> to base class <code class="highlight"><c- n>VclPtr</c-></code> involved."</p>
   </ul>
   <p>However, we must note that about half of the true positives from the diagnostic are on code
like the following example, which is not affected by this proposal:</p>
<pre class="language-c++ highlight"><c- n>std</c-><c- o>::</c-><c- n>string</c-> <c- n>fourteen</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>string</c-><c- o>&amp;&amp;</c-> <c- n>s</c-><c- p>)</c-> <c- p>{</c->
    <c- n>s</c-> <c- o>+=</c-> <c- s>"foo"</c-><c- p>;</c->
    <c- k>return</c-> <c- n>s</c-><c- p>;</c->  <c- c1>// no copy elision, and no implicit move (the object is copied)</c->
<c- p>}</c->
</pre>
   <p>See <a data-link-type="biblio" href="#biblio-khronos">[Khronos]</a>, <a data-link-type="biblio" href="#biblio-folly">[Folly]</a>, and three of the four diffs in <a data-link-type="biblio" href="#biblio-chromium">[Chromium]</a>. <a data-link-type="biblio" href="#biblio-aws">[AWS]</a> is a particularly egregious variation. (The committed diff is <a href="https://github.com/aws/aws-sdk-cpp/commit/ded84836cd7bf15aa2375a6c1f7143f34d985df1#diff-2ce19b694bb11d0ff1676f740d32f98dL136">here</a>.)</p>
<pre class="language-c++ highlight"><c- n>std</c-><c- o>::</c-><c- n>string</c-> <c- n>fifteen</c-><c- p>()</c-> <c- p>{</c->
    <c- n>std</c-><c- o>::</c-><c- n>string</c-><c- o>&amp;&amp;</c-> <c- n>s</c-> <c- o>=</c-> <c- s>"hello world"</c-><c- p>;</c->
    <c- k>return</c-> <c- n>s</c-><c- p>;</c->  <c- c1>// no copy elision, and no implicit move (the object is copied)</c->
<c- p>}</c->
</pre>
   <p>Some number of programmers certainly expect a move here, and in fact <a data-link-type="biblio" href="#biblio-p0527">[P0527]</a> proposes
to implicitly move in both of these cases. This paper does not conflict with <a data-link-type="biblio" href="#biblio-p0527">[P0527]</a>,
and we provide <a href="#wording-alt">an alternative wording</a> for the case that <a data-link-type="biblio" href="#biblio-p0527">[P0527]</a> is adopted.</p>
   <h3 class="heading settled" data-level="5.2" id="false-positives"><span class="secno">5.2. </span><span class="content">Lack of false positives</span><a class="self-link" href="#false-positives"></a></h3>
   <p>In eleven months we have received a single "false positive" report (<a data-link-type="biblio" href="#biblio-mozilla">[Mozilla]</a>), which complained that the move-constructor suggested
by Clang was <em>not significantly more efficient</em> than the actually selected copy-constructor. The programmer preferred not
to add the suggested <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>move</c-></code> because the code ugliness was not worth the minor performance gain.
This proposal would give Mozilla that minor performance gain without the ugliness — the best of both worlds!</p>
   <p>We have never received any report that Clang’s suggested move would have been incorrect.</p>
   <h2 class="heading settled" data-level="6" id="further"><span class="secno">6. </span><span class="content">Further proposal to handle assignment operators specially</span><a class="self-link" href="#further"></a></h2>
   <p>Besides the cases of <code class="highlight"><c- k>return</c-> <c- n>x</c-></code> handled by this proposal, and the cases of <code class="highlight"><c- k>return</c-> <c- n>x</c-></code> handled by
David Stone’s <a data-link-type="biblio" href="#biblio-p0527">[P0527]</a>, there is one more extremely frequent case where a copy is done instead
of an implicit move or copy-elision.</p>
<pre class="language-c++ highlight"><c- n>std</c-><c- o>::</c-><c- n>string</c-> <c- n>sixteen</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>string</c-> <c- n>lhs</c-><c- p>,</c-> <c- k>const</c-> <c- n>std</c-><c- o>::</c-><c- n>string</c-><c- o>&amp;</c-> <c- n>rhs</c-><c- p>)</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>lhs</c-> <c- o>+=</c-> <c- n>rhs</c-><c- p>;</c->  <c- c1>// no copy elision, and no implicit move (the object is copied)</c->
<c- p>}</c->

<c- n>std</c-><c- o>::</c-><c- n>string</c-> <c- n>seventeen</c-><c- p>(</c-><c- k>const</c-> <c- n>std</c-><c- o>::</c-><c- n>string</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- k>const</c-> <c- n>std</c-><c- o>::</c-><c- n>string</c-><c- o>&amp;</c-> <c- n>rhs</c-><c- p>)</c-> <c- p>{</c->
    <c- n>std</c-><c- o>::</c-><c- n>string</c-> <c- n>result</c-> <c- o>=</c-> <c- n>lhs</c-><c- p>;</c->
    <c- k>return</c-> <c- n>result</c-> <c- o>+=</c-> <c- n>rhs</c-><c- p>;</c->  <c- c1>// no copy elision, and no implicit move (the object is copied)</c->
<c- p>}</c->
</pre>
   <p>For a real-world example of this kind of code, see GNU libstdc++'s <a data-link-type="biblio" href="#biblio-pr85671">[PR85671]</a>, where even
a standard library implementor fell into the trap of writing</p>
<pre class="language-c++ highlight"><c- n>path</c-> <c- n>operator</c-><c- o>/</c-><c- p>(</c-><c- k>const</c-> <c- n>path</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- k>const</c-> <c- n>path</c-><c- o>&amp;</c-> <c- n>rhs</c-><c- p>)</c-> <c- p>{</c->
    <c- n>path</c-> <c- n>result</c-><c- p>(</c-><c- n>lhs</c-><c- p>);</c->
    <c- k>return</c-> <c- n>result</c-> <c- o>/=</c-> <c- n>rhs</c-><c- p>;</c->  <c- c1>// no copy elision, and no implicit move (the object is copied)</c->
<c- p>}</c->
</pre>
   <p>We propose that — in order to make simple code like the above produce optimal codegen —<wbr>it would be reasonable to create a new special case permitting a (possibly parenthesized)
assignment operation to count as "return by name." This would require major surgery on <a href="http://eel.is/c++draft/class.copy.elision">[class.copy.elision]</a>.
Possibly the best approach would be to introduce a new term, such as "copy-elision candidate,"
something like this:</p>
   <blockquote>
    <p>
     When certain criteria are met, an implementation is allowed to omit the copy/move
construction of a class object, even if the constructor selected for the copy/move
operation and/or the destructor for the object have side effects. 
     <ins>Each such case
involves an expression, called the <i>candidate expression</i>, and a source object,
called the <i>copy elision candidate</i>.</ins>
    </p>
    <ul>
     <li data-md>
      <ins>In a <code class="highlight"><c- k>return</c-></code> statement with an <i>expression</i>, the candidate expression is the <i>expression</i>.</ins>
     <li data-md>
      <ins>In a <i>throw-expression</i>, the candidate expression is the operand of <code class="highlight"><c- k>throw</c-></code>.</ins>
    </ul>
    <ins>The copy elision candidate is computed from the candidate expression as follows:</ins>
    <ul>
     <li data-md>
      <ins>If the candidate expression is the (possibly parenthesized) name of a non-volatile
automatic object, then the copy elision candidate is that object.</ins>
     <li data-md>
      <ins>If the candidate expression is an <i>assignment-expression</i>, and the <i>logical-or-expression</i> on the left-hand side of the <i>assignment-operator</i> is
the (possibly parenthesized) name of a non-volatile automatic object,
and the type of the <i>assignment-expression</i> is a non-cv-qualified lvalue reference
to the type of the automatic object, then the copy elision candidate is the
automatic object.<br> [<i>Note:</i> This happens regardless of the actual behavior of the assignment operator
selected by overload resolution. The implementation essentially assumes that the
return value of any (possibly compound) assignment operator is a reference to
its left-hand operand. <i>—end note</i>]</ins>
     <li data-md>
      <ins>If the candidate expression is a <i>unary-expression</i> involving the operator <code class="highlight"><c- o>++</c-></code> or <code class="highlight"><c- o>--</c-></code>, and the operand <i>cast-expression</i> is
the (possibly parenthesized) name of a non-volatile automatic object,
and the type of the <i>unary-expression</i> is a non-cv-qualified lvalue reference
to the type of the automatic object, then the copy elision candidate is the
automatic object.</ins>
    </ul>
    <p>The elision of copy/move operations,
called copy elision, is permitted in the following circumstances
(which may be combined to eliminate multiple copies):</p>
    <ul>
     <li data-md>
      <p>
       in a <code class="highlight"><c- k>return</c-></code> statement in a function with a class return type, when 
       <del>the <i>expression</i> is the name of</del>
       <ins>the copy elision candidate is</ins>
        a non-volatile automatic
object (other than a function parameter or a variable introduced by the
exception-declaration of a handler (13.3)) with
the same type (ignoring cv-qualification) as the function return type,
the copy/move operation can be omitted by constructing 
       <del>the automatic object</del>
       <ins>the copy elision candidate object</ins>
        directly into the function call’s return object
      </p>
     <li data-md>
      <p>
       in a <i>throw-expression</i>, when the 
       <del>operand</del>
       <ins>copy elision candidate</ins>
        is the name of a non-volatile automatic object (other than a function or catch-clause parameter)
whose scope does not extend beyond the end of the innermost enclosing try-block (if there is one),
the copy/move operation from 
       <del>the operand</del>
       <ins>the copy elision candidate object</ins>
        to the exception object (13.1) can be omitted by constructing the automatic object
directly into the exception object
      </p>
    </ul>
    <ins>When copy elision occurs,</ins>
     the implementation treats the source and target
of the omitted copy/move operation as simply two different ways of referring
to the same object. If the first parameter of the selected constructor is an
rvalue reference to the object’s type, the destruction of that object occurs
when the target would have been destroyed;
otherwise, the destruction occurs at the later of the times
when the two objects would have been destroyed without the optimization. 
   </blockquote>
   <p>This would be a novel special case; as the "Note" says, this would essentially permit the
core language to assume that every overloaded <code class="highlight"><c- k>operator</c-><c- o>=</c-></code> and <code class="highlight"><c- k>operator</c->@<c- o>=</c-></code> which returns an
lvalue reference at all, returns an lvalue reference to <code class="highlight"><c- o>*</c-><c- k>this</c-></code>. It would be possible for
pathological code to observe the optimization happening:</p>
<pre class="language-c++ highlight"><c- k>struct</c-> <c- n>Observer</c-><c- p>;</c->
<c- k>struct</c-> <c- n>Observer</c-> <c- p>{</c->
    <c- k>static</c-> <c- b>int</c-> <c- n>k</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
    <c- k>static</c-> <c- n>Observer</c-> <c- n>global</c-><c- p>;</c->
    <c- b>int</c-> <c- n>i</c-><c- p>;</c->
    <c- n>explicit</c-> <c- nf>Observer</c-><c- p>(</c-><c- b>int</c-> <c- n>i</c-><c- p>)</c-> <c- o>:</c-> <c- n>i</c-><c- p>(</c-><c- n>i</c-><c- p>)</c-> <c- p>{}</c->
    <c- n>Observer</c-><c- p>(</c-><c- k>const</c-> <c- n>Observer</c-><c- o>&amp;</c-> <c- n>rhs</c-><c- p>)</c-> <c- o>:</c-> <c- n>i</c-><c- p>(</c-><c- o>++</c-><c- n>k</c-><c- p>)</c-> <c- p>{</c->
        <c- n>printf</c-><c- p>(</c-><c- s>"observed a copy from %d to %d"</c-><c- p>,</c-> <c- n>rhs</c-><c- p>.</c-><c- n>i</c-><c- p>,</c-> <c- n>i</c-><c- p>);</c->
    <c- p>}</c->
    <c- n>Observer</c-><c- p>(</c-><c- n>Observer</c-><c- o>&amp;&amp;</c-> <c- n>rhs</c-><c- p>)</c-> <c- o>:</c-> <c- n>i</c-><c- p>(</c-><c- o>++</c-><c- n>k</c-><c- p>)</c-> <c- p>{</c->
        <c- n>printf</c-><c- p>(</c-><c- s>"observed a move from %d to %d"</c-><c- p>,</c-> <c- n>rhs</c-><c- p>.</c-><c- n>i</c-><c- p>,</c-> <c- n>i</c-><c- p>);</c->
    <c- p>}</c->
    <c- n>Observer</c-><c- o>&amp;</c-> <c- n>operator</c-><c- o>=</c-><c- p>(</c-><c- k>const</c-> <c- n>Observer</c-><c- o>&amp;</c-> <c- n>rhs</c-><c- p>)</c-> <c- p>{</c->
        <c- n>i</c-> <c- o>=</c-> <c- n>rhs</c-><c- p>.</c-><c- n>i</c-> <c- o>+</c-> <c- mi>1</c-><c- p>;</c->
        <c- n>printf</c-><c- p>(</c-><c- s>"observed a copy-assign from %d to %d"</c-><c- p>,</c-> <c- n>rhs</c-><c- p>.</c-><c- n>i</c-><c- p>,</c-> <c- n>i</c-><c- p>);</c->
        <c- k>return</c-> <c- o>&amp;</c-><c- n>global</c-><c- p>;</c->  <c- c1>// pathological!</c->
    <c- p>}</c->
<c- p>};</c->
<c- n>Observer</c-> <c- n>Observer</c-><c- o>::</c-><c- n>global</c-><c- p>{</c-><c- mi>10</c-><c- p>};</c->
<c- n>Observer</c-> <c- nf>foo</c-><c- p>()</c-> <c- p>{</c->
    <c- n>Observer</c-> <c- n>x</c-><c- p>{</c-><c- mi>20</c-><c- p>};</c->
    <c- n>Observer</c-> <c- n>y</c-><c- p>{</c-><c- mi>30</c-><c- p>};</c->
    <c- k>return</c-> <c- n>x</c-> <c- o>=</c-> <c- n>y</c-><c- p>;</c->
<c- p>}</c->
<c- b>int</c-> <c- nf>main</c-><c- p>()</c-> <c- p>{</c->
    <c- n>Observer</c-> <c- n>o</c-> <c- o>=</c-> <c- n>foo</c-><c- p>();</c->
    <c- n>printf</c-><c- p>(</c-><c- s>"o.i is %d</c-><c- se>\n</c-><c- s>"</c-><c- p>,</c-> <c- n>o</c-><c- p>.</c-><c- n>i</c-><c- p>);</c->
<c- p>}</c->
</pre>
   <p>In C++17, the above code has this behavior:</p>
   <ul>
    <li data-md>
     <p><code class="highlight"><c- n>observed</c-> <c- n>a</c-> <c- n>copy</c-><c- o>-</c-><c- n>assign</c-> <c- n>from</c-> <c- mi>30</c-> <c- n>to</c-> <c- mi>31</c-></code>, then <code class="highlight"><c- n>observed</c-> <c- n>a</c-> <c- n>copy</c-> <c- n>from</c-> <c- mi>10</c-> <c- n>to</c-> <c- mi>1</c-></code>, then <code class="highlight"><c- n>o</c-><c- p>.</c-><c- n>i</c-> <c- n>is</c-> <c- mi>1</c-></code> (the behavior required by C++17, forbidden under the proposal)</p>
   </ul>
   <p>Under the "further proposal" sketched above, the code would instead have one of the following behaviors:</p>
   <ul>
    <li data-md>
     <p><code class="highlight"><c- n>observed</c-> <c- n>a</c-> <c- n>copy</c-><c- o>-</c-><c- n>assign</c-> <c- n>from</c-> <c- mi>30</c-> <c- n>to</c-> <c- mi>31</c-></code>, then <code class="highlight"><c- n>observed</c-> <c- n>a</c-> <c- n>move</c-> <c- n>from</c-> <c- mi>10</c-> <c- n>to</c-> <c- mi>1</c-></code>, then <code class="highlight"><c- n>o</c-><c- p>.</c-><c- n>i</c-> <c- n>is</c-> <c- mi>1</c-></code> (implicit move, permitted under the proposal)</p>
    <li data-md>
     <p><code class="highlight"><c- n>observed</c-> <c- n>a</c-> <c- n>copy</c-><c- o>-</c-><c- n>assign</c-> <c- n>from</c-> <c- mi>30</c-> <c- n>to</c-> <c- mi>31</c-></code>, then <code class="highlight"><c- n>o</c-><c- p>.</c-><c- n>i</c-> <c- n>is</c-> <c- mi>31</c-></code> (copy elision, permitted and encouraged under the proposal)</p>
   </ul>
   <h2 class="heading settled" data-level="7" id="acknowledgments"><span class="secno">7. </span><span class="content">Acknowledgments</span><a class="self-link" href="#acknowledgments"></a></h2>
   <ul>
    <li data-md>
     <p>Thanks to Lukas Bergdoll for his copious feedback.</p>
    <li data-md>
     <p>Thanks to David Stone for <a data-link-type="biblio" href="#biblio-p0527">[P0527]</a>, and for offering to shepherd P1155R0 at the San Diego WG21 meeting (November 2018).</p>
    <li data-md>
     <p>Thanks to Barry Revzin (see <a data-link-type="biblio" href="#biblio-revzin">[Revzin]</a>) for pointing out the "By-value sinks" case.</p>
   </ul>
  </main>
<script>
(function() {
  "use strict";
  var collapseSidebarText = '<span aria-hidden="true">←</span> '
                          + '<span>Collapse Sidebar</span>';
  var expandSidebarText   = '<span aria-hidden="true">→</span> '
                          + '<span>Pop Out Sidebar</span>';
  var tocJumpText         = '<span aria-hidden="true">↑</span> '
                          + '<span>Jump to Table of Contents</span>';

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

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

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

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

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

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


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

    tocNav.appendChild(toggle);
  }

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

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

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

})();
</script>
  <h2 class="no-num no-ref heading settled" id="references"><span class="content">References</span><a class="self-link" href="#references"></a></h2>
  <h3 class="no-num no-ref heading settled" id="informative"><span class="content">Informative References</span><a class="self-link" href="#informative"></a></h3>
  <dl>
   <dt id="biblio-aws">[AWS]
   <dd><a href="https://github.com/aws/aws-sdk-cpp/issues/847">Use const references to extend lifetime of temporaries</a>. April 2018. URL: <a href="https://github.com/aws/aws-sdk-cpp/issues/847">https://github.com/aws/aws-sdk-cpp/issues/847</a>
   <dt id="biblio-chromium">[Chromium]
   <dd><a href="https://bugs.chromium.org/p/chromium/issues/detail?id=832211">clean up and enable Wreturn-std-move</a>. April 2018. URL: <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=832211">https://bugs.chromium.org/p/chromium/issues/detail?id=832211</a>
   <dt id="biblio-cwg1579">[CWG1579]
   <dd>Jeffrey Yasskin. <a href="http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1579">Return by converting move constructor</a>. October 2012. URL: <a href="http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1579">http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1579</a>
   <dt id="biblio-d43322">[D43322]
   <dd>Arthur O'Dwyer. <a href="https://reviews.llvm.org/D43322">Diagnose cases of 'return x' that should be 'return std::move(x)' for efficiency</a>. February 2018. URL: <a href="https://reviews.llvm.org/D43322">https://reviews.llvm.org/D43322</a>
   <dt id="biblio-folly">[Folly]
   <dd><a href="https://github.com/facebook/folly/commit/b5105fc5581eef1af2a809b7a3a50ac820e572ae">fix -Wreturn-std-move errors</a>. April 2018. URL: <a href="https://github.com/facebook/folly/commit/b5105fc5581eef1af2a809b7a3a50ac820e572ae">https://github.com/facebook/folly/commit/b5105fc5581eef1af2a809b7a3a50ac820e572ae</a>
   <dt id="biblio-khronos">[Khronos]
   <dd><a href="https://github.com/KhronosGroup/SPIRV-Tools/issues/1521">Use std::move(str) suggested with -Wreturn-std-move</a>. April 2018. URL: <a href="https://github.com/KhronosGroup/SPIRV-Tools/issues/1521">https://github.com/KhronosGroup/SPIRV-Tools/issues/1521</a>
   <dt id="biblio-libreoffice">[LibreOffice]
   <dd>Stephan Bergmann. <a href="https://cgit.freedesktop.org/libreoffice/core/commit/?id=74b6e61dde64c5e24bffacda6f67dbf3d1fc7032">-Werror,-Wreturn-std-move (recent Clang trunk)</a>. April 2018. URL: <a href="https://cgit.freedesktop.org/libreoffice/core/commit/?id=74b6e61dde64c5e24bffacda6f67dbf3d1fc7032">https://cgit.freedesktop.org/libreoffice/core/commit/?id=74b6e61dde64c5e24bffacda6f67dbf3d1fc7032</a>
   <dt id="biblio-mozilla">[Mozilla]
   <dd><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1454848">Various '-Wreturn-std-move' build warnings with clang 7.0 (trunk), for cases where return invokes (cheap) string copy-constructor rather than move constructor</a>. April 2018. URL: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1454848">https://bugzilla.mozilla.org/show_bug.cgi?id=1454848</a>
   <dt id="biblio-p0527">[P0527]
   <dd>David Stone. <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0527r1.html">Implicitly move from rvalue references in return statements</a>. November 2017. URL: <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0527r1.html">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0527r1.html</a>
   <dt id="biblio-pr85671">[PR85671]
   <dd>Jonathan Wakely. <a href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85671">Lack of std::move() inside operator/ for std::filesystem::path</a>. May 2018. URL: <a href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85671">https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85671</a>
   <dt id="biblio-revzin">[Revzin]
   <dd>Barry Revzin; Howard Hinnant; Arthur O'Dwyer. <a href="https://groups.google.com/a/isocpp.org/d/msg/std-proposals/eeLS8vI05nM/_BP-8YTPDAAJ">std-proposals thread: By-value sinks</a>. August 2018. URL: <a href="https://groups.google.com/a/isocpp.org/d/msg/std-proposals/eeLS8vI05nM/_BP-8YTPDAAJ">https://groups.google.com/a/isocpp.org/d/msg/std-proposals/eeLS8vI05nM/_BP-8YTPDAAJ</a>
   <dt id="biblio-rvoharder">[RVOHarder]
   <dd>Arthur O'Dwyer. <a href="https://www.youtube.com/watch?v=hA1WNtNyNbo">RVO is Harder than it Looks (CppCon 2018)</a>. September 2018. URL: <a href="https://www.youtube.com/watch?v=hA1WNtNyNbo">https://www.youtube.com/watch?v=hA1WNtNyNbo</a>
   <dt id="biblio-sg14">[SG14]
   <dd>Arthur O'Dwyer. <a href="https://github.com/WG21-SG14/SG14/issues/125">inplace_function implicit conversion chooses copy over move</a>. February 2018. URL: <a href="https://github.com/WG21-SG14/SG14/issues/125">https://github.com/WG21-SG14/SG14/issues/125</a>
  </dl>