r179151 - C++11 inheriting constructors: support for inheriting constructor templates.

Richard Smith richard-llvm at metafoo.co.uk
Tue Apr 9 22:49:00 PDT 2013


Author: rsmith
Date: Wed Apr 10 00:48:59 2013
New Revision: 179151

URL: http://llvm.org/viewvc/llvm-project?rev=179151&view=rev
Log:
C++11 inheriting constructors: support for inheriting constructor templates.

Modified:
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/CXX/special/class.inhctor/elsewhere.cpp
    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/p3.cpp
    cfe/trunk/test/CXX/special/class.inhctor/p4.cpp
    cfe/trunk/test/CXX/special/class.inhctor/p7.cpp
    cfe/trunk/test/CXX/special/class.inhctor/p8.cpp
    cfe/trunk/test/CodeGenCXX/inheriting-constructor.cpp

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=179151&r1=179150&r2=179151&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Apr 10 00:48:59 2013
@@ -4244,9 +4244,8 @@ updateExceptionSpec(Sema &S, FunctionDec
                     const Sema::ImplicitExceptionSpecification &ExceptSpec) {
   FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
   ExceptSpec.getEPI(EPI);
-  const FunctionProtoType *NewFPT = cast<FunctionProtoType>(
-      S.Context.getFunctionType(FPT->getResultType(), FPT->getArgTypes(), EPI));
-  FD->setType(QualType(NewFPT, 0));
+  FD->setType(S.Context.getFunctionType(FPT->getResultType(),
+                                        FPT->getArgTypes(), EPI));
 }
 
 void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD) {
@@ -7655,208 +7654,305 @@ void Sema::ActOnFinishDelayedMemberIniti
   CheckDelayedExplicitlyDefaultedMemberExceptionSpecs();
 }
 
-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.
-  typedef SmallVector<const RecordType *, 4> BasesVector;
-  BasesVector BasesToInheritFrom;
-  for (CXXRecordDecl::base_class_iterator BaseIt = ClassDecl->bases_begin(),
-                                          BaseE = ClassDecl->bases_end();
-         BaseIt != BaseE; ++BaseIt) {
-    if (BaseIt->getInheritConstructors()) {
-      QualType Base = BaseIt->getType();
-      if (Base->isDependentType()) {
-        // 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>());
-    }
+namespace {
+/// Information on inheriting constructors to declare.
+class InheritingConstructorInfo {
+public:
+  InheritingConstructorInfo(Sema &SemaRef, CXXRecordDecl *Derived)
+      : SemaRef(SemaRef), Derived(Derived) {
+    // Mark the constructors that we already have in the derived class.
+    //
+    // 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.
+    visitAll(Derived, &InheritingConstructorInfo::noteDeclaredInDerived);
   }
-  if (BasesToInheritFrom.empty())
-    return;
 
-  // FIXME: Constructor templates.
+  void inheritAll(CXXRecordDecl *RD) {
+    visitAll(RD, &InheritingConstructorInfo::inherit);
+  }
 
-  // Now collect the constructors that we already have in the current class.
-  // Those take precedence over inherited constructors.
-  // 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)
-    ExistingConstructors.insert(
-        Context.getCanonicalType(CtorIt->getType()).getTypePtr());
-
-  DeclarationName CreatedCtorName =
-      Context.DeclarationNames.getCXXConstructorName(
-          ClassDecl->getTypeForDecl()->getCanonicalTypeUnqualified());
-
-  // Now comes the true work.
-  // First, we keep a map from constructor types to the base that introduced
-  // them. Needed for finding conflicting constructors. We also keep the
-  // actually inserted declarations in there, for pretty diagnostics.
-  typedef std::pair<CanQualType, CXXConstructorDecl *> ConstructorInfo;
-  typedef llvm::DenseMap<const Type *, ConstructorInfo> ConstructorToSourceMap;
-  ConstructorToSourceMap InheritedConstructors;
-  for (BasesVector::iterator BaseIt = BasesToInheritFrom.begin(),
-                             BaseE = BasesToInheritFrom.end();
-       BaseIt != BaseE; ++BaseIt) {
-    const RecordType *Base = *BaseIt;
-    CanQualType CanonicalBase = Base->getCanonicalTypeUnqualified();
-    CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(Base->getDecl());
-    for (CXXRecordDecl::ctor_iterator CtorIt = BaseDecl->ctor_begin(),
-                                      CtorE = BaseDecl->ctor_end();
-         CtorIt != CtorE; ++CtorIt) {
-      // Find the using declaration for inheriting this base's constructors.
-      // FIXME: Don't perform name lookup just to obtain a source location!
-      DeclarationName Name =
-          Context.DeclarationNames.getCXXConstructorName(CanonicalBase);
-      LookupResult Result(*this, Name, SourceLocation(), LookupUsingDeclName);
-      LookupQualifiedName(Result, CurContext);
-      UsingDecl *UD = Result.getAsSingle<UsingDecl>();
-      SourceLocation UsingLoc = UD ? UD->getLocation() :
-                                     ClassDecl->getLocation();
-
-      // 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, and
-      // FIXME: ...also constructor templates.
-      CXXConstructorDecl *BaseCtor = *CtorIt;
-      bool CanBeCopyOrMove = BaseCtor->isCopyOrMoveConstructor();
-      const FunctionProtoType *BaseCtorType =
-          BaseCtor->getType()->getAs<FunctionProtoType>();
-
-      // 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;
+private:
+  /// Information about an inheriting constructor.
+  struct InheritingConstructor {
+    InheritingConstructor()
+      : DeclaredInDerived(false), BaseCtor(0), DerivedCtor(0) {}
+
+    /// If \c true, a constructor with this signature is already declared
+    /// in the derived class.
+    bool DeclaredInDerived;
+
+    /// The constructor which is inherited.
+    const CXXConstructorDecl *BaseCtor;
+
+    /// The derived constructor we declared.
+    CXXConstructorDecl *DerivedCtor;
+  };
+
+  /// Inheriting constructors with a given canonical type. There can be at
+  /// most one such non-template constructor, and any number of templated
+  /// constructors.
+  struct InheritingConstructorsForType {
+    InheritingConstructor NonTemplate;
+    llvm::SmallVector<
+      std::pair<TemplateParameterList*, InheritingConstructor>, 4> Templates;
+
+    InheritingConstructor &getEntry(Sema &S, const CXXConstructorDecl *Ctor) {
+      if (FunctionTemplateDecl *FTD = Ctor->getDescribedFunctionTemplate()) {
+        TemplateParameterList *ParamList = FTD->getTemplateParameters();
+        for (unsigned I = 0, N = Templates.size(); I != N; ++I)
+          if (S.TemplateParameterListsAreEqual(ParamList, Templates[I].first,
+                                               false, S.TPL_TemplateMatch))
+            return Templates[I].second;
+        Templates.push_back(std::make_pair(ParamList, InheritingConstructor()));
+        return Templates.back().second;
       }
 
-      for (unsigned Params = BaseCtor->getMinRequiredArguments(),
-                    MaxParams = BaseCtor->getNumParams();
-           Params <= MaxParams; ++Params) {
-        // Skip default constructors. They're never inherited.
-        if (Params == 0)
-          continue;
+      return NonTemplate;
+    }
+  };
 
-        // Skip copy and move constructors for both base and derived class
-        // for the same reason.
-        if (CanBeCopyOrMove && Params == 1)
-          continue;
+  /// Get or create the inheriting constructor record for a constructor.
+  InheritingConstructor &getEntry(const CXXConstructorDecl *Ctor,
+                                  QualType CtorType) {
+    return Map[CtorType.getCanonicalType()->castAs<FunctionProtoType>()]
+        .getEntry(SemaRef, Ctor);
+  }
+
+  typedef void (InheritingConstructorInfo::*VisitFn)(const CXXConstructorDecl*);
+
+  /// Process all constructors for a class.
+  void visitAll(const CXXRecordDecl *RD, VisitFn Callback) {
+    for (CXXRecordDecl::ctor_iterator CtorIt = RD->ctor_begin(),
+                                      CtorE = RD->ctor_end();
+         CtorIt != CtorE; ++CtorIt)
+      (this->*Callback)(*CtorIt);
+    for (CXXRecordDecl::specific_decl_iterator<FunctionTemplateDecl>
+             I(RD->decls_begin()), E(RD->decls_end());
+         I != E; ++I) {
+      const FunctionDecl *FD = (*I)->getTemplatedDecl();
+      if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD))
+        (this->*Callback)(CD);
+    }
+  }
 
-        // Build up a function type for this particular constructor.
-        QualType NewCtorType =
-            Context.getFunctionType(Context.VoidTy, ArgTypes.slice(0, Params),
-                                    EPI);
-        const Type *CanonicalNewCtorType =
-            Context.getCanonicalType(NewCtorType).getTypePtr();
-
-        // 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;
+  /// Note that a constructor (or constructor template) was declared in Derived.
+  void noteDeclaredInDerived(const CXXConstructorDecl *Ctor) {
+    getEntry(Ctor, Ctor->getType()).DeclaredInDerived = true;
+  }
 
-        // 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,
-                std::make_pair(CanonicalBase, (CXXConstructorDecl*)0)));
-        if (!result.second) {
-          // Already in the map. If it came from a different class, that's an
-          // error. Not if it's from the same.
-          CanQualType PreviousBase = result.first->second.first;
-          if (CanonicalBase != PreviousBase) {
-            const CXXConstructorDecl *PrevCtor = result.first->second.second;
-            const CXXConstructorDecl *PrevBaseCtor =
-                PrevCtor->getInheritedConstructor();
-            assert(PrevBaseCtor && "Conflicting constructor was not inherited");
-
-            Diag(UsingLoc, diag::err_using_decl_constructor_conflict);
-            Diag(BaseCtor->getLocation(),
-                 diag::note_using_decl_constructor_conflict_current_ctor);
-            Diag(PrevBaseCtor->getLocation(),
-                 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.
-            SetDeclDeleted(result.first->second.second, UsingLoc);
-          }
-          continue;
-        }
+  /// Inherit a single constructor.
+  void inherit(const CXXConstructorDecl *Ctor) {
+    const FunctionProtoType *CtorType =
+        Ctor->getType()->castAs<FunctionProtoType>();
+    ArrayRef<QualType> ArgTypes(CtorType->getArgTypes());
+    FunctionProtoType::ExtProtoInfo EPI = CtorType->getExtProtoInfo();
 
-        // OK, we're there, now add the constructor.
-        DeclarationNameInfo DNI(CreatedCtorName, UsingLoc);
-        CXXConstructorDecl *NewCtor = CXXConstructorDecl::Create(
-            Context, ClassDecl, UsingLoc, DNI, NewCtorType,
-            /*TInfo=*/0, BaseCtor->isExplicit(), /*Inline=*/true,
-            /*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) {
-          ParmVarDecl *PD = ParmVarDecl::Create(Context, NewCtor,
-                                                UsingLoc, UsingLoc,
-                                                /*IdentifierInfo=*/0,
-                                                BaseCtorType->getArgType(i),
-                                                /*TInfo=*/0, SC_None,
-                                                /*DefaultArg=*/0);
-          PD->setScopeInfo(0, i);
-          PD->setImplicit();
-          ParamDecls.push_back(PD);
-        }
-        NewCtor->setParams(ParamDecls);
-        NewCtor->setInheritedConstructor(BaseCtor);
-        if (BaseCtor->isDeleted())
-          SetDeclDeleted(NewCtor, UsingLoc);
+    SourceLocation UsingLoc = getUsingLoc(Ctor->getParent());
+
+    // Core issue (no number yet): the ellipsis is always discarded.
+    if (EPI.Variadic) {
+      SemaRef.Diag(UsingLoc, diag::warn_using_decl_constructor_ellipsis);
+      SemaRef.Diag(Ctor->getLocation(),
+                   diag::note_using_decl_constructor_ellipsis);
+      EPI.Variadic = false;
+    }
 
-        ClassDecl->addDecl(NewCtor);
-        result.first->second.second = NewCtor;
+    // Declare a constructor for each number of parameters.
+    //
+    // C++11 [class.inhctor]p1:
+    //   The candidate set of inherited constructors from the class X named in
+    //   the using-declaration consists of [... modulo defects ...] for each
+    //   constructor or constructor template of X, the set of constructors or
+    //   constructor templates that results from omitting any ellipsis parameter
+    //   specification and successively omitting parameters with a default
+    //   argument from the end of the parameter-type-list
+    for (unsigned Params = std::max(minParamsToInherit(Ctor),
+                                    Ctor->getMinRequiredArguments()),
+                  MaxParams = Ctor->getNumParams();
+         Params <= MaxParams; ++Params)
+      declareCtor(UsingLoc, Ctor,
+                  SemaRef.Context.getFunctionType(
+                      Ctor->getResultType(), ArgTypes.slice(0, Params), EPI));
+  }
+
+  /// Find the using-declaration which specified that we should inherit the
+  /// constructors of \p Base.
+  SourceLocation getUsingLoc(const CXXRecordDecl *Base) {
+    // No fancy lookup required; just look for the base constructor name
+    // directly within the derived class.
+    ASTContext &Context = SemaRef.Context;
+    DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(
+        Context.getCanonicalType(Context.getRecordType(Base)));
+    DeclContext::lookup_const_result Decls = Derived->lookup(Name);
+    return Decls.empty() ? Derived->getLocation() : Decls[0]->getLocation();
+  }
+
+  unsigned minParamsToInherit(const CXXConstructorDecl *Ctor) {
+    // C++11 [class.inhctor]p3:
+    //   [F]or each constructor template in the candidate set of inherited
+    //   constructors, a constructor template is implicitly declared
+    if (Ctor->getDescribedFunctionTemplate())
+      return 0;
+
+    //   For each non-template constructor in the candidate set of inherited
+    //   constructors other than a constructor having no parameters or a
+    //   copy/move constructor having a single parameter, a constructor is
+    //   implicitly declared [...]
+    if (Ctor->getNumParams() == 0)
+      return 1;
+    if (Ctor->isCopyOrMoveConstructor())
+      return 2;
+
+    // Per discussion on core reflector, never inherit a constructor which
+    // would become a default, copy, or move constructor of Derived either.
+    const ParmVarDecl *PD = Ctor->getParamDecl(0);
+    const ReferenceType *RT = PD->getType()->getAs<ReferenceType>();
+    return (RT && RT->getPointeeCXXRecordDecl() == Derived) ? 2 : 1;
+  }
+
+  /// Declare a single inheriting constructor, inheriting the specified
+  /// constructor, with the given type.
+  void declareCtor(SourceLocation UsingLoc, const CXXConstructorDecl *BaseCtor,
+                   QualType DerivedType) {
+    InheritingConstructor &Entry = getEntry(BaseCtor, DerivedType);
+
+    // 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 (Entry.DeclaredInDerived)
+      return;
+
+    // C++11 [class.inhctor]p7:
+    //   If two using-declarations declare inheriting constructors with the
+    //   same signature, the program is ill-formed
+    if (Entry.DerivedCtor) {
+      if (BaseCtor->getParent() != Entry.BaseCtor->getParent()) {
+        // Only diagnose this once per constructor.
+        if (Entry.DerivedCtor->isInvalidDecl())
+          return;
+        Entry.DerivedCtor->setInvalidDecl();
+
+        SemaRef.Diag(UsingLoc, diag::err_using_decl_constructor_conflict);
+        SemaRef.Diag(BaseCtor->getLocation(),
+                     diag::note_using_decl_constructor_conflict_current_ctor);
+        SemaRef.Diag(Entry.BaseCtor->getLocation(),
+                     diag::note_using_decl_constructor_conflict_previous_ctor);
+        SemaRef.Diag(Entry.DerivedCtor->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.
+        SemaRef.SetDeclDeleted(Entry.DerivedCtor, UsingLoc);
       }
+
+      return;
+    }
+
+    ASTContext &Context = SemaRef.Context;
+    DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(
+        Context.getCanonicalType(Context.getRecordType(Derived)));
+    DeclarationNameInfo NameInfo(Name, UsingLoc);
+
+    TemplateParameterList *TemplateParams = 0;
+    if (const FunctionTemplateDecl *FTD =
+            BaseCtor->getDescribedFunctionTemplate()) {
+      TemplateParams = FTD->getTemplateParameters();
+      // We're reusing template parameters from a different DeclContext. This
+      // is questionable at best, but works out because the template depth in
+      // both places is guaranteed to be 0.
+      // FIXME: Rebuild the template parameters in the new context, and
+      // transform the function type to refer to them.
+    }
+
+    // Build type source info pointing at the using-declaration. This is
+    // required by template instantiation.
+    TypeSourceInfo *TInfo =
+        Context.getTrivialTypeSourceInfo(DerivedType, UsingLoc);
+    FunctionProtoTypeLoc ProtoLoc =
+        TInfo->getTypeLoc().IgnoreParens().castAs<FunctionProtoTypeLoc>();
+
+    CXXConstructorDecl *DerivedCtor = CXXConstructorDecl::Create(
+        Context, Derived, UsingLoc, NameInfo, DerivedType,
+        TInfo, BaseCtor->isExplicit(), /*Inline=*/true,
+        /*ImplicitlyDeclared=*/true, /*Constexpr=*/BaseCtor->isConstexpr());
+
+    // Build an unevaluated exception specification for this constructor.
+    const FunctionProtoType *FPT = DerivedType->castAs<FunctionProtoType>();
+    FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
+    EPI.ExceptionSpecType = EST_Unevaluated;
+    EPI.ExceptionSpecDecl = DerivedCtor;
+    DerivedCtor->setType(Context.getFunctionType(FPT->getResultType(),
+                                                 FPT->getArgTypes(), EPI));
+
+    // Build the parameter declarations.
+    SmallVector<ParmVarDecl *, 16> ParamDecls;
+    for (unsigned I = 0, N = FPT->getNumArgs(); I != N; ++I) {
+      TypeSourceInfo *TInfo =
+          Context.getTrivialTypeSourceInfo(FPT->getArgType(I), UsingLoc);
+      ParmVarDecl *PD = ParmVarDecl::Create(
+          Context, DerivedCtor, UsingLoc, UsingLoc, /*IdentifierInfo=*/0,
+          FPT->getArgType(I), TInfo, SC_None, /*DefaultArg=*/0);
+      PD->setScopeInfo(0, I);
+      PD->setImplicit();
+      ParamDecls.push_back(PD);
+      ProtoLoc.setArg(I, PD);
+    }
+
+    // Set up the new constructor.
+    DerivedCtor->setAccess(BaseCtor->getAccess());
+    DerivedCtor->setParams(ParamDecls);
+    DerivedCtor->setInheritedConstructor(BaseCtor);
+    if (BaseCtor->isDeleted())
+      SemaRef.SetDeclDeleted(DerivedCtor, UsingLoc);
+
+    // If this is a constructor template, build the template declaration.
+    if (TemplateParams) {
+      FunctionTemplateDecl *DerivedTemplate =
+          FunctionTemplateDecl::Create(SemaRef.Context, Derived, UsingLoc, Name,
+                                       TemplateParams, DerivedCtor);
+      DerivedTemplate->setAccess(BaseCtor->getAccess());
+      DerivedCtor->setDescribedFunctionTemplate(DerivedTemplate);
+      Derived->addDecl(DerivedTemplate);
+    } else {
+      Derived->addDecl(DerivedCtor);
     }
+
+    Entry.BaseCtor = BaseCtor;
+    Entry.DerivedCtor = DerivedCtor;
   }
+
+  Sema &SemaRef;
+  CXXRecordDecl *Derived;
+  typedef llvm::DenseMap<const Type *, InheritingConstructorsForType> MapType;
+  MapType Map;
+};
+}
+
+void Sema::DeclareInheritingConstructors(CXXRecordDecl *ClassDecl) {
+  // Defer declaring the inheriting constructors until the class is
+  // instantiated.
+  if (ClassDecl->isDependentContext())
+    return;
+
+  // Find base classes from which we might inherit constructors.
+  SmallVector<CXXRecordDecl*, 4> InheritedBases;
+  for (CXXRecordDecl::base_class_iterator BaseIt = ClassDecl->bases_begin(),
+                                          BaseE = ClassDecl->bases_end();
+       BaseIt != BaseE; ++BaseIt)
+    if (BaseIt->getInheritConstructors())
+      InheritedBases.push_back(BaseIt->getType()->getAsCXXRecordDecl());
+
+  // Go no further if we're not inheriting any constructors.
+  if (InheritedBases.empty())
+    return;
+
+  // Declare the inherited constructors.
+  InheritingConstructorInfo ICI(*this, ClassDecl);
+  for (unsigned I = 0, N = InheritedBases.size(); I != N; ++I)
+    ICI.inheritAll(InheritedBases[I]);
 }
 
 void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=179151&r1=179150&r2=179151&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Wed Apr 10 00:48:59 2013
@@ -1513,6 +1513,10 @@ TemplateDeclInstantiator::VisitCXXMethod
                                         Constructor->isExplicit(),
                                         Constructor->isInlineSpecified(),
                                         false, Constructor->isConstexpr());
+    // Claim that the instantiation of a constructor or constructor template
+    // inherits the same constructor that the template does.
+    if (const CXXConstructorDecl *Inh = Constructor->getInheritedConstructor())
+      cast<CXXConstructorDecl>(Method)->setInheritedConstructor(Inh);
   } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
     Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
                                        StartLoc, NameInfo, T, TInfo,
@@ -2688,15 +2692,16 @@ TemplateDeclInstantiator::InitFunctionIn
       FunctionDecl *ExceptionSpecTemplate = Tmpl;
       if (EPI.ExceptionSpecType == EST_Uninstantiated)
         ExceptionSpecTemplate = EPI.ExceptionSpecTemplate;
-      assert(EPI.ExceptionSpecType != EST_Unevaluated &&
-             "instantiating implicitly-declared special member");
+      ExceptionSpecificationType NewEST = EST_Uninstantiated;
+      if (EPI.ExceptionSpecType == EST_Unevaluated)
+        NewEST = EST_Unevaluated;
 
       // Mark the function has having an uninstantiated exception specification.
       const FunctionProtoType *NewProto
         = New->getType()->getAs<FunctionProtoType>();
       assert(NewProto && "Template instantiation without function prototype?");
       EPI = NewProto->getExtProtoInfo();
-      EPI.ExceptionSpecType = EST_Uninstantiated;
+      EPI.ExceptionSpecType = NewEST;
       EPI.ExceptionSpecDecl = New;
       EPI.ExceptionSpecTemplate = ExceptionSpecTemplate;
       New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),
@@ -2733,7 +2738,6 @@ TemplateDeclInstantiator::InitMethodInst
   if (Tmpl->isVirtualAsWritten())
     New->setVirtualAsWritten(true);
 
-  // FIXME: attributes
   // FIXME: New needs a pointer to Tmpl
   return false;
 }

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=179151&r1=179150&r2=179151&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.inhctor/elsewhere.cpp (original)
+++ cfe/trunk/test/CXX/special/class.inhctor/elsewhere.cpp Wed Apr 10 00:48:59 2013
@@ -55,3 +55,10 @@ template<typename T> struct F : D<bool>
   using A<T>::A; // expected-error {{'A<bool>' is not a direct base of 'F<bool>'}}
 };
 F<bool> fb; // expected-note {{here}}
+
+template<typename T>
+struct G : T {
+  using T::T;
+  G(int &) : G(0) {}
+};
+G<B1> g(123);

Modified: 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=179151&r1=179150&r2=179151&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.inhctor/p1.cpp (original)
+++ cfe/trunk/test/CXX/special/class.inhctor/p1.cpp Wed Apr 10 00:48:59 2013
@@ -2,17 +2,24 @@
 // 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, int = 0, int = 0, ...); // expected-note 9{{here}}
   A(int = 0, int = 0, ...); // expected-note {{here}}
+
+  template<typename T> A(T, int = 0, ...); // expected-note 5{{here}}
+
+  template<typename T, int N> A(const T (&)[N]); // expected-note 2{{here}}
+  template<typename T, int N> A(const T (&)[N], int = 0); // expected-note 2{{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}}
+struct B : A { // expected-note 6{{candidate}}
+  using A::A; // expected-warning 4{{inheriting constructor does not inherit ellipsis}} expected-note 16{{candidate}} expected-note 3{{deleted}}
 };
 
+struct C {} c;
+
 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}}
+// expected-note at -8 {{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
@@ -29,3 +36,16 @@ B b4{1,2,3,4};
 
 B b5{1,2,3,4,5};
 // expected-error at -1 {{no matching constructor for initialization of 'B'}}
+
+B b6{c};
+// ok
+
+B b7{c,0};
+// ok
+
+B b8{c,0,1};
+// expected-error at -1 {{no matching constructor}}
+
+B b9{"foo"};
+// FIXME: explain why the inheriting constructor was deleted
+// expected-error at -2 {{call to deleted constructor of 'B'}}

Modified: 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=179151&r1=179150&r2=179151&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.inhctor/p2.cpp (original)
+++ cfe/trunk/test/CXX/special/class.inhctor/p2.cpp Wed Apr 10 00:48:59 2013
@@ -3,7 +3,7 @@
 template<int> struct X {};
 
 // Constructor characteristics are:
-//   - the template parameter list [FIXME]
+//   - the template parameter list
 //   - the parameter-type-list
 //   - absence or presence of explicit
 //   - absence or presence of constexpr
@@ -85,3 +85,37 @@ struct ConstexprEval3 : ConstexprEval, C
 constexpr ConstexprEval3 ce{4, "foobar"};
 static_assert(ce.k == 'a', "");
 static_assert(ce.k2 == 'x', "");
+
+
+struct TemplateCtors {
+  constexpr TemplateCtors() {}
+  template<template<int> class T> TemplateCtors(X<0>, T<0>);
+  template<int N> TemplateCtors(X<1>, X<N>);
+  template<typename T> TemplateCtors(X<2>, T);
+
+  template<typename T = int> TemplateCtors(int, int = 0, int = 0); // expected-note {{inherited from here}}
+};
+
+struct UsingTemplateCtors : TemplateCtors {
+  using TemplateCtors::TemplateCtors; // expected-note 4{{here}} expected-note {{candidate}}
+
+  constexpr UsingTemplateCtors(X<0>, X<0>) {}
+  constexpr UsingTemplateCtors(X<1>, X<1>) {}
+  constexpr UsingTemplateCtors(X<2>, X<2>) {}
+
+  template<int = 0> constexpr UsingTemplateCtors(int) {} // expected-note {{candidate}}
+  template<typename T = void> constexpr UsingTemplateCtors(int, int) {}
+  template<typename T, typename U> constexpr UsingTemplateCtors(int, int, int) {}
+};
+
+template<int> struct Y {};
+constexpr UsingTemplateCtors uct1{ X<0>{}, X<0>{} };
+constexpr UsingTemplateCtors uct2{ X<0>{}, Y<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
+constexpr UsingTemplateCtors uct3{ X<1>{}, X<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
+constexpr UsingTemplateCtors uct4{ X<1>{}, X<1>{} };
+constexpr UsingTemplateCtors uct5{ X<2>{}, 0 }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
+constexpr UsingTemplateCtors uct6{ X<2>{}, X<2>{} };
+
+constexpr UsingTemplateCtors utc7{ 0 }; // expected-error {{ambiguous}}
+constexpr UsingTemplateCtors utc8{ 0, 0 }; // ok
+constexpr UsingTemplateCtors utc9{ 0, 0, 0 }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}

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=179151&r1=179150&r2=179151&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.inhctor/p3.cpp (original)
+++ cfe/trunk/test/CXX/special/class.inhctor/p3.cpp Wed Apr 10 00:48:59 2013
@@ -46,3 +46,13 @@ struct U {
   friend T3<int>::T3(int);
   friend T3<int>::T3(int, int);
 };
+
+struct B4 {
+  template<typename T> explicit B4(T, int = 0);
+};
+template<typename T> struct T4 : B4 {
+  using B4::B4; // expected-note {{here}}
+  template<typename U> T4(U);
+};
+T4<void> t4a = {0};
+T4<void> t4b = {0, 0}; // expected-error {{chosen constructor is explicit}}

Modified: 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=179151&r1=179150&r2=179151&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.inhctor/p4.cpp (original)
+++ cfe/trunk/test/CXX/special/class.inhctor/p4.cpp Wed Apr 10 00:48:59 2013
@@ -44,11 +44,13 @@ FA fa2{X<2>{}}; // expected-error {{call
 // It is deleted if the corresponding constructor [...] is deleted.
 struct G {
   G(int) = delete;
+  template<typename T> G(T*) = delete;
 };
 struct H : G {
-  using G::G; // expected-note {{marked deleted here}}
+  using G::G; // expected-note 2{{marked deleted here}}
 };
-H h(5); // expected-error {{call to implicitly-deleted function of 'H'}}
+H h1(5); // expected-error {{call to implicitly-deleted function of 'H'}}
+H h2("foo"); // expected-error {{call to deleted constructor of 'H'}}
 
 
 // Core defect: It is also deleted if multiple base constructors generate the

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=179151&r1=179150&r2=179151&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.inhctor/p7.cpp (original)
+++ cfe/trunk/test/CXX/special/class.inhctor/p7.cpp Wed Apr 10 00:48:59 2013
@@ -27,3 +27,21 @@ template<typename T> struct B4 : B3<T>,
 };
 B4<char> b4c;
 B4<int> b4i; // expected-note {{here}}
+
+struct B5 {
+  template<typename T> B5(T); // expected-note {{previous constructor}}
+};
+struct B6 {
+  template<typename T> B6(T); // expected-note {{conflicting constructor}}
+};
+struct B7 {
+  template<typename T, int> B7(T);
+};
+struct D56 : B5, B6, B7 {
+  using B5::B5; // expected-note {{inherited here}}
+  using B6::B6; // expected-error {{already inherited}}
+};
+struct D57 : B5, B6, B7 {
+  using B5::B5;
+  using B7::B7; // ok, not the same signature
+};

Modified: 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=179151&r1=179150&r2=179151&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.inhctor/p8.cpp (original)
+++ cfe/trunk/test/CXX/special/class.inhctor/p8.cpp Wed Apr 10 00:48:59 2013
@@ -19,3 +19,12 @@ constexpr B b0{0};
 constexpr B b1{k};
 
 static_assert(a0.rval && !a1.rval && b0.rval && !b1.rval, "");
+
+struct C {
+  template<typename T> constexpr C(T t) : v(t) {}
+  int v;
+};
+struct D : C {
+  using C::C;
+};
+static_assert(D(123).v == 123, "");

Modified: cfe/trunk/test/CodeGenCXX/inheriting-constructor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/inheriting-constructor.cpp?rev=179151&r1=179150&r2=179151&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/inheriting-constructor.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/inheriting-constructor.cpp Wed Apr 10 00:48:59 2013
@@ -7,6 +7,10 @@ B::~B() {}
 
 B b(123);
 
+struct C { template<typename T> C(T); };
+struct D : C { using C::C; };
+D d(123);
+
 // CHECK: define void @_ZN1BD0Ev
 // CHECK: define void @_ZN1BD1Ev
 // CHECK: define void @_ZN1BD2Ev
@@ -14,5 +18,11 @@ B b(123);
 // CHECK: define linkonce_odr void @_ZN1BC1Ei(
 // CHECK: call void @_ZN1BC2Ei(
 
+// CHECK: define linkonce_odr void @_ZN1DC1IiEET_(
+// CHECK: call void @_ZN1DC2IiEET_(
+
+// CHECK: define linkonce_odr void @_ZN1DC2IiEET_(
+// CHECK: call void @_ZN1CC2IiEET_(
+
 // CHECK: define linkonce_odr void @_ZN1BC2Ei(
 // CHECK: call void @_ZN1AC2Ei(





More information about the cfe-commits mailing list