r177320 - Bring inheriting constructor implementation up-to-date with current defect

Richard Smith richard-llvm at metafoo.co.uk
Mon Mar 18 14:12:30 PDT 2013


Author: rsmith
Date: Mon Mar 18 16:12:30 2013
New Revision: 177320

URL: http://llvm.org/viewvc/llvm-project?rev=177320&view=rev
Log:
Bring inheriting constructor implementation up-to-date with current defect
reports, and implement implicit definition of inheriting constructors.
Remaining missing features: inheriting constructor templates, implicit
exception specifications for inheriting constructors, inheriting constructors
from dependent bases.

Added:
    cfe/trunk/test/CXX/special/class.inhctor/p1.cpp
    cfe/trunk/test/CXX/special/class.inhctor/p2.cpp
    cfe/trunk/test/CXX/special/class.inhctor/p4.cpp
    cfe/trunk/test/CXX/special/class.inhctor/p8.cpp
Modified:
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/test/CXX/special/class.inhctor/elsewhere.cpp
    cfe/trunk/test/CXX/special/class.inhctor/p3.cpp
    cfe/trunk/test/CXX/special/class.inhctor/p7.cpp
    cfe/trunk/test/CodeGenCXX/inheriting-constructor.cpp

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=177320&r1=177319&r2=177320&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Mon Mar 18 16:12:30 2013
@@ -2863,6 +2863,9 @@ public:
     assert(i < NumArgs && "Invalid argument number!");
     return arg_type_begin()[i];
   }
+  ArrayRef<QualType> getArgTypes() const {
+    return ArrayRef<QualType>(arg_type_begin(), arg_type_end());
+  }
 
   ExtProtoInfo getExtProtoInfo() const {
     ExtProtoInfo EPI;

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=177320&r1=177319&r2=177320&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Mar 18 16:12:30 2013
@@ -254,19 +254,20 @@ def note_using_decl_constructor_conflict
   "previous constructor">;
 def note_using_decl_constructor_conflict_previous_using : Note<
   "previously inherited here">;
+def warn_using_decl_constructor_ellipsis : Warning<
+  "inheriting constructor does not inherit ellipsis">,
+  InGroup<DiagGroup<"inherited-variadic-ctor">>;
+def note_using_decl_constructor_ellipsis : Note<
+  "constructor declared with ellipsis here">;
 def err_using_decl_can_not_refer_to_class_member : Error<
   "using declaration can not refer to class member">;
 def err_using_decl_can_not_refer_to_namespace : Error<
   "using declaration can not refer to namespace">;
 def err_using_decl_constructor : Error<
   "using declaration can not refer to a constructor">;
-def err_using_decl_constructor_unsupported : Error<
-  "inheriting constructors are not supported">;
-// FIXME: Replace the above error with this warning if support for
-//        inheriting constructors is implemented.
-//def warn_cxx98_compat_using_decl_constructor : Warning<
-//  "inheriting constructors are incompatible with C++98">,
-//  InGroup<CXX98Compat>, DefaultIgnore;
+def warn_cxx98_compat_using_decl_constructor : Warning<
+  "inheriting constructors are incompatible with C++98">,
+  InGroup<CXX98Compat>, DefaultIgnore;
 def err_using_decl_destructor : Error<
   "using declaration can not refer to a destructor">;
 def err_using_decl_template_id : Error<
@@ -1104,9 +1105,11 @@ def note_member_synthesized_at : Note<
   "implicit default %select{constructor|copy constructor|move constructor|copy "
   "assignment operator|move assignment operator|destructor}0 for %1 first "
   "required here">;
+def note_inhctor_synthesized_at : Note<
+  "inheriting constructor for %0 first required here">;
 def err_missing_default_ctor : Error<
-  "%select{|implicit default }0constructor for %1 must explicitly initialize "
-  "the %select{base class|member}2 %3 which does not have a default "
+  "%select{|implicit default |inheriting }0constructor for %1 must explicitly "
+  "initialize the %select{base class|member}2 %3 which does not have a default "
   "constructor">;
 
 def err_illegal_union_or_anon_struct_member : Error<
@@ -2274,8 +2277,8 @@ def err_uninitialized_member_for_assign
   "non-static %select{reference|const}1 member %2 can't use default "
   "assignment operator">;
 def err_uninitialized_member_in_ctor : Error<
-  "%select{|implicit default }0constructor for %1 must explicitly initialize "
-  "the %select{reference|const}2 member %3">;
+  "%select{|implicit default |inheriting }0constructor for %1 must explicitly "
+  "initialize the %select{reference|const}2 member %3">;
 def err_default_arg_makes_ctor_special : Error<
   "addition of default argument on redeclaration makes this constructor a "
   "%select{default|copy|move}0 constructor">;

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=177320&r1=177319&r2=177320&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Mar 18 16:12:30 2013
@@ -3597,6 +3597,11 @@ public:
   ImplicitExceptionSpecification
   ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD);
 
+  /// \brief Determine what sort of exception specification an inheriting
+  /// constructor of a class will have.
+  ImplicitExceptionSpecification
+  ComputeInheritingCtorExceptionSpec(CXXMethodDecl *MD);
+
   /// \brief Evaluate the implicit exception specification for a defaulted
   /// special member function.
   void EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD);
@@ -3649,11 +3654,15 @@ public:
   void AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,
                                      CXXDestructorDecl *Destructor);
 
-  /// \brief Declare all inherited constructors for the given class.
+  /// \brief Declare all inheriting constructors for the given class.
   ///
-  /// \param ClassDecl The class declaration into which the inherited
+  /// \param ClassDecl The class declaration into which the inheriting
   /// constructors will be added.
-  void DeclareInheritedConstructors(CXXRecordDecl *ClassDecl);
+  void DeclareInheritingConstructors(CXXRecordDecl *ClassDecl);
+
+  /// \brief Define the specified inheriting constructor.
+  void DefineInheritingConstructor(SourceLocation UseLoc,
+                                   CXXConstructorDecl *Constructor);
 
   /// \brief Declare the implicit copy constructor for the given class.
   ///

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=177320&r1=177319&r2=177320&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Mar 18 16:12:30 2013
@@ -2642,9 +2642,10 @@ Sema::BuildBaseInitializer(QualType Base
 }
 
 // Create a static_cast\<T&&>(expr).
-static Expr *CastForMoving(Sema &SemaRef, Expr *E) {
-  QualType ExprType = E->getType();
-  QualType TargetType = SemaRef.Context.getRValueReferenceType(ExprType);
+static Expr *CastForMoving(Sema &SemaRef, Expr *E, QualType T = QualType()) {
+  if (T.isNull()) T = E->getType();
+  QualType TargetType = SemaRef.BuildReferenceType(
+      T, /*SpelledAsLValue*/false, SourceLocation(), DeclarationName());
   SourceLocation ExprLoc = E->getLocStart();
   TypeSourceInfo *TargetLoc = SemaRef.Context.getTrivialTypeSourceInfo(
       TargetType, ExprLoc);
@@ -2659,7 +2660,8 @@ static Expr *CastForMoving(Sema &SemaRef
 enum ImplicitInitializerKind {
   IIK_Default,
   IIK_Copy,
-  IIK_Move
+  IIK_Move,
+  IIK_Inherit
 };
 
 static bool
@@ -2675,6 +2677,35 @@ BuildImplicitBaseInitializer(Sema &SemaR
   ExprResult BaseInit;
   
   switch (ImplicitInitKind) {
+  case IIK_Inherit: {
+    const CXXRecordDecl *Inherited =
+        Constructor->getInheritedConstructor()->getParent();
+    const CXXRecordDecl *Base = BaseSpec->getType()->getAsCXXRecordDecl();
+    if (Base && Inherited->getCanonicalDecl() == Base->getCanonicalDecl()) {
+      // C++11 [class.inhctor]p8:
+      //   Each expression in the expression-list is of the form
+      //   static_cast<T&&>(p), where p is the name of the corresponding
+      //   constructor parameter and T is the declared type of p.
+      SmallVector<Expr*, 16> Args;
+      for (unsigned I = 0, E = Constructor->getNumParams(); I != E; ++I) {
+        ParmVarDecl *PD = Constructor->getParamDecl(I);
+        ExprResult ArgExpr =
+            SemaRef.BuildDeclRefExpr(PD, PD->getType().getNonReferenceType(),
+                                     VK_LValue, SourceLocation());
+        if (ArgExpr.isInvalid())
+          return true;
+        Args.push_back(CastForMoving(SemaRef, ArgExpr.take(), PD->getType()));
+      }
+
+      InitializationKind InitKind = InitializationKind::CreateDirect(
+          Constructor->getLocation(), SourceLocation(), SourceLocation());
+      InitializationSequence InitSeq(SemaRef, InitEntity, InitKind,
+                                     Args.data(), Args.size());
+      BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, Args);
+      break;
+    }
+  }
+  // Fall through.
   case IIK_Default: {
     InitializationKind InitKind
       = InitializationKind::CreateDefault(Constructor->getLocation());
@@ -2897,7 +2928,8 @@ BuildImplicitMemberInitializer(Sema &Sem
     return false;
   }
 
-  assert(ImplicitInitKind == IIK_Default && "Unhandled implicit init kind!");
+  assert((ImplicitInitKind == IIK_Default || ImplicitInitKind == IIK_Inherit) &&
+         "Unhandled implicit init kind!");
 
   QualType FieldBaseElementType = 
     SemaRef.Context.getBaseElementType(Field->getType());
@@ -2988,6 +3020,8 @@ struct BaseAndFieldInfo {
       IIK = IIK_Copy;
     else if (Generated && Ctor->isMoveConstructor())
       IIK = IIK_Move;
+    else if (Ctor->getInheritedConstructor())
+      IIK = IIK_Inherit;
     else
       IIK = IIK_Default;
   }
@@ -2999,6 +3033,7 @@ struct BaseAndFieldInfo {
       return true;
       
     case IIK_Default:
+    case IIK_Inherit:
       return false;
     }
 
@@ -3226,7 +3261,7 @@ bool Sema::SetCtorInitializers(CXXConstr
       // If we're not generating the implicit copy/move constructor, then we'll
       // handle anonymous struct/union fields based on their individual
       // indirect fields.
-      if (F->isAnonymousStructOrUnion() && Info.IIK == IIK_Default)
+      if (F->isAnonymousStructOrUnion() && !Info.isImplicitCopyOrMove())
         continue;
           
       if (CollectFieldInitializer(*this, Info, F))
@@ -3235,7 +3270,7 @@ bool Sema::SetCtorInitializers(CXXConstr
     }
     
     // Beyond this point, we only consider default initialization.
-    if (Info.IIK != IIK_Default)
+    if (Info.isImplicitCopyOrMove())
       continue;
     
     if (IndirectFieldDecl *F = dyn_cast<IndirectFieldDecl>(*Mem)) {
@@ -4062,14 +4097,14 @@ void Sema::CheckCompletedCXXClass(CXXRec
     }
   }
 
-  // Declare inherited constructors. We do this eagerly here because:
-  // - The standard requires an eager diagnostic for conflicting inherited
+  // Declare inheriting constructors. We do this eagerly here because:
+  // - The standard requires an eager diagnostic for conflicting inheriting
   //   constructors from different classes.
   // - The lazy declaration of the other implicit constructors is so as to not
   //   waste space and performance on classes that are not meant to be
   //   instantiated (e.g. meta-functions). This doesn't apply to classes that
-  //   have inherited constructors.
-  DeclareInheritedConstructors(Record);
+  //   have inheriting constructors.
+  DeclareInheritingConstructors(Record);
 }
 
 /// Is the special member function which would be selected to perform the
@@ -4185,7 +4220,9 @@ computeImplicitExceptionSpec(Sema &S, So
   case Sema::CXXInvalid:
     break;
   }
-  llvm_unreachable("only special members have implicit exception specs");
+  assert(cast<CXXConstructorDecl>(MD)->getInheritedConstructor() &&
+         "only special members have implicit exception specs");
+  return S.ComputeInheritingCtorExceptionSpec(cast<CXXConstructorDecl>(MD));
 }
 
 static void
@@ -4194,10 +4231,7 @@ updateExceptionSpec(Sema &S, FunctionDec
   FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
   ExceptSpec.getEPI(EPI);
   const FunctionProtoType *NewFPT = cast<FunctionProtoType>(
-    S.Context.getFunctionType(FPT->getResultType(),
-                              ArrayRef<QualType>(FPT->arg_type_begin(),
-                                                 FPT->getNumArgs()),
-                              EPI));
+      S.Context.getFunctionType(FPT->getResultType(), FPT->getArgTypes(), EPI));
   FD->setType(QualType(NewFPT, 0));
 }
 
@@ -5644,10 +5678,7 @@ QualType Sema::CheckConstructorDeclarato
   EPI.TypeQuals = 0;
   EPI.RefQualifier = RQ_None;
   
-  return Context.getFunctionType(Context.VoidTy,
-                                 ArrayRef<QualType>(Proto->arg_type_begin(),
-                                                    Proto->getNumArgs()),
-                                 EPI);
+  return Context.getFunctionType(Context.VoidTy, Proto->getArgTypes(), EPI);
 }
 
 /// CheckConstructor - Checks a fully-formed constructor for
@@ -6519,9 +6550,7 @@ Decl *Sema::ActOnUsingDeclaration(Scope
     // C++11 inheriting constructors.
     Diag(Name.getLocStart(),
          getLangOpts().CPlusPlus11 ?
-           // FIXME: Produce warn_cxx98_compat_using_decl_constructor
-           //        instead once inheriting constructors work.
-           diag::err_using_decl_constructor_unsupported :
+           diag::warn_cxx98_compat_using_decl_constructor :
            diag::err_using_decl_constructor)
       << SS.getRange();
 
@@ -6545,7 +6574,7 @@ Decl *Sema::ActOnUsingDeclaration(Scope
   if (!TargetName)
     return 0;
 
-  // Warn about using declarations.
+  // Warn about access declarations.
   // TODO: store that the declaration was written without 'using' and
   // talk about access decls instead of using decls in the
   // diagnostics.
@@ -7471,6 +7500,13 @@ Sema::ComputeDefaultedDefaultCtorExcepti
   return ExceptSpec;
 }
 
+Sema::ImplicitExceptionSpecification
+Sema::ComputeInheritingCtorExceptionSpec(CXXMethodDecl *MD) {
+  ImplicitExceptionSpecification ExceptSpec(*this);
+  // FIXME: Compute the exception spec.
+  return ExceptSpec;
+}
+
 namespace {
 /// RAII object to register a special member as being currently declared.
 struct DeclaringSpecialMember {
@@ -7597,7 +7633,7 @@ void Sema::ActOnFinishDelayedMemberIniti
   CheckDelayedExplicitlyDefaultedMemberExceptionSpecs();
 }
 
-void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
+void Sema::DeclareInheritingConstructors(CXXRecordDecl *ClassDecl) {
   // We start with an initial pass over the base classes to collect those that
   // inherit constructors from. If there are none, we can forgo all further
   // processing.
@@ -7612,6 +7648,8 @@ void Sema::DeclareInheritedConstructors(
         // If we inherit constructors from anything that is dependent, just
         // abort processing altogether. We'll get another chance for the
         // instantiations.
+        // FIXME: We need to ensure that any call to a constructor of this class
+        // is considered instantiation-dependent in this case.
         return;
       }
       BasesToInheritFrom.push_back(Base->castAs<RecordType>());
@@ -7620,18 +7658,19 @@ void Sema::DeclareInheritedConstructors(
   if (BasesToInheritFrom.empty())
     return;
 
+  // FIXME: Constructor templates.
+
   // Now collect the constructors that we already have in the current class.
   // Those take precedence over inherited constructors.
-  // C++0x [class.inhctor]p3: [...] a constructor is implicitly declared [...]
+  // C++11 [class.inhctor]p3: [...] a constructor is implicitly declared [...]
   //   unless there is a user-declared constructor with the same signature in
   //   the class where the using-declaration appears.
   llvm::SmallSet<const Type *, 8> ExistingConstructors;
   for (CXXRecordDecl::ctor_iterator CtorIt = ClassDecl->ctor_begin(),
                                     CtorE = ClassDecl->ctor_end();
-       CtorIt != CtorE; ++CtorIt) {
+       CtorIt != CtorE; ++CtorIt)
     ExistingConstructors.insert(
         Context.getCanonicalType(CtorIt->getType()).getTypePtr());
-  }
 
   DeclarationName CreatedCtorName =
       Context.DeclarationNames.getCXXConstructorName(
@@ -7663,62 +7702,71 @@ void Sema::DeclareInheritedConstructors(
       SourceLocation UsingLoc = UD ? UD->getLocation() :
                                      ClassDecl->getLocation();
 
-      // C++0x [class.inhctor]p1: The candidate set of inherited constructors
-      //   from the class X named in the using-declaration consists of actual
-      //   constructors and notional constructors that result from the
-      //   transformation of defaulted parameters as follows:
-      //   - all non-template default constructors of X, and
+      // C++11 [class.inhctor]p1:
+      //   The candidate set of inherited constructors from the class X named in
+      //   the using-declaration consists of actual constructors and notional
+      //   constructors that result from the transformation of defaulted
+      //   parameters as follows:
+      //   - all non-template constructors of X, and
       //   - for each non-template constructor of X that has at least one
       //     parameter with a default argument, the set of constructors that
       //     results from omitting any ellipsis parameter specification and
       //     successively omitting parameters with a default argument from the
-      //     end of the parameter-type-list.
+      //     end of the parameter-type-list, and
+      // FIXME: ...also constructor templates.
       CXXConstructorDecl *BaseCtor = *CtorIt;
       bool CanBeCopyOrMove = BaseCtor->isCopyOrMoveConstructor();
       const FunctionProtoType *BaseCtorType =
           BaseCtor->getType()->getAs<FunctionProtoType>();
 
-      for (unsigned params = BaseCtor->getMinRequiredArguments(),
-                    maxParams = BaseCtor->getNumParams();
-           params <= maxParams; ++params) {
+      // Determine whether this would be a copy or move constructor for the
+      // derived class.
+      if (BaseCtorType->getNumArgs() >= 1 &&
+          BaseCtorType->getArgType(0)->isReferenceType() &&
+          Context.hasSameUnqualifiedType(
+            BaseCtorType->getArgType(0)->getPointeeType(),
+            Context.getTagDeclType(ClassDecl)))
+        CanBeCopyOrMove = true;
+
+      ArrayRef<QualType> ArgTypes(BaseCtorType->getArgTypes());
+      FunctionProtoType::ExtProtoInfo EPI = BaseCtorType->getExtProtoInfo();
+      // Core issue (no number yet): the ellipsis is always discarded.
+      if (EPI.Variadic) {
+        Diag(UsingLoc, diag::warn_using_decl_constructor_ellipsis);
+        Diag(BaseCtor->getLocation(),
+             diag::note_using_decl_constructor_ellipsis);
+        EPI.Variadic = false;
+      }
+
+      for (unsigned Params = BaseCtor->getMinRequiredArguments(),
+                    MaxParams = BaseCtor->getNumParams();
+           Params <= MaxParams; ++Params) {
         // Skip default constructors. They're never inherited.
-        if (params == 0)
+        if (Params == 0)
           continue;
-        // Skip copy and move constructors for the same reason.
-        if (CanBeCopyOrMove && params == 1)
+
+        // Skip copy and move constructors for both base and derived class
+        // for the same reason.
+        if (CanBeCopyOrMove && Params == 1)
           continue;
 
         // Build up a function type for this particular constructor.
-        // FIXME: The working paper does not consider that the exception spec
-        // for the inheriting constructor might be larger than that of the
-        // source. This code doesn't yet, either. When it does, this code will
-        // need to be delayed until after exception specifications and in-class
-        // member initializers are attached.
-        const Type *NewCtorType;
-        if (params == maxParams)
-          NewCtorType = BaseCtorType;
-        else {
-          SmallVector<QualType, 16> Args;
-          for (unsigned i = 0; i < params; ++i) {
-            Args.push_back(BaseCtorType->getArgType(i));
-          }
-          FunctionProtoType::ExtProtoInfo ExtInfo =
-              BaseCtorType->getExtProtoInfo();
-          ExtInfo.Variadic = false;
-          NewCtorType = Context.getFunctionType(BaseCtorType->getResultType(),
-                                                Args, ExtInfo)
-                       .getTypePtr();
-        }
+        QualType NewCtorType =
+            Context.getFunctionType(Context.VoidTy, ArgTypes.slice(0, Params),
+                                    EPI);
         const Type *CanonicalNewCtorType =
-            Context.getCanonicalType(NewCtorType);
+            Context.getCanonicalType(NewCtorType).getTypePtr();
 
-        // Now that we have the type, first check if the class already has a
-        // constructor with this signature.
+        // C++11 [class.inhctor]p3:
+        //   ... a constructor is implicitly declared with the same constructor
+        //   characteristics unless there is a user-declared constructor with
+        //   the same signature in the class where the using-declaration appears
         if (ExistingConstructors.count(CanonicalNewCtorType))
           continue;
 
-        // Then we check if we have already declared an inherited constructor
-        // with this signature.
+        // C++11 [class.inhctor]p7:
+        //   If two using-declarations declare inheriting constructors with the
+        //   same signature, the program is ill-formed
         std::pair<ConstructorToSourceMap::iterator, bool> result =
             InheritedConstructors.insert(std::make_pair(
                 CanonicalNewCtorType,
@@ -7740,35 +7788,47 @@ void Sema::DeclareInheritedConstructors(
                  diag::note_using_decl_constructor_conflict_previous_ctor);
             Diag(PrevCtor->getLocation(),
                  diag::note_using_decl_constructor_conflict_previous_using);
+          } else {
+            // Core issue (no number): if the same inheriting constructor is
+            // produced by multiple base class constructors from the same base
+            // class, the inheriting constructor is defined as deleted.
+            result.first->second.second->setDeletedAsWritten();
           }
           continue;
         }
 
         // OK, we're there, now add the constructor.
-        // C++0x [class.inhctor]p8: [...] that would be performed by a
-        //   user-written inline constructor [...]
         DeclarationNameInfo DNI(CreatedCtorName, UsingLoc);
         CXXConstructorDecl *NewCtor = CXXConstructorDecl::Create(
-            Context, ClassDecl, UsingLoc, DNI, QualType(NewCtorType, 0),
+            Context, ClassDecl, UsingLoc, DNI, NewCtorType,
             /*TInfo=*/0, BaseCtor->isExplicit(), /*Inline=*/true,
-            /*ImplicitlyDeclared=*/true,
-            // FIXME: Due to a defect in the standard, we treat inherited
-            // constructors as constexpr even if that makes them ill-formed.
-            /*Constexpr=*/BaseCtor->isConstexpr());
+            /*ImplicitlyDeclared=*/true, /*Constexpr=*/BaseCtor->isConstexpr());
         NewCtor->setAccess(BaseCtor->getAccess());
 
+        // Build an unevaluated exception specification for this constructor.
+        EPI.ExceptionSpecType = EST_Unevaluated;
+        EPI.ExceptionSpecDecl = NewCtor;
+        NewCtor->setType(Context.getFunctionType(Context.VoidTy,
+                                                 ArgTypes.slice(0, Params),
+                                                 EPI));
+
         // Build up the parameter decls and add them.
         SmallVector<ParmVarDecl *, 16> ParamDecls;
-        for (unsigned i = 0; i < params; ++i) {
-          ParamDecls.push_back(ParmVarDecl::Create(Context, NewCtor,
-                                                   UsingLoc, UsingLoc,
-                                                   /*IdentifierInfo=*/0,
-                                                   BaseCtorType->getArgType(i),
-                                                   /*TInfo=*/0, SC_None,
-                                                   SC_None, /*DefaultArg=*/0));
+        for (unsigned i = 0; i < Params; ++i) {
+          ParmVarDecl *PD = ParmVarDecl::Create(Context, NewCtor,
+                                                UsingLoc, UsingLoc,
+                                                /*IdentifierInfo=*/0,
+                                                BaseCtorType->getArgType(i),
+                                                /*TInfo=*/0, SC_None,
+                                                SC_None, /*DefaultArg=*/0);
+          PD->setScopeInfo(0, i);
+          PD->setImplicit();
+          ParamDecls.push_back(PD);
         }
         NewCtor->setParams(ParamDecls);
         NewCtor->setInheritedConstructor(BaseCtor);
+        if (BaseCtor->isDeleted())
+          NewCtor->setDeletedAsWritten();
 
         ClassDecl->addDecl(NewCtor);
         result.first->second.second = NewCtor;
@@ -7777,6 +7837,35 @@ void Sema::DeclareInheritedConstructors(
   }
 }
 
+void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
+                                       CXXConstructorDecl *Constructor) {
+  CXXRecordDecl *ClassDecl = Constructor->getParent();
+  assert(Constructor->getInheritedConstructor() &&
+         !Constructor->doesThisDeclarationHaveABody() &&
+         !Constructor->isDeleted());
+
+  SynthesizedFunctionScope Scope(*this, Constructor);
+  DiagnosticErrorTrap Trap(Diags);
+  if (SetCtorInitializers(Constructor, /*AnyErrors=*/false) ||
+      Trap.hasErrorOccurred()) {
+    Diag(CurrentLocation, diag::note_inhctor_synthesized_at)
+      << Context.getTagDeclType(ClassDecl);
+    Constructor->setInvalidDecl();
+    return;
+  }
+
+  SourceLocation Loc = Constructor->getLocation();
+  Constructor->setBody(new (Context) CompoundStmt(Loc));
+
+  Constructor->setUsed();
+  MarkVTableUsed(CurrentLocation, ClassDecl);
+
+  if (ASTMutationListener *L = getASTMutationListener()) {
+    L->CompletedImplicitDefinition(Constructor);
+  }
+}
+
+
 Sema::ImplicitExceptionSpecification
 Sema::ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD) {
   CXXRecordDecl *ClassDecl = MD->getParent();

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=177320&r1=177319&r2=177320&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Mar 18 16:12:30 2013
@@ -10501,6 +10501,9 @@ void Sema::MarkFunctionReferenced(Source
         if (!Constructor->isUsed(false))
           DefineImplicitMoveConstructor(Loc, Constructor);
       }
+    } else if (Constructor->getInheritedConstructor()) {
+      if (!Constructor->isUsed(false))
+        DefineInheritingConstructor(Loc, Constructor);
     }
 
     MarkVTableUsed(Loc, Constructor->getParent());

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=177320&r1=177319&r2=177320&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Mon Mar 18 16:12:30 2013
@@ -5825,7 +5825,8 @@ bool InitializationSequence::Diagnose(Se
             = cast<CXXConstructorDecl>(S.CurContext);
           if (Entity.getKind() == InitializedEntity::EK_Base) {
             S.Diag(Kind.getLocation(), diag::err_missing_default_ctor)
-              << Constructor->isImplicit()
+              << (Constructor->getInheritedConstructor() ? 2 :
+                  Constructor->isImplicit() ? 1 : 0)
               << S.Context.getTypeDeclType(Constructor->getParent())
               << /*base=*/0
               << Entity.getType();
@@ -5837,7 +5838,8 @@ bool InitializationSequence::Diagnose(Se
               << S.Context.getTagDeclType(BaseDecl);
           } else {
             S.Diag(Kind.getLocation(), diag::err_missing_default_ctor)
-              << Constructor->isImplicit()
+              << (Constructor->getInheritedConstructor() ? 2 :
+                  Constructor->isImplicit() ? 1 : 0)
               << S.Context.getTypeDeclType(Constructor->getParent())
               << /*member=*/1
               << Entity.getName();
@@ -5898,7 +5900,8 @@ bool InitializationSequence::Diagnose(Se
       // initialized.
       CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(S.CurContext);
       S.Diag(Kind.getLocation(), diag::err_uninitialized_member_in_ctor)
-        << Constructor->isImplicit()
+        << (Constructor->getInheritedConstructor() ? 2 :
+            Constructor->isImplicit() ? 1 : 0)
         << S.Context.getTypeDeclType(Constructor->getParent())
         << /*const=*/1
         << Entity.getName();

Modified: cfe/trunk/test/CXX/special/class.inhctor/elsewhere.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.inhctor/elsewhere.cpp?rev=177320&r1=177319&r2=177320&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.inhctor/elsewhere.cpp (original)
+++ cfe/trunk/test/CXX/special/class.inhctor/elsewhere.cpp Mon Mar 18 16:12:30 2013
@@ -9,49 +9,49 @@ struct B1 {
   B1(int);
 };
 
-using B1::B1; // expected-error {{using declaration can not refer to class member}} expected-error {{not supported}}
+using B1::B1; // expected-error {{using declaration can not refer to class member}}
 
-// C++0x [namespace.udecl]p10:
+// C++11 [namespace.udecl]p10:
 //   A using-declaration is a declaration and can therefore be used repeatedly
 //   where (and only where) multiple declarations are allowed.
 
 struct I1 : B1 {
-  using B1::B1; // expected-note {{previous using declaration}} expected-error {{not supported}}
-  using B1::B1; // expected-error {{redeclaration of using decl}} expected-error {{not supported}}
+  using B1::B1; // expected-note {{previous using declaration}}
+  using B1::B1; // expected-error {{redeclaration of using decl}}
 };
 
-// C++0x [namespace.udecl]p3:
+// C++11 [namespace.udecl]p3:
 //   In a using declaration used as a member-declaration, the nested-name-
 //   specifier shall name a base class of the class being defined.
 //   If such a using-declaration names a constructor, the nested-name-specifier
 //   shall name a direct base class of the class being defined.
 
 struct D1 : I1 {
-  using B1::B1; // expected-error {{'B1' is not a direct base of 'D1', can not inherit constructors}} expected-error {{not supported}}
+  using B1::B1; // expected-error {{'B1' is not a direct base of 'D1', can not inherit constructors}}
 };
 
 template<typename T> struct A {};
 
 template<typename T> struct B : A<bool>, A<char> {
-  using A<T>::A; // expected-error {{'A<double>::', which is not a base class of 'B<double>'}} expected-error {{not supported}}
+  using A<T>::A; // expected-error {{'A<double>::', which is not a base class of 'B<double>'}}
 };
 B<bool> bb;
 B<char> bc;
 B<double> bd; // expected-note {{here}}
 
 template<typename T> struct C : A<T> {
-  using A<bool>::A; // expected-error {{'A<bool>::', which is not a base class of 'C<char>'}} expected-error {{not supported}}
+  using A<bool>::A; // expected-error {{'A<bool>::', which is not a base class of 'C<char>'}}
 };
 C<bool> cb;
 C<char> cc; // expected-note {{here}}
 
 template<typename T> struct D : A<T> {};
 template<typename T> struct E : D<T> {
-  using A<bool>::A; // expected-error {{'A<bool>' is not a direct base of 'E<bool>', can not inherit}} expected-error {{not supported}}
+  using A<bool>::A; // expected-error {{'A<bool>' is not a direct base of 'E<bool>', can not inherit}}
 };
 E<bool> eb; // expected-note {{here}}
 
 template<typename T> struct F : D<bool> {
-  using A<T>::A; // expected-error {{'A<bool>' is not a direct base of 'F<bool>'}} expected-error {{not supported}}
+  using A<T>::A; // expected-error {{'A<bool>' is not a direct base of 'F<bool>'}}
 };
 F<bool> fb; // expected-note {{here}}

Added: cfe/trunk/test/CXX/special/class.inhctor/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.inhctor/p1.cpp?rev=177320&view=auto
==============================================================================
--- cfe/trunk/test/CXX/special/class.inhctor/p1.cpp (added)
+++ cfe/trunk/test/CXX/special/class.inhctor/p1.cpp Mon Mar 18 16:12:30 2013
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+// Per a core issue (no number yet), an ellipsis is always dropped.
+struct A {
+  A(...); // expected-note {{here}}
+  A(int = 0, int = 0, int = 0, int = 0, ...); // expected-note 5{{here}}
+  A(int = 0, int = 0, ...); // expected-note {{here}}
+};
+
+struct B : A { // expected-note 3{{candidate}}
+  using A::A; // expected-warning 3{{inheriting constructor does not inherit ellipsis}} expected-note 4{{candidate}} expected-note 2{{deleted}}
+};
+
+B b0{};
+// expected-error at -1 {{call to implicitly-deleted default constructor}}
+// expected-note at 9 {{default constructor of 'B' is implicitly deleted because base class 'A' has multiple default constructors}}
+
+B b1{1};
+// FIXME: explain why the inheriting constructor was deleted
+// expected-error at -2 {{call to implicitly-deleted function of 'B'}}
+
+B b2{1,2};
+// expected-error at -1 {{call to implicitly-deleted function of 'B'}}
+
+B b3{1,2,3};
+// ok
+
+B b4{1,2,3,4};
+// ok
+
+B b5{1,2,3,4,5};
+// expected-error at -1 {{no matching constructor for initialization of 'B'}}

Added: cfe/trunk/test/CXX/special/class.inhctor/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.inhctor/p2.cpp?rev=177320&view=auto
==============================================================================
--- cfe/trunk/test/CXX/special/class.inhctor/p2.cpp (added)
+++ cfe/trunk/test/CXX/special/class.inhctor/p2.cpp Mon Mar 18 16:12:30 2013
@@ -0,0 +1,87 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+template<int> struct X {};
+
+// Constructor characteristics are:
+//   - the template parameter list [FIXME]
+//   - the parameter-type-list
+//   - absence or presence of explicit
+//   - absence or presence of constexpr
+struct A {
+  A(X<0>) {} // expected-note 2{{here}}
+  constexpr A(X<1>) {}
+  explicit A(X<2>) {} // expected-note 3{{here}}
+  explicit constexpr A(X<3>) {} // expected-note 2{{here}}
+};
+
+A a0 { X<0>{} };
+A a0i = { X<0>{} };
+constexpr A a0c { X<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
+constexpr A a0ic = { X<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
+
+A a1 { X<1>{} };
+A a1i = { X<1>{} };
+constexpr A a1c { X<1>{} };
+constexpr A a1ic = { X<1>{} };
+
+A a2 { X<2>{} };
+A a2i = { X<2>{} }; // expected-error {{constructor is explicit}}
+constexpr A a2c { X<2>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
+constexpr A a2ic = { X<2>{} }; // expected-error {{constructor is explicit}}
+
+A a3 { X<3>{} };
+A a3i = { X<3>{} }; // expected-error {{constructor is explicit}}
+constexpr A a3c { X<3>{} };
+constexpr A a3ic = { X<3>{} }; // expected-error {{constructor is explicit}}
+
+
+struct B : A {
+  using A::A; // expected-note 7{{here}}
+};
+
+B b0 { X<0>{} };
+B b0i = { X<0>{} };
+constexpr B b0c { X<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
+constexpr B b0ic = { X<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
+
+B b1 { X<1>{} };
+B b1i = { X<1>{} };
+constexpr B b1c { X<1>{} };
+constexpr B b1ic = { X<1>{} };
+
+B b2 { X<2>{} };
+B b2i = { X<2>{} }; // expected-error {{constructor is explicit}}
+constexpr B b2c { X<2>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
+constexpr B b2ic = { X<2>{} }; // expected-error {{constructor is explicit}}
+
+B b3 { X<3>{} };
+B b3i = { X<3>{} }; // expected-error {{constructor is explicit}}
+constexpr B b3c { X<3>{} };
+constexpr B b3ic = { X<3>{} }; // expected-error {{constructor is explicit}}
+
+
+// 'constexpr' is OK even if the constructor doesn't obey the constraints.
+struct NonLiteral { NonLiteral(); };
+struct NonConstexpr { NonConstexpr(); constexpr NonConstexpr(int); }; // expected-note {{here}}
+struct Constexpr { constexpr Constexpr(int) {} };
+
+struct BothNonLiteral : NonLiteral, Constexpr { using Constexpr::Constexpr; }; // expected-note {{base class 'NonLiteral' of non-literal type}}
+constexpr BothNonLiteral bothNL{42}; // expected-error {{constexpr variable cannot have non-literal type 'const BothNonLiteral'}}
+
+struct BothNonConstexpr : NonConstexpr, Constexpr { using Constexpr::Constexpr; }; // expected-note {{non-constexpr constructor 'NonConstexpr}}
+constexpr BothNonConstexpr bothNC{42}; // expected-error {{must be initialized by a constant expression}} expected-note {{in call to 'BothNonConstexpr(42)'}}
+
+
+struct ConstexprEval {
+  constexpr ConstexprEval(int a, const char *p) : k(p[a]) {}
+  char k;
+};
+struct ConstexprEval2 {
+  char k2 = 'x';
+};
+struct ConstexprEval3 : ConstexprEval, ConstexprEval2 {
+  using ConstexprEval::ConstexprEval;
+};
+constexpr ConstexprEval3 ce{4, "foobar"};
+static_assert(ce.k == 'a', "");
+static_assert(ce.k2 == 'x', "");

Modified: cfe/trunk/test/CXX/special/class.inhctor/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.inhctor/p3.cpp?rev=177320&r1=177319&r2=177320&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.inhctor/p3.cpp (original)
+++ cfe/trunk/test/CXX/special/class.inhctor/p3.cpp Mon Mar 18 16:12:30 2013
@@ -5,7 +5,7 @@ struct B1 {
   B1(int, int);
 };
 struct D1 : B1 {
-  using B1::B1; // expected-error {{not supported}}
+  using B1::B1;
 };
 D1 d1a(1), d1b(1, 1);
 
@@ -15,7 +15,7 @@ struct B2 {
   explicit B2(int, int = 0, int = 0);
 };
 struct D2 : B2 { // expected-note 2 {{candidate constructor}}
-  using B2::B2; // expected-error {{not supported}}
+  using B2::B2;
 };
 D2 d2a(1), d2b(1, 1), d2c(1, 1, 1);
 
@@ -25,18 +25,18 @@ struct B3 {
   B3(void*); // expected-note {{inherited from here}}
 };
 struct D3 : B3 { // expected-note 2 {{candidate constructor}}
-  using B3::B3; // expected-note {{candidate constructor (inherited)}} expected-error {{not supported}}
+  using B3::B3; // expected-note {{candidate constructor (inherited)}}
 };
 D3 fd3() { return 1; } // expected-error {{no viable conversion}}
 
 template<typename T> struct T1 : B1 {
-  using B1::B1; // expected-error {{not supported}}
+  using B1::B1;
 };
 template<typename T> struct T2 : T1<T> {
-  using T1<int>::T1; // expected-error {{not supported}}
+  using T1<int>::T1;
 };
 template<typename T> struct T3 : T1<int> {
-  using T1<T>::T1; // expected-error {{not supported}}
+  using T1<T>::T1;
 };
 struct U {
   friend T1<int>::T1(int);

Added: cfe/trunk/test/CXX/special/class.inhctor/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.inhctor/p4.cpp?rev=177320&view=auto
==============================================================================
--- cfe/trunk/test/CXX/special/class.inhctor/p4.cpp (added)
+++ cfe/trunk/test/CXX/special/class.inhctor/p4.cpp Mon Mar 18 16:12:30 2013
@@ -0,0 +1,70 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+template<int> struct X {};
+
+// A[n inheriting] constructor [...] has the same access as the corresponding
+// constructor [in the base class].
+struct A {
+public:
+  A(X<0>) {}
+protected:
+  A(X<1>) {}
+private:
+  A(X<2>) {} // expected-note {{declared private here}}
+  friend class FA;
+};
+
+struct B : A {
+  using A::A; // expected-error {{private constructor}} expected-note {{implicitly declared protected here}}
+  friend class FB;
+};
+
+B b0{X<0>{}};
+B b1{X<1>{}}; // expected-error {{calling a protected constructor}}
+B b2{X<2>{}}; // expected-note {{first required here}}
+
+struct C : B {
+  C(X<0> x) : B(x) {}
+  C(X<1> x) : B(x) {}
+};
+
+struct FB {
+  B b0{X<0>{}};
+  B b1{X<1>{}};
+};
+
+struct FA : A {
+  using A::A; // expected-note 2{{here}}
+};
+FA fa0{X<0>{}};
+FA fa1{X<1>{}}; // expected-error {{calling a protected constructor}}
+FA fa2{X<2>{}}; // expected-error {{calling a private constructor}}
+
+
+// It is deleted if the corresponding constructor [...] is deleted.
+struct G {
+  G(int) = delete;
+};
+struct H : G {
+  using G::G; // expected-note {{marked deleted here}}
+};
+H h(5); // expected-error {{call to implicitly-deleted function of 'H'}}
+
+
+// Core defect: It is also deleted if multiple base constructors generate the
+// same signature.
+namespace DRnnnn {
+  struct A {
+    constexpr A(int, float = 0) {}
+    explicit A(int, int = 0) {}
+
+    A(int, int, int = 0) = delete;
+  };
+  struct B : A {
+    // FIXME: produce notes indicating why it was deleted
+    using A::A; // expected-note {{here}}
+  };
+
+  constexpr B b0(0, 0.0f); // ok, constexpr
+  B b1(0, 1); // expected-error {{call to implicitly-deleted}}
+}

Modified: cfe/trunk/test/CXX/special/class.inhctor/p7.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.inhctor/p7.cpp?rev=177320&r1=177319&r2=177320&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.inhctor/p7.cpp (original)
+++ cfe/trunk/test/CXX/special/class.inhctor/p7.cpp Mon Mar 18 16:12:30 2013
@@ -8,12 +8,12 @@ struct B2 {
   B2(int); // expected-note {{conflicting constructor}}
 };
 struct D1 : B1, B2 {
-  using B1::B1; // expected-note {{inherited here}} expected-error {{not supported}}
-  using B2::B2; // expected-error {{already inherited constructor with the same signature}} expected-error {{not supported}}
+  using B1::B1; // expected-note {{inherited here}}
+  using B2::B2; // expected-error {{already inherited constructor with the same signature}}
 };
 struct D2 : B1, B2 {
-  using B1::B1; // expected-error {{not supported}}
-  using B2::B2; // expected-error {{not supported}}
+  using B1::B1;
+  using B2::B2;
   D2(int);
 };
 
@@ -22,8 +22,8 @@ template<typename T> struct B3 {
 };
 template<typename T> struct B4 : B3<T>, B1 {
   B4();
-  using B3<T>::B3; // expected-note {{inherited here}} expected-error {{not supported}}
-  using B1::B1; // expected-error {{already inherited}} expected-error {{not supported}}
+  using B3<T>::B3; // expected-note {{inherited here}}
+  using B1::B1; // expected-error {{already inherited}}
 };
 B4<char> b4c;
 B4<int> b4i; // expected-note {{here}}

Added: cfe/trunk/test/CXX/special/class.inhctor/p8.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.inhctor/p8.cpp?rev=177320&view=auto
==============================================================================
--- cfe/trunk/test/CXX/special/class.inhctor/p8.cpp (added)
+++ cfe/trunk/test/CXX/special/class.inhctor/p8.cpp Mon Mar 18 16:12:30 2013
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+// expected-no-diagnostics
+struct A {
+  constexpr A(const int&) : rval(false) {}
+  constexpr A(const int&&) : rval(true) {}
+  bool rval;
+};
+struct B : A {
+  using A::A;
+};
+
+constexpr int k = 0;
+constexpr A a0{0};
+constexpr A a1{k};
+constexpr B b0{0};
+// This performs static_cast<(const int&)&&>(k), so calls the A(const int&)
+// constructor.
+constexpr B b1{k};
+
+static_assert(a0.rval && !a1.rval && b0.rval && !b1.rval, "");

Modified: cfe/trunk/test/CodeGenCXX/inheriting-constructor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/inheriting-constructor.cpp?rev=177320&r1=177319&r2=177320&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/inheriting-constructor.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/inheriting-constructor.cpp Mon Mar 18 16:12:30 2013
@@ -1,11 +1,18 @@
 // RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
 
-// XFAIL: *
-
 // PR12219
 struct A { A(int); virtual ~A(); };
 struct B : A { using A::A; ~B(); };
 B::~B() {}
+
+B b(123);
+
 // CHECK: define void @_ZN1BD0Ev
 // CHECK: define void @_ZN1BD1Ev
 // CHECK: define void @_ZN1BD2Ev
+
+// CHECK: define linkonce_odr void @_ZN1BC1Ei(
+// CHECK: call void @_ZN1BC2Ei(
+
+// CHECK: define linkonce_odr void @_ZN1BC2Ei(
+// CHECK: call void @_ZN1AC2Ei(





More information about the cfe-commits mailing list