<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Jun 10, 2013 at 6:02 AM, Rafael Espíndola <span dir="ltr"><<a href="mailto:rafael.espindola@gmail.com" target="_blank">rafael.espindola@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div class="im">On 10 June 2013 02:50, Larisse Voufo <<a href="mailto:lvoufo@google.com">lvoufo@google.com</a>> wrote:<br>
> Author: lvoufo<br>
> Date: Mon Jun 10 01:50:24 2013<br>
> New Revision: 183637<br>
><br>
> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=183637&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=183637&view=rev</a><br>
> Log:<br>
> reverted test<br>
<br>
</div>There is a lot more in here than in 183636. Was this an accidental commit?<br></blockquote><div> </div><div style>Yes and No. The commit was not accidental. The message, "reverted test", was accidental. </div>
<div style>I tried to clarify that with another commit, under revision <span style="font-family:arial,sans-serif;font-size:13px">r183639.</span></div><div style><span style="font-family:arial,sans-serif;font-size:13px"><br>
</span></div><div style><span style="font-family:arial,sans-serif;font-size:13px">I was trying my first commits last night, using git-svn, and was running into unforeseen difficulties using "git svn dcommit". </span><span style="font-size:13px;font-family:arial,sans-serif">The instructions at </span><a href="http://llvm.org/docs/GettingStarted.html#for-developers-to-work-with-git-svn">http://llvm.org/docs/GettingStarted.html#for-developers-to-work-with-git-svn</a> did not seem to help. I am trying to resolve the issues.</div>
<div style><br></div><div style><span style="font-family:arial,sans-serif;font-size:13px"><br></span></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div class=""><div class="h5"><br>
><br>
> Added:<br>
> cfe/trunk/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp<br>
> Modified:<br>
> cfe/trunk/lib/Sema/SemaOverload.cpp<br>
> cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp<br>
><br>
> Modified: cfe/trunk/lib/Sema/SemaOverload.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=183637&r1=183636&r2=183637&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=183637&r1=183636&r2=183637&view=diff</a><br>
> ==============================================================================<br>
> --- cfe/trunk/lib/Sema/SemaOverload.cpp (original)<br>
> +++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Jun 10 01:50:24 2013<br>
> @@ -5121,6 +5121,130 @@ bool Sema::ICEConvertDiagnoser::match(Qu<br>
> : T->isIntegralOrUnscopedEnumerationType();<br>
> }<br>
><br>
> +static ExprResult<br>
> +diagnoseAmbiguousConversion(Sema &SemaRef, SourceLocation Loc, Expr *From,<br>
> + Sema::ContextualImplicitConverter &Converter,<br>
> + QualType T, UnresolvedSetImpl &ViableConversions) {<br>
> +<br>
> + if (Converter.Suppress)<br>
> + return ExprError();<br>
> +<br>
> + Converter.diagnoseAmbiguous(SemaRef, Loc, T) << From->getSourceRange();<br>
> + for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) {<br>
> + CXXConversionDecl *Conv =<br>
> + cast<CXXConversionDecl>(ViableConversions[I]->getUnderlyingDecl());<br>
> + QualType ConvTy = Conv->getConversionType().getNonReferenceType();<br>
> + Converter.noteAmbiguous(SemaRef, Conv, ConvTy);<br>
> + }<br>
> + return SemaRef.Owned(From);<br>
> +}<br>
> +<br>
> +static bool<br>
> +diagnoseNoViableConversion(Sema &SemaRef, SourceLocation Loc, Expr *&From,<br>
> + Sema::ContextualImplicitConverter &Converter,<br>
> + QualType T, bool HadMultipleCandidates,<br>
> + UnresolvedSetImpl &ExplicitConversions) {<br>
> + if (ExplicitConversions.size() == 1 && !Converter.Suppress) {<br>
> + DeclAccessPair Found = ExplicitConversions[0];<br>
> + CXXConversionDecl *Conversion =<br>
> + cast<CXXConversionDecl>(Found->getUnderlyingDecl());<br>
> +<br>
> + // The user probably meant to invoke the given explicit<br>
> + // conversion; use it.<br>
> + QualType ConvTy = Conversion->getConversionType().getNonReferenceType();<br>
> + std::string TypeStr;<br>
> + ConvTy.getAsStringInternal(TypeStr, SemaRef.getPrintingPolicy());<br>
> +<br>
> + Converter.diagnoseExplicitConv(SemaRef, Loc, T, ConvTy)<br>
> + << FixItHint::CreateInsertion(From->getLocStart(),<br>
> + "static_cast<" + TypeStr + ">(")<br>
> + << FixItHint::CreateInsertion(<br>
> + SemaRef.PP.getLocForEndOfToken(From->getLocEnd()), ")");<br>
> + Converter.noteExplicitConv(SemaRef, Conversion, ConvTy);<br>
> +<br>
> + // If we aren't in a SFINAE context, build a call to the<br>
> + // explicit conversion function.<br>
> + if (SemaRef.isSFINAEContext())<br>
> + return true;<br>
> +<br>
> + SemaRef.CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found);<br>
> + ExprResult Result = SemaRef.BuildCXXMemberCallExpr(From, Found, Conversion,<br>
> + HadMultipleCandidates);<br>
> + if (Result.isInvalid())<br>
> + return true;<br>
> + // Record usage of conversion in an implicit cast.<br>
> + From = ImplicitCastExpr::Create(SemaRef.Context, Result.get()->getType(),<br>
> + CK_UserDefinedConversion, Result.get(), 0,<br>
> + Result.get()->getValueKind());<br>
> + }<br>
> + return false;<br>
> +}<br>
> +<br>
> +static bool recordConversion(Sema &SemaRef, SourceLocation Loc, Expr *&From,<br>
> + Sema::ContextualImplicitConverter &Converter,<br>
> + QualType T, bool HadMultipleCandidates,<br>
> + DeclAccessPair &Found) {<br>
> + CXXConversionDecl *Conversion =<br>
> + cast<CXXConversionDecl>(Found->getUnderlyingDecl());<br>
> + SemaRef.CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found);<br>
> +<br>
> + QualType ToType = Conversion->getConversionType().getNonReferenceType();<br>
> + if (!Converter.SuppressConversion) {<br>
> + if (SemaRef.isSFINAEContext())<br>
> + return true;<br>
> +<br>
> + Converter.diagnoseConversion(SemaRef, Loc, T, ToType)<br>
> + << From->getSourceRange();<br>
> + }<br>
> +<br>
> + ExprResult Result = SemaRef.BuildCXXMemberCallExpr(From, Found, Conversion,<br>
> + HadMultipleCandidates);<br>
> + if (Result.isInvalid())<br>
> + return true;<br>
> + // Record usage of conversion in an implicit cast.<br>
> + From = ImplicitCastExpr::Create(SemaRef.Context, Result.get()->getType(),<br>
> + CK_UserDefinedConversion, Result.get(), 0,<br>
> + Result.get()->getValueKind());<br>
> + return false;<br>
> +}<br>
> +<br>
> +static ExprResult finishContextualImplicitConversion(<br>
> + Sema &SemaRef, SourceLocation Loc, Expr *From,<br>
> + Sema::ContextualImplicitConverter &Converter) {<br>
> + if (!Converter.match(From->getType()) && !Converter.Suppress)<br>
> + Converter.diagnoseNoMatch(SemaRef, Loc, From->getType())<br>
> + << From->getSourceRange();<br>
> +<br>
> + return SemaRef.DefaultLvalueConversion(From);<br>
> +}<br>
> +<br>
> +static void<br>
> +collectViableConversionCandidates(Sema &SemaRef, Expr *From, QualType ToType,<br>
> + UnresolvedSetImpl &ViableConversions,<br>
> + OverloadCandidateSet &CandidateSet) {<br>
> + for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) {<br>
> + DeclAccessPair FoundDecl = ViableConversions[I];<br>
> + NamedDecl *D = FoundDecl.getDecl();<br>
> + CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext());<br>
> + if (isa<UsingShadowDecl>(D))<br>
> + D = cast<UsingShadowDecl>(D)->getTargetDecl();<br>
> +<br>
> + CXXConversionDecl *Conv;<br>
> + FunctionTemplateDecl *ConvTemplate;<br>
> + if ((ConvTemplate = dyn_cast<FunctionTemplateDecl>(D)))<br>
> + Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());<br>
> + else<br>
> + Conv = cast<CXXConversionDecl>(D);<br>
> +<br>
> + if (ConvTemplate)<br>
> + SemaRef.AddTemplateConversionCandidate(<br>
> + ConvTemplate, FoundDecl, ActingContext, From, ToType, CandidateSet);<br>
> + else<br>
> + SemaRef.AddConversionCandidate(Conv, FoundDecl, ActingContext, From,<br>
> + ToType, CandidateSet);<br>
> + }<br>
> +}<br>
> +<br>
> /// \brief Attempt to convert the given expression to a type which is accepted<br>
> /// by the given converter.<br>
> ///<br>
> @@ -5148,7 +5272,8 @@ ExprResult Sema::PerformContextualImplic<br>
> // Process placeholders immediately.<br>
> if (From->hasPlaceholderType()) {<br>
> ExprResult result = CheckPlaceholderExpr(From);<br>
> - if (result.isInvalid()) return result;<br>
> + if (result.isInvalid())<br>
> + return result;<br>
> From = result.take();<br>
> }<br>
><br>
> @@ -5185,119 +5310,142 @@ ExprResult Sema::PerformContextualImplic<br>
> return Owned(From);<br>
><br>
> // Look for a conversion to an integral or enumeration type.<br>
> - UnresolvedSet<4> ViableConversions;<br>
> + UnresolvedSet<4><br>
> + ViableConversions; // These are *potentially* viable in C++1y.<br>
> UnresolvedSet<4> ExplicitConversions;<br>
> std::pair<CXXRecordDecl::conversion_iterator,<br>
> - CXXRecordDecl::conversion_iterator> Conversions<br>
> - = cast<CXXRecordDecl>(RecordTy->getDecl())->getVisibleConversionFunctions();<br>
> + CXXRecordDecl::conversion_iterator> Conversions =<br>
> + cast<CXXRecordDecl>(RecordTy->getDecl())->getVisibleConversionFunctions();<br>
><br>
> - bool HadMultipleCandidates<br>
> - = (std::distance(Conversions.first, Conversions.second) > 1);<br>
> + bool HadMultipleCandidates =<br>
> + (std::distance(Conversions.first, Conversions.second) > 1);<br>
><br>
> - for (CXXRecordDecl::conversion_iterator<br>
> - I = Conversions.first, E = Conversions.second; I != E; ++I) {<br>
> - if (CXXConversionDecl *Conversion<br>
> - = dyn_cast<CXXConversionDecl>((*I)->getUnderlyingDecl())) {<br>
> - if (Converter.match(<br>
> - Conversion->getConversionType().getNonReferenceType())) {<br>
> - if (Conversion->isExplicit())<br>
> + // To check that there is only one target type, in C++1y:<br>
> + QualType ToType;<br>
> + bool HasUniqueTargetType = true;<br>
> +<br>
> + // Collect explicit or viable (potentially in C++1y) conversions.<br>
> + for (CXXRecordDecl::conversion_iterator I = Conversions.first,<br>
> + E = Conversions.second;<br>
> + I != E; ++I) {<br>
> + NamedDecl *D = (*I)->getUnderlyingDecl();<br>
> + CXXConversionDecl *Conversion;<br>
> + FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D);<br>
> + if (ConvTemplate) {<br>
> + if (getLangOpts().CPlusPlus1y)<br>
> + Conversion = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());<br>
> + else<br>
> + continue; // C++11 does not consider conversion operator templates(?).<br>
> + } else<br>
> + Conversion = cast<CXXConversionDecl>(D);<br>
> +<br>
> + assert((!ConvTemplate || getLangOpts().CPlusPlus1y) &&<br>
> + "Conversion operator templates are considered potentially "<br>
> + "viable in C++1y");<br>
> +<br>
> + QualType CurToType = Conversion->getConversionType().getNonReferenceType();<br>
> + if (Converter.match(CurToType) || ConvTemplate) {<br>
> +<br>
> + if (Conversion->isExplicit()) {<br>
> + // FIXME: For C++1y, do we need this restriction?<br>
> + // cf. diagnoseNoViableConversion()<br>
> + if (!ConvTemplate)<br>
> ExplicitConversions.addDecl(I.getDecl(), I.getAccess());<br>
> - else<br>
> - ViableConversions.addDecl(I.getDecl(), I.getAccess());<br>
> + } else {<br>
> + if (!ConvTemplate && getLangOpts().CPlusPlus1y) {<br>
> + if (ToType.isNull())<br>
> + ToType = CurToType.getUnqualifiedType();<br>
> + else if (HasUniqueTargetType &&<br>
> + (CurToType.getUnqualifiedType() != ToType))<br>
> + HasUniqueTargetType = false;<br>
> + }<br>
> + ViableConversions.addDecl(I.getDecl(), I.getAccess());<br>
> }<br>
> }<br>
> }<br>
><br>
> - // FIXME: Implement the C++11 rules!<br>
> - switch (ViableConversions.size()) {<br>
> - case 0:<br>
> - if (ExplicitConversions.size() == 1 && !Converter.Suppress) {<br>
> - DeclAccessPair Found = ExplicitConversions[0];<br>
> - CXXConversionDecl *Conversion<br>
> - = cast<CXXConversionDecl>(Found->getUnderlyingDecl());<br>
> -<br>
> - // The user probably meant to invoke the given explicit<br>
> - // conversion; use it.<br>
> - QualType ConvTy<br>
> - = Conversion->getConversionType().getNonReferenceType();<br>
> - std::string TypeStr;<br>
> - ConvTy.getAsStringInternal(TypeStr, getPrintingPolicy());<br>
> -<br>
> - Converter.diagnoseExplicitConv(*this, Loc, T, ConvTy)<br>
> - << FixItHint::CreateInsertion(From->getLocStart(),<br>
> - "static_cast<" + TypeStr + ">(")<br>
> - << FixItHint::CreateInsertion(PP.getLocForEndOfToken(From->getLocEnd()),<br>
> - ")");<br>
> - Converter.noteExplicitConv(*this, Conversion, ConvTy);<br>
> -<br>
> - // If we aren't in a SFINAE context, build a call to the<br>
> - // explicit conversion function.<br>
> - if (isSFINAEContext())<br>
> + if (getLangOpts().CPlusPlus1y) {<br>
> + // C++1y [conv]p6:<br>
> + // ... An expression e of class type E appearing in such a context<br>
> + // is said to be contextually implicitly converted to a specified<br>
> + // type T and is well-formed if and only if e can be implicitly<br>
> + // converted to a type T that is determined as follows: E is searched<br>
> + // for conversion functions whose return type is cv T or reference<br>
> + // to cv T such that T is allowed by the context. There shall be<br>
> + // exactly one such T.<br>
> +<br>
> + // If no unique T is found:<br>
> + if (ToType.isNull()) {<br>
> + if (diagnoseNoViableConversion(*this, Loc, From, Converter, T,<br>
> + HadMultipleCandidates,<br>
> + ExplicitConversions))<br>
> return ExprError();<br>
> + return finishContextualImplicitConversion(*this, Loc, From, Converter);<br>
> + }<br>
><br>
> - CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found);<br>
> - ExprResult Result = BuildCXXMemberCallExpr(From, Found, Conversion,<br>
> - HadMultipleCandidates);<br>
> - if (Result.isInvalid())<br>
> + // If more than one unique Ts are found:<br>
> + if (!HasUniqueTargetType)<br>
> + return diagnoseAmbiguousConversion(*this, Loc, From, Converter, T,<br>
> + ViableConversions);<br>
> +<br>
> + // If one unique T is found:<br>
> + // First, build a candidate set from the previously recorded<br>
> + // potentially viable conversions.<br>
> + OverloadCandidateSet CandidateSet(Loc);<br>
> + collectViableConversionCandidates(*this, From, ToType, ViableConversions,<br>
> + CandidateSet);<br>
> +<br>
> + // Then, perform overload resolution over the candidate set.<br>
> + OverloadCandidateSet::iterator Best;<br>
> + switch (CandidateSet.BestViableFunction(*this, Loc, Best)) {<br>
> + case OR_Success: {<br>
> + // Apply this conversion.<br>
> + DeclAccessPair Found =<br>
> + DeclAccessPair::make(Best->Function, Best->FoundDecl.getAccess());<br>
> + if (recordConversion(*this, Loc, From, Converter, T,<br>
> + HadMultipleCandidates, Found))<br>
> return ExprError();<br>
> - // Record usage of conversion in an implicit cast.<br>
> - From = ImplicitCastExpr::Create(Context, Result.get()->getType(),<br>
> - CK_UserDefinedConversion,<br>
> - Result.get(), 0,<br>
> - Result.get()->getValueKind());<br>
> - }<br>
> -<br>
> - // We'll complain below about a non-integral condition type.<br>
> - break;<br>
> -<br>
> - case 1: {<br>
> - // Apply this conversion.<br>
> - DeclAccessPair Found = ViableConversions[0];<br>
> - CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found);<br>
> -<br>
> - CXXConversionDecl *Conversion<br>
> - = cast<CXXConversionDecl>(Found->getUnderlyingDecl());<br>
> - QualType ConvTy<br>
> - = Conversion->getConversionType().getNonReferenceType();<br>
> - if (!Converter.SuppressConversion) {<br>
> - if (isSFINAEContext())<br>
> + break;<br>
> + }<br>
> + case OR_Ambiguous:<br>
> + return diagnoseAmbiguousConversion(*this, Loc, From, Converter, T,<br>
> + ViableConversions);<br>
> + case OR_No_Viable_Function:<br>
> + if (diagnoseNoViableConversion(*this, Loc, From, Converter, T,<br>
> + HadMultipleCandidates,<br>
> + ExplicitConversions))<br>
> return ExprError();<br>
> -<br>
> - Converter.diagnoseConversion(*this, Loc, T, ConvTy)<br>
> - << From->getSourceRange();<br>
> + // fall through 'OR_Deleted' case.<br>
> + case OR_Deleted:<br>
> + // We'll complain below about a non-integral condition type.<br>
> + break;<br>
> }<br>
> + } else {<br>
> + switch (ViableConversions.size()) {<br>
> + case 0: {<br>
> + if (diagnoseNoViableConversion(*this, Loc, From, Converter, T,<br>
> + HadMultipleCandidates,<br>
> + ExplicitConversions))<br>
> + return ExprError();<br>
><br>
> - ExprResult Result = BuildCXXMemberCallExpr(From, Found, Conversion,<br>
> - HadMultipleCandidates);<br>
> - if (Result.isInvalid())<br>
> - return ExprError();<br>
> - // Record usage of conversion in an implicit cast.<br>
> - From = ImplicitCastExpr::Create(Context, Result.get()->getType(),<br>
> - CK_UserDefinedConversion,<br>
> - Result.get(), 0,<br>
> - Result.get()->getValueKind());<br>
> - break;<br>
> - }<br>
> -<br>
> - default:<br>
> - if (Converter.Suppress)<br>
> - return ExprError();<br>
> -<br>
> - Converter.diagnoseAmbiguous(*this, Loc, T) << From->getSourceRange();<br>
> - for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) {<br>
> - CXXConversionDecl *Conv<br>
> - = cast<CXXConversionDecl>(ViableConversions[I]->getUnderlyingDecl());<br>
> - QualType ConvTy = Conv->getConversionType().getNonReferenceType();<br>
> - Converter.noteAmbiguous(*this, Conv, ConvTy);<br>
> + // We'll complain below about a non-integral condition type.<br>
> + break;<br>
> + }<br>
> + case 1: {<br>
> + // Apply this conversion.<br>
> + DeclAccessPair Found = ViableConversions[0];<br>
> + if (recordConversion(*this, Loc, From, Converter, T,<br>
> + HadMultipleCandidates, Found))<br>
> + return ExprError();<br>
> + break;<br>
> + }<br>
> + default:<br>
> + return diagnoseAmbiguousConversion(*this, Loc, From, Converter, T,<br>
> + ViableConversions);<br>
> }<br>
> - return Owned(From);<br>
> }<br>
><br>
> - if (!Converter.match(From->getType()) && !Converter.Suppress)<br>
> - Converter.diagnoseNoMatch(*this, Loc, From->getType())<br>
> - << From->getSourceRange();<br>
> -<br>
> - return DefaultLvalueConversion(From);<br>
> + return finishContextualImplicitConversion(*this, Loc, From, Converter);<br>
> }<br>
><br>
> /// AddOverloadCandidate - Adds the given function to the set of<br>
><br>
> Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=183637&r1=183636&r2=183637&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=183637&r1=183636&r2=183637&view=diff</a><br>
> ==============================================================================<br>
> --- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)<br>
> +++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Mon Jun 10 01:50:24 2013<br>
> @@ -2842,7 +2842,6 @@ void Sema::InstantiateFunctionDefinition<br>
> if (Function->isInvalidDecl() || Function->isDefined())<br>
> return;<br>
><br>
> -<br>
> // Never instantiate an explicit specialization except if it is a class scope<br>
> // explicit specialization.<br>
> if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization &&<br>
><br>
> Added: cfe/trunk/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp?rev=183637&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp?rev=183637&view=auto</a><br>
> ==============================================================================<br>
> --- cfe/trunk/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp (added)<br>
> +++ cfe/trunk/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp Mon Jun 10 01:50:24 2013<br>
> @@ -0,0 +1,157 @@<br>
> +// RUN: %clang_cc1 -std=c++11 -verify -fsyntax-only %s<br>
> +// RUN: %clang_cc1 -std=c++1y %s -verify -DCXX1Y<br>
> +<br>
> +// Explicit member declarations behave as in C++11.<br>
> +<br>
> +namespace n3323_example {<br>
> +<br>
> + template <class T> class zero_init {<br>
> + public:<br>
> + zero_init() : val(static_cast<T>(0)) {}<br>
> + zero_init(T val) : val(val) {}<br>
> +<br>
> + operator T &() { return val; } //@13<br>
> + operator T() const { return val; } //@14<br>
> +<br>
> + private:<br>
> + T val;<br>
> + };<br>
> +<br>
> + void Delete() {<br>
> + zero_init<int *> p;<br>
> + p = new int(7);<br>
> + delete p; //@23<br>
> + delete (p + 0);<br>
> + delete + p;<br>
> + }<br>
> +<br>
> + void Switch() {<br>
> + zero_init<int> i;<br>
> + i = 7;<br>
> + switch (i) {} // @31<br>
> + switch (i + 0) {}<br>
> + switch (+i) {}<br>
> + }<br>
> +}<br>
> +<br>
> +#ifdef CXX1Y<br>
> +#else<br>
> +//expected-error@23 {{ambiguous conversion of delete expression of type 'zero_init<int *>' to a pointer}}<br>
> +//expected-note@13 {{conversion to pointer type 'int *'}}<br>
> +//expected-note@14 {{conversion to pointer type 'int *'}}<br>
> +//expected-error@31 {{multiple conversions from switch condition type 'zero_init<int>' to an integral or enumeration type}}<br>
> +//expected-note@13 {{conversion to integral type 'int'}}<br>
> +//expected-note@14 {{conversion to integral type 'int'}}<br>
> +#endif<br>
> +<br>
> +namespace extended_examples {<br>
> +<br>
> + struct A0 {<br>
> + operator int(); // matching and viable<br>
> + };<br>
> +<br>
> + struct A1 {<br>
> + operator int() &&; // matching and not viable<br>
> + };<br>
> +<br>
> + struct A2 {<br>
> + operator float(); // not matching<br>
> + };<br>
> +<br>
> + struct A3 {<br>
> + template<typename T> operator T(); // not matching (ambiguous anyway)<br>
> + };<br>
> +<br>
> + struct A4 {<br>
> + template<typename T> operator int(); // not matching (ambiguous anyway)<br>
> + };<br>
> +<br>
> + struct B1 {<br>
> + operator int() &&; // @70<br>
> + operator int(); // @71 -- duplicate declaration with different qualifier is not allowed<br>
> + };<br>
> +<br>
> + struct B2 {<br>
> + operator int() &&; // matching but not viable<br>
> + operator float(); // not matching<br>
> + };<br>
> +<br>
> + void foo(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, B2 b2) {<br>
> + switch (a0) {}<br>
> + switch (a1) {} // @81 -- fails for different reasons<br>
> + switch (a2) {} // @82<br>
> + switch (a3) {} // @83<br>
> + switch (a4) {} // @84<br>
> + switch (b2) {} // @85 -- fails for different reasons<br>
> + }<br>
> +}<br>
> +<br>
> +//expected-error@71 {{cannot overload a member function without a ref-qualifier with a member function with ref-qualifier '&&'}}<br>
> +//expected-note@70 {{previous declaration is here}}<br>
> +//expected-error@82 {{statement requires expression of integer type ('extended_examples::A2' invalid)}}<br>
> +//expected-error@83 {{statement requires expression of integer type ('extended_examples::A3' invalid)}}<br>
> +//expected-error@84 {{statement requires expression of integer type ('extended_examples::A4' invalid)}}<br>
> +<br>
> +#ifdef CXX1Y<br>
> +//expected-error@81 {{statement requires expression of integer type ('extended_examples::A1' invalid)}}<br>
> +//expected-error@85 {{statement requires expression of integer type ('extended_examples::B2' invalid)}}<br>
> +#else<br>
> +//expected-error@81 {{cannot initialize object parameter of type 'extended_examples::A1' with an expression of type 'extended_examples::A1'}}<br>
> +//expected-error@85 {{cannot initialize object parameter of type 'extended_examples::B2' with an expression of type 'extended_examples::B2'}}<br>
> +#endif<br>
> +<br>
> +namespace extended_examples_cxx1y {<br>
> +<br>
> + struct A1 { // leads to viable match in C++1y, and no viable match in C++11<br>
> + operator int() &&; // matching but not viable<br>
> + template <typename T> operator T(); // In C++1y: matching and viable, since disambiguated by L.100<br>
> + };<br>
> +<br>
> + struct A2 { // leads to ambiguity in C++1y, and no viable match in C++11<br>
> + operator int() &&; // matching but not viable<br>
> + template <typename T> operator int(); // In C++1y: matching but ambiguous (disambiguated by L.105).<br>
> + };<br>
> +<br>
> + struct B1 { // leads to one viable match in both cases<br>
> + operator int(); // matching and viable<br>
> + template <typename T> operator T(); // In C++1y: matching and viable, since disambiguated by L.110<br>
> + };<br>
> +<br>
> + struct B2 { // leads to one viable match in both cases<br>
> + operator int(); // matching and viable<br>
> + template <typename T> operator int(); // In C++1y: matching but ambiguous, since disambiguated by L.115<br>
> + };<br>
> +<br>
> + struct C { // leads to no match in both cases<br>
> + operator float(); // not matching<br>
> + template <typename T> operator T(); // In C++1y: not matching, nor viable.<br>
> + };<br>
> +<br>
> + struct D { // leads to viable match in C++1y, and no viable match in C++11<br>
> + operator int() &&; // matching but not viable<br>
> + operator float(); // not matching<br>
> + template <typename T> operator T(); // In C++1y: matching and viable, since disambiguated by L.125<br>
> + };<br>
> +<br>
> +<br>
> + void foo(A1 a1, A2 a2, B1 b1, B2 b2, C c, D d) {<br>
> + switch (a1) {} // @138 -- should presumably call templated conversion operator to convert to int.<br>
> + switch (a2) {} // @139<br>
> + switch (b1) {}<br>
> + switch (b2) {}<br>
> + switch (c) {} // @142<br>
> + switch (d) {} // @143<br>
> + }<br>
> +}<br>
> +<br>
> +//expected-error@142 {{statement requires expression of integer type ('extended_examples_cxx1y::C' invalid)}}<br>
> +<br>
> +#ifdef CXX1Y<br>
> +//expected-error@139 {{statement requires expression of integer type ('extended_examples_cxx1y::A2' invalid)}}<br>
> +#else<br>
> +//expected-error@138 {{cannot initialize object parameter of type 'extended_examples_cxx1y::A1' with an expression of type 'extended_examples_cxx1y::A1'}}<br>
> +//expected-error@139 {{cannot initialize object parameter of type 'extended_examples_cxx1y::A2' with an expression of type 'extended_examples_cxx1y::A2'}}<br>
> +//expected-error@143 {{cannot initialize object parameter of type 'extended_examples_cxx1y::D' with an expression of type 'extended_examples_cxx1y::D'}}<br>
> +#endif<br>
> +<br>
> +// FIXME: Extend with more examples, including [expr.const] and [expr.new].<br>
><br>
><br>
> _______________________________________________<br>
> cfe-commits mailing list<br>
> <a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
> <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</div></div></blockquote></div><br></div></div>