[cfe-commits] r124970 - in /cfe/trunk: include/clang/AST/DeclCXX.h include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/AST/DeclCXX.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaOverload.cpp lib/Serialization/ASTReader.cpp lib/Serialization/ASTWriter.cpp test/CXX/special/class.inhctor/elsewhere.cpp test/CXX/special/class.inhctor/p3.cpp test/CXX/special/class.inhctor/p7.cpp

Sebastian Redl sebastian.redl at getdesigned.at
Sat Feb 5 11:23:19 PST 2011


Author: cornedbee
Date: Sat Feb  5 13:23:19 2011
New Revision: 124970

URL: http://llvm.org/viewvc/llvm-project?rev=124970&view=rev
Log:
Basic implementation of inherited constructors. Only generates declarations, and probably only works for very basic use cases.

Added:
    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
Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=124970&r1=124969&r2=124970&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Sat Feb  5 13:23:19 2011
@@ -187,6 +187,10 @@
   /// VC++ bug.
   unsigned Access : 2;
 
+  /// InheritConstructors - Whether the class contains a using declaration
+  /// to inherit the named class's constructors.
+  bool InheritConstructors : 1;
+
   /// BaseTypeInfo - The type of the base class. This will be a class or struct
   /// (or a typedef of such). The source code range does not include the
   /// "virtual" or access specifier.
@@ -198,7 +202,7 @@
   CXXBaseSpecifier(SourceRange R, bool V, bool BC, AccessSpecifier A,
                    TypeSourceInfo *TInfo, SourceLocation EllipsisLoc)
     : Range(R), EllipsisLoc(EllipsisLoc), Virtual(V), BaseOfClass(BC), 
-      Access(A), BaseTypeInfo(TInfo) { }
+      Access(A), InheritConstructors(false), BaseTypeInfo(TInfo) { }
 
   /// getSourceRange - Retrieves the source range that contains the
   /// entire base specifier.
@@ -214,12 +218,20 @@
   
   /// \brief Determine whether this base specifier is a pack expansion.
   bool isPackExpansion() const { return EllipsisLoc.isValid(); }
-  
+
+  /// \brief Determine whether this base class's constructors get inherited.
+  bool getInheritConstructors() const { return InheritConstructors; }
+
+  /// \brief Set that this base class's constructors should be inherited.
+  void setInheritConstructors(bool Inherit = true) {
+    InheritConstructors = Inherit;
+  }
+
   /// \brief For a pack expansion, determine the location of the ellipsis.
   SourceLocation getEllipsisLoc() const {
     return EllipsisLoc;
   }
-  
+
   /// getAccessSpecifier - Returns the access specifier for this base
   /// specifier. This is the actual base specifier as used for
   /// semantic analysis, so the result can never be AS_none. To
@@ -1519,6 +1531,12 @@
   /// would copy the object to itself. Such constructors are never used to copy
   /// an object.
   bool isSpecializationCopyingObject() const;
+
+  /// \brief Get the constructor that this inheriting constructor is based on.
+  const CXXConstructorDecl *getInheritedConstructor() const;
+
+  /// \brief Set the constructor that this inheriting constructor is based on.
+  void setInheritedConstructor(const CXXConstructorDecl *BaseCtor);
   
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=124970&r1=124969&r2=124970&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sat Feb  5 13:23:19 2011
@@ -162,6 +162,17 @@
   "using declaration refers to its own class">;
 def err_using_decl_nested_name_specifier_is_not_base_class : Error<
   "using declaration refers into '%0', which is not a base class of %1">;
+def err_using_decl_constructor_not_in_direct_base : Error<
+  "%0 is not a direct base of %1, can not inherit constructors">;
+def err_using_decl_constructor_conflict : Error<
+  "can not inherit constructor, already inherited constructor with "
+  "the same signature">;
+def note_using_decl_constructor_conflict_current_ctor : Note<
+  "conflicting constructor">;
+def note_using_decl_constructor_conflict_previous_ctor : Note<
+  "previous constructor">;
+def note_using_decl_constructor_conflict_previous_using : Note<
+  "previously inherited 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<
@@ -1282,12 +1293,14 @@
     "function |function |constructor |"
     "is the implicit default constructor|"
     "is the implicit copy constructor|"
-    "is the implicit copy assignment operator}0%1">;
+    "is the implicit copy assignment operator|"
+    "is an inherited constructor}0%1">;
 
 def warn_init_pointer_from_false : Warning<
     "initialization of pointer of type %0 from literal 'false'">,
     InGroup<BoolConversions>;
 
+def note_ovl_candidate_inherited_constructor : Note<"inherited from here">;
 def note_ovl_candidate_bad_deduction : Note<
     "candidate template ignored: failed template argument deduction">;
 def note_ovl_candidate_incomplete_deduction : Note<"candidate template ignored: "
@@ -1315,14 +1328,15 @@
     "%select{function|function|constructor|function|function|constructor|"
     "constructor (the implicit default constructor)|"
     "constructor (the implicit copy constructor)|"
-    "function (the implicit copy assignment operator)}0 %select{|template }1"
+    "function (the implicit copy assignment operator)|"
+    "constructor (inherited)}0 %select{|template }1"
     "not viable: requires%select{ at least| at most|}2 %3 argument%s3, but %4 "
     "%plural{1:was|:were}4 provided">;
 
 def note_ovl_candidate_deleted : Note<
-  "candidate %select{function|function|constructor|"
-  "function |function |constructor |||}0%1 "
-  "has been explicitly %select{made unavailable|deleted}2">;
+    "candidate %select{function|function|constructor|"
+    "function |function |constructor ||||constructor (inherited)}0%1 "
+    "has been explicitly %select{made unavailable|deleted}2">;
 
 // Giving the index of the bad argument really clutters this message, and
 // it's relatively unimportant because 1) it's generally obvious which
@@ -1334,21 +1348,24 @@
     "function |function |constructor |"
     "constructor (the implicit default constructor)|"
     "constructor (the implicit copy constructor)|"
-    "function (the implicit copy assignment operator)}0%1 "
+    "function (the implicit copy assignment operator)|"
+    "constructor (inherited)}0%1 "
     "not viable: cannot convert argument of incomplete type %2 to %3">;
 def note_ovl_candidate_bad_overload : Note<"candidate "
     "%select{function|function|constructor|"
     "function |function |constructor |"
     "constructor (the implicit default constructor)|"
     "constructor (the implicit copy constructor)|"
-    "function (the implicit copy assignment operator)}0%1"
+    "function (the implicit copy assignment operator)|"
+    "constructor (inherited)}0%1"
     " not viable: no overload of %3 matching %2 for %ordinal4 argument">;
 def note_ovl_candidate_bad_conv : Note<"candidate "
     "%select{function|function|constructor|"
     "function |function |constructor |"
     "constructor (the implicit default constructor)|"
     "constructor (the implicit copy constructor)|"
-    "function (the implicit copy assignment operator)}0%1"
+    "function (the implicit copy assignment operator)|"
+    "constructor (inherited)}0%1"
     " not viable: no known conversion from %2 to %3 for "
     "%select{%ordinal5 argument|object argument}4">;
 def note_ovl_candidate_bad_addrspace : Note<"candidate "
@@ -1356,12 +1373,13 @@
     "function |function |constructor |"
     "constructor (the implicit default constructor)|"
     "constructor (the implicit copy constructor)|"
-    "function (the implicit copy assignment operator)}0%1 not viable: "
+    "function (the implicit copy assignment operator)|"
+    "constructor (inherited)}0%1 not viable: "
     "%select{%ordinal6|'this'}5 argument (%2) is in "
     "address space %3, but parameter must be in address space %4">;
 def note_ovl_candidate_bad_cvr_this : Note<"candidate "
     "%select{|function|||function||||"
-    "function (the implicit copy assignment operator)}0 not viable: "
+    "function (the implicit copy assignment operator)|}0 not viable: "
     "'this' argument has type %2, but method is not marked "
     "%select{const|restrict|const or restrict|volatile|const or volatile|"
     "volatile or restrict|const, volatile, or restrict}3">;
@@ -1370,7 +1388,8 @@
     "function |function |constructor |"
     "constructor (the implicit default constructor)|"
     "constructor (the implicit copy constructor)|"
-    "function (the implicit copy assignment operator)}0%1 not viable: "
+    "function (the implicit copy assignment operator)|"
+    "constructor (inherited)}0%1 not viable: "
     "%ordinal4 argument (%2) would lose "
     "%select{const|restrict|const and restrict|volatile|const and volatile|"
     "volatile and restrict|const, volatile, and restrict}3 qualifier"
@@ -1380,7 +1399,8 @@
     "function |function |constructor |"
     "constructor (the implicit default constructor)|"
     "constructor (the implicit copy constructor)|"
-    "function (the implicit copy assignment operator)}0%1"
+    "function (the implicit copy assignment operator)|"
+    "constructor (inherited)}0%1"
     " not viable: cannot %select{convert from|convert from|bind}2 "
     "%select{base class pointer|superclass|base class object of type}2 %3 to "
     "%select{derived class pointer|subclass|derived class reference}2 %4 for "

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=124970&r1=124969&r2=124970&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Sat Feb  5 13:23:19 2011
@@ -2091,6 +2091,8 @@
                                    bool IsTypeName,
                                    SourceLocation TypenameLoc);
 
+  bool CheckInheritedConstructorUsingDecl(UsingDecl *UD);
+
   Decl *ActOnUsingDeclaration(Scope *CurScope,
                               AccessSpecifier AS,
                               bool HasUsingKeyword,
@@ -2171,6 +2173,12 @@
   void DefineImplicitDestructor(SourceLocation CurrentLocation,
                                 CXXDestructorDecl *Destructor);
 
+  /// \brief Declare all inherited constructors for the given class.
+  ///
+  /// \param ClassDecl The class declaration into which the inherited
+  /// constructors will be added.
+  void DeclareInheritedConstructors(CXXRecordDecl *ClassDecl);
+
   /// \brief Declare the implicit copy constructor for the given class.
   ///
   /// \param S The scope of the class, which may be NULL if this is a 

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=124970&r1=124969&r2=124970&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Sat Feb  5 13:23:19 2011
@@ -1204,6 +1204,22 @@
   return true;  
 }
 
+const CXXConstructorDecl *CXXConstructorDecl::getInheritedConstructor() const {
+  // Hack: we store the inherited constructor in the overridden method table
+  method_iterator It = begin_overridden_methods();
+  if (It == end_overridden_methods())
+    return 0;
+
+  return cast<CXXConstructorDecl>(*It);
+}
+
+void
+CXXConstructorDecl::setInheritedConstructor(const CXXConstructorDecl *BaseCtor){
+  // Hack: we store the inherited constructor in the overridden method table
+  assert(size_overridden_methods() == 0 && "Base ctor already set.");
+  addOverriddenMethod(BaseCtor);
+}
+
 CXXDestructorDecl *
 CXXDestructorDecl::Create(ASTContext &C, EmptyShell Empty) {
   return new (C) CXXDestructorDecl(0, DeclarationNameInfo(),

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=124970&r1=124969&r2=124970&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sat Feb  5 13:23:19 2011
@@ -2787,6 +2787,15 @@
       DiagnoseHiddenVirtualMethods(Record, *M);
     }
   }
+
+  // Declare inherited constructors. We do this eagerly here because:
+  // - The standard requires an eager diagnostic for conflicting inherited
+  //   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);
 }
 
 /// \brief Data used with FindHiddenVirtualMethod
@@ -4122,8 +4131,7 @@
     LookupQualifiedName(Previous, CurContext);
   }
 
-  NestedNameSpecifier *NNS =
-    static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+  NestedNameSpecifier *NNS = SS.getScopeRep();
 
   // Check for invalid redeclarations.
   if (CheckUsingDeclRedeclaration(UsingLoc, IsTypeName, SS, IdentLoc, Previous))
@@ -4163,7 +4171,14 @@
     return UD;
   }
 
-  // Look up the target name.
+  // Constructor inheriting using decls get special treatment.
+  if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) {
+    if (CheckInheritedConstructorUsingDecl(UD))
+      UD->setInvalidDecl();
+    return UD;
+  }
+
+  // Otherwise, look up the target name.
 
   LookupResult R(*this, NameInfo, LookupOrdinaryName);
 
@@ -4227,6 +4242,42 @@
   return UD;
 }
 
+/// Additional checks for a using declaration referring to a constructor name.
+bool Sema::CheckInheritedConstructorUsingDecl(UsingDecl *UD) {
+  if (UD->isTypeName()) {
+    // FIXME: Cannot specify typename when specifying constructor
+    return true;
+  }
+
+  const Type *SourceType = UD->getTargetNestedNameDecl()->getAsType();
+  assert(SourceType &&
+         "Using decl naming constructor doesn't have type in scope spec.");
+  CXXRecordDecl *TargetClass = cast<CXXRecordDecl>(CurContext);
+
+  // Check whether the named type is a direct base class.
+  CanQualType CanonicalSourceType = SourceType->getCanonicalTypeUnqualified();
+  CXXRecordDecl::base_class_iterator BaseIt, BaseE;
+  for (BaseIt = TargetClass->bases_begin(), BaseE = TargetClass->bases_end();
+       BaseIt != BaseE; ++BaseIt) {
+    CanQualType BaseType = BaseIt->getType()->getCanonicalTypeUnqualified();
+    if (CanonicalSourceType == BaseType)
+      break;
+  }
+
+  if (BaseIt == BaseE) {
+    // Did not find SourceType in the bases.
+    Diag(UD->getUsingLocation(),
+         diag::err_using_decl_constructor_not_in_direct_base)
+      << UD->getNameInfo().getSourceRange()
+      << QualType(SourceType, 0) << TargetClass;
+    return true;
+  }
+
+  BaseIt->setInheritConstructors();
+
+  return false;
+}
+
 /// Checks that the given using declaration is not an invalid
 /// redeclaration.  Note that this is checking only for the using decl
 /// itself, not for any ill-formedness among the UsingShadowDecls.
@@ -4670,6 +4721,180 @@
   MarkVTableUsed(CurrentLocation, ClassDecl);
 }
 
+void Sema::DeclareInheritedConstructors(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 llvm::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.
+        return;
+      }
+      BasesToInheritFrom.push_back(Base->castAs<RecordType>());
+    }
+  }
+  if (BasesToInheritFrom.empty())
+    return;
+
+  // 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 [...]
+  //   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());
+  }
+
+  Scope *S = getScopeForContext(ClassDecl);
+  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.
+      DeclarationName Name =
+          Context.DeclarationNames.getCXXConstructorName(CanonicalBase);
+      UsingDecl *UD = dyn_cast_or_null<UsingDecl>(
+          LookupSingleName(S, Name,SourceLocation(), LookupUsingDeclName));
+      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
+      //   - 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.
+      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) {
+        // Skip default constructors. They're never inherited.
+        if (params == 0)
+          continue;
+        // Skip copy and move constructors 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.
+        const Type *NewCtorType;
+        if (params == maxParams)
+          NewCtorType = BaseCtorType;
+        else {
+          llvm::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.data(), params, ExtInfo)
+                       .getTypePtr();
+        }
+        const Type *CanonicalNewCtorType =
+            Context.getCanonicalType(NewCtorType);
+
+        // Now that we have the type, first check if the class already has a
+        // constructor with this signature.
+        if (ExistingConstructors.count(CanonicalNewCtorType))
+          continue;
+
+        // Then we check if we have already declared an inherited constructor
+        // with this signature.
+        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);
+          }
+          continue;
+        }
+
+        // OK, we're there, now add the constructor.
+        // C++0x [class.inhctor]p8: [...] that would be performed by a
+        //   user-writtern inline constructor [...]
+        DeclarationNameInfo DNI(CreatedCtorName, UsingLoc);
+        CXXConstructorDecl *NewCtor = CXXConstructorDecl::Create(
+            Context, ClassDecl, DNI, QualType(NewCtorType, 0), /*TInfo=*/0,
+            BaseCtor->isExplicit(), /*Inline=*/true,
+            /*ImplicitlyDeclared=*/true);
+        NewCtor->setAccess(BaseCtor->getAccess());
+
+        // Build up the parameter decls and add them.
+        llvm::SmallVector<ParmVarDecl *, 16> ParamDecls;
+        for (unsigned i = 0; i < params; ++i) {
+          ParamDecls.push_back(ParmVarDecl::Create(Context, NewCtor, UsingLoc,
+                                                   /*IdentifierInfo=*/0,
+                                                   BaseCtorType->getArgType(i),
+                                                   /*TInfo=*/0, SC_None,
+                                                   SC_None, /*DefaultArg=*/0));
+        }
+        NewCtor->setParams(ParamDecls.data(), ParamDecls.size());
+        NewCtor->setInheritedConstructor(BaseCtor);
+
+        PushOnScopeChains(NewCtor, S, false);
+        ClassDecl->addDecl(NewCtor);
+        result.first->second.second = NewCtor;
+      }
+    }
+  }
+}
+
 CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
   // C++ [class.dtor]p2:
   //   If a class has no user-declared destructor, a destructor is
@@ -5590,7 +5815,6 @@
                                  /*isInline=*/true,
                                  /*isImplicitlyDeclared=*/true);
   CopyConstructor->setAccess(AS_public);
-  CopyConstructor->setImplicit();
   CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor());
   
   // Note that we have declared this constructor.

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=124970&r1=124969&r2=124970&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Sat Feb  5 13:23:19 2011
@@ -6201,7 +6201,8 @@
   oc_constructor_template,
   oc_implicit_default_constructor,
   oc_implicit_copy_constructor,
-  oc_implicit_copy_assignment
+  oc_implicit_copy_assignment,
+  oc_implicit_inherited_constructor
 };
 
 OverloadCandidateKind ClassifyOverloadCandidate(Sema &S,
@@ -6219,6 +6220,9 @@
     if (!Ctor->isImplicit())
       return isTemplate ? oc_constructor_template : oc_constructor;
 
+    if (Ctor->getInheritedConstructor())
+      return oc_implicit_inherited_constructor;
+
     return Ctor->isCopyConstructor() ? oc_implicit_copy_constructor
                                      : oc_implicit_default_constructor;
   }
@@ -6237,6 +6241,16 @@
   return isTemplate ? oc_function_template : oc_function;
 }
 
+void MaybeEmitInheritedConstructorNote(Sema &S, FunctionDecl *Fn) {
+  const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Fn);
+  if (!Ctor) return;
+
+  Ctor = Ctor->getInheritedConstructor();
+  if (!Ctor) return;
+
+  S.Diag(Ctor->getLocation(), diag::note_ovl_candidate_inherited_constructor);
+}
+
 } // end anonymous namespace
 
 // Notes the location of an overload candidate.
@@ -6245,6 +6259,7 @@
   OverloadCandidateKind K = ClassifyOverloadCandidate(*this, Fn, FnDesc);
   Diag(Fn->getLocation(), diag::note_ovl_candidate)
     << (unsigned) K << FnDesc;
+  MaybeEmitInheritedConstructorNote(*this, Fn);
 }
 
 /// Diagnoses an ambiguous conversion.  The partial diagnostic is the
@@ -6299,6 +6314,7 @@
       << (unsigned) FnKind << FnDesc
       << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
       << ToTy << Name << I+1;
+    MaybeEmitInheritedConstructorNote(S, Fn);
     return;
   }
 
@@ -6333,6 +6349,7 @@
         << FromTy
         << FromQs.getAddressSpace() << ToQs.getAddressSpace()
         << (unsigned) isObjectArgument << I+1;
+      MaybeEmitInheritedConstructorNote(S, Fn);
       return;
     }
 
@@ -6350,6 +6367,7 @@
         << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
         << FromTy << (CVR - 1) << I+1;
     }
+    MaybeEmitInheritedConstructorNote(S, Fn);
     return;
   }
 
@@ -6364,6 +6382,7 @@
       << (unsigned) FnKind << FnDesc
       << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
       << FromTy << ToTy << (unsigned) isObjectArgument << I+1;
+    MaybeEmitInheritedConstructorNote(S, Fn);
     return;
   }
 
@@ -6404,6 +6423,7 @@
       << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
       << (BaseToDerivedConversion - 1)
       << FromTy << ToTy << I+1;
+    MaybeEmitInheritedConstructorNote(S, Fn);
     return;
   }
 
@@ -6412,6 +6432,7 @@
     << (unsigned) FnKind << FnDesc
     << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
     << FromTy << ToTy << (unsigned) isObjectArgument << I+1;
+  MaybeEmitInheritedConstructorNote(S, Fn);
 }
 
 void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
@@ -6452,6 +6473,7 @@
   S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity)
     << (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != 0) << mode
     << modeCount << NumFormalArgs;
+  MaybeEmitInheritedConstructorNote(S, Fn);
 }
 
 /// Diagnose a failed template-argument deduction.
@@ -6472,6 +6494,7 @@
     assert(ParamD && "no parameter found for incomplete deduction result");
     S.Diag(Fn->getLocation(), diag::note_ovl_candidate_incomplete_deduction)
       << ParamD->getDeclName();
+    MaybeEmitInheritedConstructorNote(S, Fn);
     return;
   }
 
@@ -6496,6 +6519,7 @@
 
     S.Diag(Fn->getLocation(), diag::note_ovl_candidate_underqualified)
       << ParamD->getDeclName() << Arg << NonCanonParam;
+    MaybeEmitInheritedConstructorNote(S, Fn);
     return;
   }
 
@@ -6514,6 +6538,7 @@
       << which << ParamD->getDeclName()
       << *Cand->DeductionFailure.getFirstArg()
       << *Cand->DeductionFailure.getSecondArg();
+    MaybeEmitInheritedConstructorNote(S, Fn);
     return;
   }
 
@@ -6536,6 +6561,7 @@
              diag::note_ovl_candidate_explicit_arg_mismatch_unnamed)
         << (index + 1);
     }
+    MaybeEmitInheritedConstructorNote(S, Fn);
     return;
 
   case Sema::TDK_TooManyArguments:
@@ -6545,6 +6571,7 @@
 
   case Sema::TDK_InstantiationDepth:
     S.Diag(Fn->getLocation(), diag::note_ovl_candidate_instantiation_depth);
+    MaybeEmitInheritedConstructorNote(S, Fn);
     return;
 
   case Sema::TDK_SubstitutionFailure: {
@@ -6556,6 +6583,7 @@
                                                     *Args);
     S.Diag(Fn->getLocation(), diag::note_ovl_candidate_substitution_failure)
       << ArgString;
+    MaybeEmitInheritedConstructorNote(S, Fn);
     return;
   }
 
@@ -6564,6 +6592,7 @@
   case Sema::TDK_NonDeducedMismatch:
   case Sema::TDK_FailedOverloadResolution:
     S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_deduction);
+    MaybeEmitInheritedConstructorNote(S, Fn);
     return;
   }
 }
@@ -6592,6 +6621,7 @@
 
     S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted)
       << FnKind << FnDesc << Fn->isDeleted();
+    MaybeEmitInheritedConstructorNote(S, Fn);
     return;
   }
 
@@ -6658,6 +6688,7 @@
 
   S.Diag(Cand->Surrogate->getLocation(), diag::note_ovl_surrogate_cand)
     << FnType;
+  MaybeEmitInheritedConstructorNote(S, Cand->Surrogate);
 }
 
 void NoteBuiltinOperatorCandidate(Sema &S,

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=124970&r1=124969&r2=124970&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Sat Feb  5 13:23:19 2011
@@ -4381,11 +4381,14 @@
   bool isVirtual = static_cast<bool>(Record[Idx++]);
   bool isBaseOfClass = static_cast<bool>(Record[Idx++]);
   AccessSpecifier AS = static_cast<AccessSpecifier>(Record[Idx++]);
+  bool inheritConstructors = static_cast<bool>(Record[Idx++]);
   TypeSourceInfo *TInfo = GetTypeSourceInfo(F, Record, Idx);
   SourceRange Range = ReadSourceRange(F, Record, Idx);
   SourceLocation EllipsisLoc = ReadSourceLocation(F, Record, Idx);
-  return CXXBaseSpecifier(Range, isVirtual, isBaseOfClass, AS, TInfo, 
+  CXXBaseSpecifier Result(Range, isVirtual, isBaseOfClass, AS, TInfo, 
                           EllipsisLoc);
+  Result.setInheritConstructors(inheritConstructors);
+  return Result;
 }
 
 std::pair<CXXCtorInitializer **, unsigned>

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=124970&r1=124969&r2=124970&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Sat Feb  5 13:23:19 2011
@@ -3304,6 +3304,7 @@
   Record.push_back(Base.isVirtual());
   Record.push_back(Base.isBaseOfClass());
   Record.push_back(Base.getAccessSpecifierAsWritten());
+  Record.push_back(Base.getInheritConstructors());
   AddTypeSourceInfo(Base.getTypeSourceInfo(), Record);
   AddSourceRange(Base.getSourceRange(), Record);
   AddSourceLocation(Base.isPackExpansion()? Base.getEllipsisLoc() 

Added: 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=124970&view=auto
==============================================================================
--- cfe/trunk/test/CXX/special/class.inhctor/elsewhere.cpp (added)
+++ cfe/trunk/test/CXX/special/class.inhctor/elsewhere.cpp Sat Feb  5 13:23:19 2011
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+// Tests related to constructor inheriting, but not specified in [class.inhctor]
+
+// [namespace.udecl]p8:
+//   A using-declaration for a class member shall be a member-declaration.
+
+struct B1 {
+  B1(int);
+};
+
+using B1::B1; // expected-error {{using declaration can not refer to class member}}
+
+// C++0x [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}}
+  using B1::B1; // expected-error {{redeclaration of using decl}}
+};
+
+// C++0x [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}}
+};

Added: 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=124970&view=auto
==============================================================================
--- cfe/trunk/test/CXX/special/class.inhctor/p3.cpp (added)
+++ cfe/trunk/test/CXX/special/class.inhctor/p3.cpp Sat Feb  5 13:23:19 2011
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+struct B1 {
+  B1(int);
+  B1(int, int);
+};
+struct D1 : B1 {
+  using B1::B1;
+};
+D1 d1a(1), d1b(1, 1);
+
+D1 fd1() { return 1; }
+
+struct B2 {
+  explicit B2(int, int = 0, int = 0);
+};
+struct D2 : B2 { // expected-note {{candidate constructor}}
+  using B2::B2;
+};
+D2 d2a(1), d2b(1, 1), d2c(1, 1, 1);
+
+D2 fd2() { return 1; } // expected-error {{no viable conversion}}
+
+struct B3 {
+  B3(void*); // expected-note {{inherited from here}}
+};
+struct D3 : B3 { // expected-note {{candidate constructor}}
+  using B3::B3; // expected-note {{candidate constructor (inherited)}}
+};
+D3 fd3() { return 1; } // expected-error {{no viable conversion}}

Added: 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=124970&view=auto
==============================================================================
--- cfe/trunk/test/CXX/special/class.inhctor/p7.cpp (added)
+++ cfe/trunk/test/CXX/special/class.inhctor/p7.cpp Sat Feb  5 13:23:19 2011
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+// Straight from the standard
+struct B1 {
+  B1(int); // expected-note {{previous constructor}}
+};
+struct B2 {
+  B2(int); // expected-note {{conflicting constructor}}
+};
+struct D1 : B1, B2 {
+  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;
+  using B2::B2;
+  D2(int);
+};





More information about the cfe-commits mailing list