r183637 - reverted test

Larisse Voufo lvoufo at google.com
Sun Jun 9 23:50:24 PDT 2013


Author: lvoufo
Date: Mon Jun 10 01:50:24 2013
New Revision: 183637

URL: http://llvm.org/viewvc/llvm-project?rev=183637&view=rev
Log:
reverted test

Added:
    cfe/trunk/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp
Modified:
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=183637&r1=183636&r2=183637&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Jun 10 01:50:24 2013
@@ -5121,6 +5121,130 @@ bool Sema::ICEConvertDiagnoser::match(Qu
                                  : T->isIntegralOrUnscopedEnumerationType();
 }
 
+static ExprResult
+diagnoseAmbiguousConversion(Sema &SemaRef, SourceLocation Loc, Expr *From,
+                            Sema::ContextualImplicitConverter &Converter,
+                            QualType T, UnresolvedSetImpl &ViableConversions) {
+
+  if (Converter.Suppress)
+    return ExprError();
+
+  Converter.diagnoseAmbiguous(SemaRef, Loc, T) << From->getSourceRange();
+  for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) {
+    CXXConversionDecl *Conv =
+        cast<CXXConversionDecl>(ViableConversions[I]->getUnderlyingDecl());
+    QualType ConvTy = Conv->getConversionType().getNonReferenceType();
+    Converter.noteAmbiguous(SemaRef, Conv, ConvTy);
+  }
+  return SemaRef.Owned(From);
+}
+
+static bool
+diagnoseNoViableConversion(Sema &SemaRef, SourceLocation Loc, Expr *&From,
+                           Sema::ContextualImplicitConverter &Converter,
+                           QualType T, bool HadMultipleCandidates,
+                           UnresolvedSetImpl &ExplicitConversions) {
+  if (ExplicitConversions.size() == 1 && !Converter.Suppress) {
+    DeclAccessPair Found = ExplicitConversions[0];
+    CXXConversionDecl *Conversion =
+        cast<CXXConversionDecl>(Found->getUnderlyingDecl());
+
+    // The user probably meant to invoke the given explicit
+    // conversion; use it.
+    QualType ConvTy = Conversion->getConversionType().getNonReferenceType();
+    std::string TypeStr;
+    ConvTy.getAsStringInternal(TypeStr, SemaRef.getPrintingPolicy());
+
+    Converter.diagnoseExplicitConv(SemaRef, Loc, T, ConvTy)
+        << FixItHint::CreateInsertion(From->getLocStart(),
+                                      "static_cast<" + TypeStr + ">(")
+        << FixItHint::CreateInsertion(
+               SemaRef.PP.getLocForEndOfToken(From->getLocEnd()), ")");
+    Converter.noteExplicitConv(SemaRef, Conversion, ConvTy);
+
+    // If we aren't in a SFINAE context, build a call to the
+    // explicit conversion function.
+    if (SemaRef.isSFINAEContext())
+      return true;
+
+    SemaRef.CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found);
+    ExprResult Result = SemaRef.BuildCXXMemberCallExpr(From, Found, Conversion,
+                                                       HadMultipleCandidates);
+    if (Result.isInvalid())
+      return true;
+    // Record usage of conversion in an implicit cast.
+    From = ImplicitCastExpr::Create(SemaRef.Context, Result.get()->getType(),
+                                    CK_UserDefinedConversion, Result.get(), 0,
+                                    Result.get()->getValueKind());
+  }
+  return false;
+}
+
+static bool recordConversion(Sema &SemaRef, SourceLocation Loc, Expr *&From,
+                             Sema::ContextualImplicitConverter &Converter,
+                             QualType T, bool HadMultipleCandidates,
+                             DeclAccessPair &Found) {
+  CXXConversionDecl *Conversion =
+      cast<CXXConversionDecl>(Found->getUnderlyingDecl());
+  SemaRef.CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found);
+
+  QualType ToType = Conversion->getConversionType().getNonReferenceType();
+  if (!Converter.SuppressConversion) {
+    if (SemaRef.isSFINAEContext())
+      return true;
+
+    Converter.diagnoseConversion(SemaRef, Loc, T, ToType)
+        << From->getSourceRange();
+  }
+
+  ExprResult Result = SemaRef.BuildCXXMemberCallExpr(From, Found, Conversion,
+                                                     HadMultipleCandidates);
+  if (Result.isInvalid())
+    return true;
+  // Record usage of conversion in an implicit cast.
+  From = ImplicitCastExpr::Create(SemaRef.Context, Result.get()->getType(),
+                                  CK_UserDefinedConversion, Result.get(), 0,
+                                  Result.get()->getValueKind());
+  return false;
+}
+
+static ExprResult finishContextualImplicitConversion(
+    Sema &SemaRef, SourceLocation Loc, Expr *From,
+    Sema::ContextualImplicitConverter &Converter) {
+  if (!Converter.match(From->getType()) && !Converter.Suppress)
+    Converter.diagnoseNoMatch(SemaRef, Loc, From->getType())
+        << From->getSourceRange();
+
+  return SemaRef.DefaultLvalueConversion(From);
+}
+
+static void
+collectViableConversionCandidates(Sema &SemaRef, Expr *From, QualType ToType,
+                                  UnresolvedSetImpl &ViableConversions,
+                                  OverloadCandidateSet &CandidateSet) {
+  for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) {
+    DeclAccessPair FoundDecl = ViableConversions[I];
+    NamedDecl *D = FoundDecl.getDecl();
+    CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext());
+    if (isa<UsingShadowDecl>(D))
+      D = cast<UsingShadowDecl>(D)->getTargetDecl();
+
+    CXXConversionDecl *Conv;
+    FunctionTemplateDecl *ConvTemplate;
+    if ((ConvTemplate = dyn_cast<FunctionTemplateDecl>(D)))
+      Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
+    else
+      Conv = cast<CXXConversionDecl>(D);
+
+    if (ConvTemplate)
+      SemaRef.AddTemplateConversionCandidate(
+          ConvTemplate, FoundDecl, ActingContext, From, ToType, CandidateSet);
+    else
+      SemaRef.AddConversionCandidate(Conv, FoundDecl, ActingContext, From,
+                                     ToType, CandidateSet);
+  }
+}
+
 /// \brief Attempt to convert the given expression to a type which is accepted
 /// by the given converter.
 ///
@@ -5148,7 +5272,8 @@ ExprResult Sema::PerformContextualImplic
   // Process placeholders immediately.
   if (From->hasPlaceholderType()) {
     ExprResult result = CheckPlaceholderExpr(From);
-    if (result.isInvalid()) return result;
+    if (result.isInvalid())
+      return result;
     From = result.take();
   }
 
@@ -5185,119 +5310,142 @@ ExprResult Sema::PerformContextualImplic
     return Owned(From);
 
   // Look for a conversion to an integral or enumeration type.
-  UnresolvedSet<4> ViableConversions;
+  UnresolvedSet<4>
+      ViableConversions; // These are *potentially* viable in C++1y.
   UnresolvedSet<4> ExplicitConversions;
   std::pair<CXXRecordDecl::conversion_iterator,
-            CXXRecordDecl::conversion_iterator> Conversions
-    = cast<CXXRecordDecl>(RecordTy->getDecl())->getVisibleConversionFunctions();
+            CXXRecordDecl::conversion_iterator> Conversions =
+      cast<CXXRecordDecl>(RecordTy->getDecl())->getVisibleConversionFunctions();
 
-  bool HadMultipleCandidates
-    = (std::distance(Conversions.first, Conversions.second) > 1);
+  bool HadMultipleCandidates =
+      (std::distance(Conversions.first, Conversions.second) > 1);
 
-  for (CXXRecordDecl::conversion_iterator
-         I = Conversions.first, E = Conversions.second; I != E; ++I) {
-    if (CXXConversionDecl *Conversion
-          = dyn_cast<CXXConversionDecl>((*I)->getUnderlyingDecl())) {
-      if (Converter.match(
-              Conversion->getConversionType().getNonReferenceType())) {
-        if (Conversion->isExplicit())
+  // To check that there is only one target type, in C++1y:
+  QualType ToType;
+  bool HasUniqueTargetType = true;
+
+  // Collect explicit or viable (potentially in C++1y) conversions.
+  for (CXXRecordDecl::conversion_iterator I = Conversions.first,
+                                          E = Conversions.second;
+       I != E; ++I) {
+    NamedDecl *D = (*I)->getUnderlyingDecl();
+    CXXConversionDecl *Conversion;
+    FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D);
+    if (ConvTemplate) {
+      if (getLangOpts().CPlusPlus1y)
+        Conversion = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
+      else
+        continue; // C++11 does not consider conversion operator templates(?).
+    } else
+      Conversion = cast<CXXConversionDecl>(D);
+
+    assert((!ConvTemplate || getLangOpts().CPlusPlus1y) &&
+           "Conversion operator templates are considered potentially "
+           "viable in C++1y");
+
+    QualType CurToType = Conversion->getConversionType().getNonReferenceType();
+    if (Converter.match(CurToType) || ConvTemplate) {
+
+      if (Conversion->isExplicit()) {
+        // FIXME: For C++1y, do we need this restriction?
+        // cf. diagnoseNoViableConversion()
+        if (!ConvTemplate)
           ExplicitConversions.addDecl(I.getDecl(), I.getAccess());
-        else
-          ViableConversions.addDecl(I.getDecl(), I.getAccess());
+      } else {
+        if (!ConvTemplate && getLangOpts().CPlusPlus1y) {
+          if (ToType.isNull())
+            ToType = CurToType.getUnqualifiedType();
+          else if (HasUniqueTargetType &&
+                   (CurToType.getUnqualifiedType() != ToType))
+            HasUniqueTargetType = false;
+        }
+        ViableConversions.addDecl(I.getDecl(), I.getAccess());
       }
     }
   }
 
-  // FIXME: Implement the C++11 rules!
-  switch (ViableConversions.size()) {
-  case 0:
-    if (ExplicitConversions.size() == 1 && !Converter.Suppress) {
-      DeclAccessPair Found = ExplicitConversions[0];
-      CXXConversionDecl *Conversion
-        = cast<CXXConversionDecl>(Found->getUnderlyingDecl());
-
-      // The user probably meant to invoke the given explicit
-      // conversion; use it.
-      QualType ConvTy
-        = Conversion->getConversionType().getNonReferenceType();
-      std::string TypeStr;
-      ConvTy.getAsStringInternal(TypeStr, getPrintingPolicy());
-
-      Converter.diagnoseExplicitConv(*this, Loc, T, ConvTy)
-        << FixItHint::CreateInsertion(From->getLocStart(),
-                                      "static_cast<" + TypeStr + ">(")
-        << FixItHint::CreateInsertion(PP.getLocForEndOfToken(From->getLocEnd()),
-                                      ")");
-      Converter.noteExplicitConv(*this, Conversion, ConvTy);
-
-      // If we aren't in a SFINAE context, build a call to the
-      // explicit conversion function.
-      if (isSFINAEContext())
+  if (getLangOpts().CPlusPlus1y) {
+    // C++1y [conv]p6:
+    // ... An expression e of class type E appearing in such a context
+    // is said to be contextually implicitly converted to a specified
+    // type T and is well-formed if and only if e can be implicitly
+    // converted to a type T that is determined as follows: E is searched
+    // for conversion functions whose return type is cv T or reference
+    // to cv T such that T is allowed by the context. There shall be
+    // exactly one such T.
+
+    // If no unique T is found:
+    if (ToType.isNull()) {
+      if (diagnoseNoViableConversion(*this, Loc, From, Converter, T,
+                                     HadMultipleCandidates,
+                                     ExplicitConversions))
         return ExprError();
+      return finishContextualImplicitConversion(*this, Loc, From, Converter);
+    }
 
-      CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found);
-      ExprResult Result = BuildCXXMemberCallExpr(From, Found, Conversion,
-                                                 HadMultipleCandidates);
-      if (Result.isInvalid())
+    // If more than one unique Ts are found:
+    if (!HasUniqueTargetType)
+      return diagnoseAmbiguousConversion(*this, Loc, From, Converter, T,
+                                         ViableConversions);
+
+    // If one unique T is found:
+    // First, build a candidate set from the previously recorded
+    // potentially viable conversions.
+    OverloadCandidateSet CandidateSet(Loc);
+    collectViableConversionCandidates(*this, From, ToType, ViableConversions,
+                                      CandidateSet);
+
+    // Then, perform overload resolution over the candidate set.
+    OverloadCandidateSet::iterator Best;
+    switch (CandidateSet.BestViableFunction(*this, Loc, Best)) {
+    case OR_Success: {
+      // Apply this conversion.
+      DeclAccessPair Found =
+          DeclAccessPair::make(Best->Function, Best->FoundDecl.getAccess());
+      if (recordConversion(*this, Loc, From, Converter, T,
+                           HadMultipleCandidates, Found))
         return ExprError();
-      // Record usage of conversion in an implicit cast.
-      From = ImplicitCastExpr::Create(Context, Result.get()->getType(),
-                                      CK_UserDefinedConversion,
-                                      Result.get(), 0,
-                                      Result.get()->getValueKind());
-    }
-
-    // We'll complain below about a non-integral condition type.
-    break;
-
-  case 1: {
-    // Apply this conversion.
-    DeclAccessPair Found = ViableConversions[0];
-    CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found);
-
-    CXXConversionDecl *Conversion
-      = cast<CXXConversionDecl>(Found->getUnderlyingDecl());
-    QualType ConvTy
-      = Conversion->getConversionType().getNonReferenceType();
-    if (!Converter.SuppressConversion) {
-      if (isSFINAEContext())
+      break;
+    }
+    case OR_Ambiguous:
+      return diagnoseAmbiguousConversion(*this, Loc, From, Converter, T,
+                                         ViableConversions);
+    case OR_No_Viable_Function:
+      if (diagnoseNoViableConversion(*this, Loc, From, Converter, T,
+                                     HadMultipleCandidates,
+                                     ExplicitConversions))
         return ExprError();
-
-      Converter.diagnoseConversion(*this, Loc, T, ConvTy)
-        << From->getSourceRange();
+    // fall through 'OR_Deleted' case.
+    case OR_Deleted:
+      // We'll complain below about a non-integral condition type.
+      break;
     }
+  } else {
+    switch (ViableConversions.size()) {
+    case 0: {
+      if (diagnoseNoViableConversion(*this, Loc, From, Converter, T,
+                                     HadMultipleCandidates,
+                                     ExplicitConversions))
+        return ExprError();
 
-    ExprResult Result = BuildCXXMemberCallExpr(From, Found, Conversion,
-                                               HadMultipleCandidates);
-    if (Result.isInvalid())
-      return ExprError();
-    // Record usage of conversion in an implicit cast.
-    From = ImplicitCastExpr::Create(Context, Result.get()->getType(),
-                                    CK_UserDefinedConversion,
-                                    Result.get(), 0,
-                                    Result.get()->getValueKind());
-    break;
-  }
-
-  default:
-    if (Converter.Suppress)
-      return ExprError();
-
-    Converter.diagnoseAmbiguous(*this, Loc, T) << From->getSourceRange();
-    for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) {
-      CXXConversionDecl *Conv
-        = cast<CXXConversionDecl>(ViableConversions[I]->getUnderlyingDecl());
-      QualType ConvTy = Conv->getConversionType().getNonReferenceType();
-      Converter.noteAmbiguous(*this, Conv, ConvTy);
+      // We'll complain below about a non-integral condition type.
+      break;
+    }
+    case 1: {
+      // Apply this conversion.
+      DeclAccessPair Found = ViableConversions[0];
+      if (recordConversion(*this, Loc, From, Converter, T,
+                           HadMultipleCandidates, Found))
+        return ExprError();
+      break;
+    }
+    default:
+      return diagnoseAmbiguousConversion(*this, Loc, From, Converter, T,
+                                         ViableConversions);
     }
-    return Owned(From);
   }
 
-  if (!Converter.match(From->getType()) && !Converter.Suppress)
-    Converter.diagnoseNoMatch(*this, Loc, From->getType())
-      << From->getSourceRange();
-
-  return DefaultLvalueConversion(From);
+  return finishContextualImplicitConversion(*this, Loc, From, Converter);
 }
 
 /// AddOverloadCandidate - Adds the given function to the set of

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=183637&r1=183636&r2=183637&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Mon Jun 10 01:50:24 2013
@@ -2842,7 +2842,6 @@ void Sema::InstantiateFunctionDefinition
   if (Function->isInvalidDecl() || Function->isDefined())
     return;
 
-
   // Never instantiate an explicit specialization except if it is a class scope
   // explicit specialization.
   if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization &&

Added: cfe/trunk/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp?rev=183637&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp (added)
+++ cfe/trunk/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp Mon Jun 10 01:50:24 2013
@@ -0,0 +1,157 @@
+// RUN: %clang_cc1 -std=c++11 -verify -fsyntax-only %s
+// RUN: %clang_cc1 -std=c++1y %s -verify -DCXX1Y
+
+// Explicit member declarations behave as in C++11.
+
+namespace n3323_example {
+
+  template <class T> class zero_init {
+  public:
+    zero_init() : val(static_cast<T>(0)) {}
+    zero_init(T val) : val(val) {}
+
+    operator T &() { return val; }     //@13
+    operator T() const { return val; } //@14
+
+  private:
+    T val;
+  };
+
+  void Delete() {
+    zero_init<int *> p;
+    p = new int(7);
+    delete p; //@23
+    delete (p + 0);
+    delete + p;
+  }
+
+  void Switch() {
+    zero_init<int> i;
+    i = 7;
+    switch (i) {} // @31
+    switch (i + 0) {}
+    switch (+i) {}
+  }
+}
+
+#ifdef CXX1Y
+#else
+//expected-error at 23 {{ambiguous conversion of delete expression of type 'zero_init<int *>' to a pointer}}
+//expected-note at 13 {{conversion to pointer type 'int *'}}
+//expected-note at 14 {{conversion to pointer type 'int *'}}
+//expected-error at 31 {{multiple conversions from switch condition type 'zero_init<int>' to an integral or enumeration type}}
+//expected-note at 13 {{conversion to integral type 'int'}}
+//expected-note at 14 {{conversion to integral type 'int'}}
+#endif
+
+namespace extended_examples {
+
+  struct A0 {
+    operator int();      // matching and viable
+  };
+
+  struct A1 {
+    operator int() &&;   // matching and not viable
+  };
+
+  struct A2 {
+    operator float();    // not matching
+  };
+
+  struct A3 {
+    template<typename T> operator T();  // not matching (ambiguous anyway)
+  };
+
+  struct A4 {
+    template<typename T> operator int();  // not matching (ambiguous anyway)
+  };
+
+  struct B1 {
+    operator int() &&;  // @70
+    operator int();     // @71  -- duplicate declaration with different qualifier is not allowed
+  };
+
+  struct B2 {
+    operator int() &&;  // matching but not viable
+    operator float();   // not matching
+  };
+
+  void foo(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, B2 b2) {
+    switch (a0) {}
+    switch (a1) {}     // @81 -- fails for different reasons
+    switch (a2) {}     // @82
+    switch (a3) {}     // @83
+    switch (a4) {}     // @84
+    switch (b2) {}     // @85 -- fails for different reasons
+  }
+}
+
+//expected-error at 71 {{cannot overload a member function without a ref-qualifier with a member function with ref-qualifier '&&'}}
+//expected-note at 70 {{previous declaration is here}}
+//expected-error at 82 {{statement requires expression of integer type ('extended_examples::A2' invalid)}}
+//expected-error at 83 {{statement requires expression of integer type ('extended_examples::A3' invalid)}}
+//expected-error at 84 {{statement requires expression of integer type ('extended_examples::A4' invalid)}}
+
+#ifdef CXX1Y
+//expected-error at 81 {{statement requires expression of integer type ('extended_examples::A1' invalid)}}
+//expected-error at 85 {{statement requires expression of integer type ('extended_examples::B2' invalid)}}
+#else
+//expected-error at 81 {{cannot initialize object parameter of type 'extended_examples::A1' with an expression of type 'extended_examples::A1'}}
+//expected-error at 85 {{cannot initialize object parameter of type 'extended_examples::B2' with an expression of type 'extended_examples::B2'}}
+#endif
+
+namespace extended_examples_cxx1y {
+
+  struct A1 {   // leads to viable match in C++1y, and no viable match in C++11
+    operator int() &&;                  // matching but not viable
+    template <typename T> operator T(); // In C++1y: matching and viable, since disambiguated by L.100
+  };
+
+  struct A2 {   // leads to ambiguity in C++1y, and no viable match in C++11
+    operator int() &&;                    // matching but not viable
+    template <typename T> operator int(); // In C++1y: matching but ambiguous (disambiguated by L.105).
+  };
+
+  struct B1 {    // leads to one viable match in both cases
+    operator int();                  // matching and viable
+    template <typename T> operator T(); // In C++1y: matching and viable, since disambiguated by L.110
+  };
+
+  struct B2 {    // leads to one viable match in both cases
+    operator int();                  // matching and viable
+    template <typename T> operator int(); // In C++1y: matching but ambiguous, since disambiguated by L.115
+  };
+
+  struct C {    // leads to no match in both cases
+    operator float();                  // not matching
+    template <typename T> operator T(); // In C++1y: not matching, nor viable.
+  };
+
+  struct D {   // leads to viable match in C++1y, and no viable match in C++11
+    operator int() &&;                  // matching but not viable
+    operator float();                   // not matching
+    template <typename T> operator T(); // In C++1y: matching and viable, since disambiguated by L.125
+  };
+
+
+  void foo(A1 a1, A2 a2, B1 b1, B2 b2, C c, D d) {
+    switch (a1) {} // @138 --  should presumably call templated conversion operator to convert to int.
+    switch (a2) {} // @139
+    switch (b1) {}
+    switch (b2) {}
+    switch (c) {}  // @142
+    switch (d) {}  // @143
+  }
+}
+
+//expected-error at 142 {{statement requires expression of integer type ('extended_examples_cxx1y::C' invalid)}}
+
+#ifdef CXX1Y
+//expected-error at 139 {{statement requires expression of integer type ('extended_examples_cxx1y::A2' invalid)}}
+#else
+//expected-error at 138 {{cannot initialize object parameter of type 'extended_examples_cxx1y::A1' with an expression of type 'extended_examples_cxx1y::A1'}}
+//expected-error at 139 {{cannot initialize object parameter of type 'extended_examples_cxx1y::A2' with an expression of type 'extended_examples_cxx1y::A2'}}
+//expected-error at 143 {{cannot initialize object parameter of type 'extended_examples_cxx1y::D' with an expression of type 'extended_examples_cxx1y::D'}}
+#endif
+
+// FIXME: Extend with more examples, including [expr.const] and [expr.new].





More information about the cfe-commits mailing list