[cfe-commits] r58749 - in /cfe/trunk: include/clang/AST/DeclCXX.h include/clang/Basic/DiagnosticKinds.def include/clang/Parse/Action.h include/clang/Parse/Parser.h lib/AST/DeclCXX.cpp lib/Parse/ParseCXXInlineMethods.cpp lib/Parse/ParseDeclCXX.cpp lib/Parse/Parser.cpp lib/Sema/Sema.h lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExprCXX.cpp test/SemaCXX/constructor-initializer.cpp www/cxx_status.html

Douglas Gregor doug.gregor at gmail.com
Tue Nov 4 20:30:01 PST 2008


Author: dgregor
Date: Tue Nov  4 22:29:56 2008
New Revision: 58749

URL: http://llvm.org/viewvc/llvm-project?rev=58749&view=rev
Log:
Initial implementation of parsing, semantic analysis, and AST-building
for constructor initializations, e.g.,

  class A { };
  class B : public A { 
    int m;
  public:
    B() : A(), m(17) { };
  };




Added:
    cfe/trunk/test/SemaCXX/constructor-initializer.cpp
Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/Basic/DiagnosticKinds.def
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Parse/Parser.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/www/cxx_status.html

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=58749&r1=58748&r2=58749&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Tue Nov  4 22:29:56 2008
@@ -395,6 +395,105 @@
   friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C);
 };
 
+/// CXXBaseOrMemberInitializer - Represents a C++ base or member
+/// initializer, which is part of a constructor initializer that
+/// initializes one non-static member variable or one base class. For
+/// example, in the following, both 'A(a)' and 'f(3.14159)' are member
+/// initializers:
+///
+/// @code
+/// class A { };
+/// class B : public A {
+///   float f;
+/// public:
+///   B(A& a) : A(a), f(3.14159) { }
+/// };
+class CXXBaseOrMemberInitializer {
+  /// BaseOrMember - This points to the entity being initialized,
+  /// which is either a base class (a Type) or a non-static data
+  /// member (a CXXFieldDecl). When the low bit is 1, it's a base
+  /// class; when the low bit is 0, it's a member.
+  uintptr_t BaseOrMember;
+
+  /// Args - The arguments used to initialize the base or member.
+  Expr **Args;
+  unsigned NumArgs;
+
+public:
+  /// CXXBaseOrMemberInitializer - Creates a new base-class initializer.
+  explicit 
+  CXXBaseOrMemberInitializer(QualType BaseType, Expr **Args, unsigned NumArgs);
+
+  /// CXXBaseOrMemberInitializer - Creates a new member initializer.
+  explicit 
+  CXXBaseOrMemberInitializer(CXXFieldDecl *Member, Expr **Args, unsigned NumArgs);
+
+  /// ~CXXBaseOrMemberInitializer - Destroy the base or member initializer.
+  ~CXXBaseOrMemberInitializer();
+
+  /// arg_iterator - Iterates through the member initialization
+  /// arguments.
+  typedef Expr **arg_iterator;
+
+  /// arg_const_iterator - Iterates through the member initialization
+  /// arguments.
+  typedef Expr * const * arg_const_iterator;
+
+  /// isBaseInitializer - Returns true when this initializer is
+  /// initializing a base class.
+  bool isBaseInitializer() const { return (BaseOrMember & 0x1) != 0; }
+
+  /// isMemberInitializer - Returns true when this initializer is
+  /// initializing a non-static data member.
+  bool isMemberInitializer() const { return (BaseOrMember & 0x1) == 0; }
+
+  /// getBaseClass - If this is a base class initializer, returns the
+  /// type used to specify the initializer. The resulting type will be
+  /// a class type or a typedef of a class type. If this is not a base
+  /// class initializer, returns NULL.
+  Type *getBaseClass() { 
+    if (isBaseInitializer()) 
+      return reinterpret_cast<Type*>(BaseOrMember & ~0x01);
+    else
+      return 0;
+  }
+
+  /// getBaseClass - If this is a base class initializer, returns the
+  /// type used to specify the initializer. The resulting type will be
+  /// a class type or a typedef of a class type. If this is not a base
+  /// class initializer, returns NULL.
+  const Type *getBaseClass() const { 
+    if (isBaseInitializer()) 
+      return reinterpret_cast<const Type*>(BaseOrMember & ~0x01);
+    else
+      return 0;
+  }
+
+  /// getMember - If this is a member initializer, returns the
+  /// declaration of the non-static data member being
+  /// initialized. Otherwise, returns NULL.
+  CXXFieldDecl *getMember() { 
+    if (isMemberInitializer())
+      return reinterpret_cast<CXXFieldDecl *>(BaseOrMember); 
+    else
+      return 0;
+  }
+
+  /// begin() - Retrieve an iterator to the first initializer argument.
+  arg_iterator       begin()       { return Args; }
+  /// begin() - Retrieve an iterator to the first initializer argument.
+  arg_const_iterator begin() const { return Args; }
+
+  /// end() - Retrieve an iterator past the last initializer argument.
+  arg_iterator       end()       { return Args + NumArgs; }
+  /// end() - Retrieve an iterator past the last initializer argument.
+  arg_const_iterator end() const { return Args + NumArgs; }
+
+  /// getNumArgs - Determine the number of arguments used to
+  /// initialize the member or base.
+  unsigned getNumArgs() const { return NumArgs; }
+};
+
 /// CXXConstructorDecl - Represents a C++ constructor within a
 /// class. For example:
 /// 

Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=58749&r1=58748&r2=58749&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Tue Nov  4 22:29:56 2008
@@ -562,6 +562,8 @@
      "statement was disambiguated as %0")
 DIAG(warn_parens_disambiguated_as_function_decl, WARNING,
      "parentheses were disambiguated as a function declarator")
+DIAG(err_expected_member_or_base_name, ERROR,
+     "expected class member or base class name")
 
 // Language specific pragmas
 
@@ -1240,6 +1242,14 @@
 DIAG(err_anon_type_definition, ERROR,
      "declaration of anonymous %0 must be a definition")
 
+// C++ member initializers.
+DIAG(err_mem_init_not_member_or_class, ERROR,
+     "member initializer '%0' does not name a non-static data member or base class")
+DIAG(err_base_init_does_not_name_class, ERROR,
+     "constructor initializer '%0' does not name a class")
+DIAG(err_base_init_direct_and_virtual, ERROR,
+     "base class initializer '%0' names both a direct base class and an inherited virtual base class")
+
 // Derived classes.
 DIAG(err_dup_virtual, ERROR,
      "duplicate 'virtual' in base specifier")

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=58749&r1=58748&r2=58749&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Tue Nov  4 22:29:56 2008
@@ -58,6 +58,7 @@
   typedef void TypeTy;
   typedef void AttrTy;
   typedef void BaseTy;
+  typedef void MemInitTy;
 
   /// ActionResult - This structure is used while parsing/acting on expressions,
   /// stmts, etc.  It encapsulates both the object returned by the action, plus
@@ -85,6 +86,7 @@
   typedef ActionResult<1> StmtResult;
   typedef ActionResult<2> TypeResult;
   typedef ActionResult<3> BaseResult;
+  typedef ActionResult<4> MemInitResult;
 
   /// Deletion callbacks - Since the parser doesn't know the concrete types of
   /// the AST nodes being generated, it must do callbacks to delete objects when
@@ -687,6 +689,28 @@
     return 0;
   }
 
+  virtual MemInitResult ActOnMemInitializer(DeclTy *ConstructorDecl,
+                                            Scope *S,
+                                            IdentifierInfo *MemberOrBase,
+                                            SourceLocation IdLoc,
+                                            SourceLocation LParenLoc,
+                                            ExprTy **Args, unsigned NumArgs,
+                                            SourceLocation *CommaLocs,
+                                            SourceLocation RParenLoc) {
+    return true;
+  }
+
+  /// ActOnMemInitializers - This is invoked when all of the member
+  /// initializers of a constructor have been parsed. ConstructorDecl
+  /// is the function declaration (which will be a C++ constructor in
+  /// a well-formed program), ColonLoc is the location of the ':' that
+  /// starts the constructor initializer, and MemInit/NumMemInits
+  /// contains the individual member (and base) initializers. 
+  virtual void ActOnMemInitializers(DeclTy *ConstructorDecl, 
+                                    SourceLocation ColonLoc,
+                                    MemInitTy **MemInits, unsigned NumMemInits) {
+  }
+
   /// ActOnFinishCXXMemberSpecification - Invoked after all member declarators
   /// are parsed but *before* parsing of inline method definitions.
   virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=58749&r1=58748&r2=58749&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Tue Nov  4 22:29:56 2008
@@ -74,7 +74,8 @@
   typedef Action::DeclTy DeclTy;
   typedef Action::TypeTy TypeTy;
   typedef Action::BaseTy BaseTy;
-  
+  typedef Action::MemInitTy MemInitTy;
+
   // Parsing methods.
   
   /// ParseTranslationUnit - All in one method that initializes parses, and
@@ -314,10 +315,11 @@
   bool SkipUntil(const tok::TokenKind *Toks, unsigned NumToks,
                  bool StopAtSemi = true, bool DontConsume = false);
  
-  typedef Action::ExprResult ExprResult;
-  typedef Action::StmtResult StmtResult;
-  typedef Action::BaseResult BaseResult;
-    
+  typedef Action::ExprResult    ExprResult;
+  typedef Action::StmtResult    StmtResult;
+  typedef Action::BaseResult    BaseResult;
+  typedef Action::MemInitResult MemInitResult;
+
   //===--------------------------------------------------------------------===//
   // Lexing and parsing of C++ inline methods.
 
@@ -717,6 +719,8 @@
   void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType,
                                    DeclTy *TagDecl);
   DeclTy *ParseCXXClassMemberDeclaration(AccessSpecifier AS);
+  void ParseConstructorInitializer(DeclTy *ConstructorDecl);
+  MemInitResult ParseMemInitializer(DeclTy *ConstructorDecl);
 
   //===--------------------------------------------------------------------===//
   // C++ 10: Derived classes [class.derived]

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=58749&r1=58748&r2=58749&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Tue Nov  4 22:29:56 2008
@@ -109,6 +109,39 @@
   return C.getPointerType(ClassTy).withConst();
 }
 
+CXXBaseOrMemberInitializer::
+CXXBaseOrMemberInitializer(QualType BaseType, Expr **Args, unsigned NumArgs) 
+  : Args(0), NumArgs(0) {
+  BaseOrMember = reinterpret_cast<uintptr_t>(BaseType.getTypePtr());
+  assert((BaseOrMember & 0x01) == 0 && "Invalid base class type pointer");
+  BaseOrMember |= 0x01;
+  
+  if (NumArgs > 0) {
+    this->NumArgs = NumArgs;
+    this->Args = new Expr*[NumArgs];
+    for (unsigned Idx = 0; Idx < NumArgs; ++Idx)
+      this->Args[Idx] = Args[Idx];
+  }
+}
+
+CXXBaseOrMemberInitializer::
+CXXBaseOrMemberInitializer(CXXFieldDecl *Member, Expr **Args, unsigned NumArgs)
+  : Args(0), NumArgs(0) {
+  BaseOrMember = reinterpret_cast<uintptr_t>(Member);
+  assert((BaseOrMember & 0x01) == 0 && "Invalid member pointer");  
+
+  if (NumArgs > 0) {
+    this->NumArgs = NumArgs;
+    this->Args = new Expr*[NumArgs];
+    for (unsigned Idx = 0; Idx < NumArgs; ++Idx)
+      this->Args[Idx] = Args[Idx];
+  }
+}
+
+CXXBaseOrMemberInitializer::~CXXBaseOrMemberInitializer() {
+  delete [] Args;
+}
+
 CXXConstructorDecl *
 CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
                            SourceLocation L, IdentifierInfo *Id,

Modified: cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp?rev=58749&r1=58748&r2=58749&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp (original)
+++ cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp Tue Nov  4 22:29:56 2008
@@ -23,7 +23,8 @@
 Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D) {
   assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function &&
          "This isn't a function declarator!");
-  assert(Tok.is(tok::l_brace) && "Current token not a '{'!");
+  assert((Tok.is(tok::l_brace) || Tok.is(tok::colon)) && 
+         "Current token not a '{' or ':'!");
 
   DeclTy *FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D, 0, 0, 0);
 
@@ -32,9 +33,16 @@
   getCurTopClassStack().push(LexedMethod(FnD));
   TokensTy &Toks = getCurTopClassStack().top().Toks;
 
-  // Begin by storing the '{' token.
-  Toks.push_back(Tok);
-  ConsumeBrace();
+  // We may have a constructor initializer here.
+  if (Tok.is(tok::colon)) {
+    // Consume everything up to (and including) the left brace.
+    ConsumeAndStoreUntil(tok::l_brace, Toks);
+  } else {
+    // Begin by storing the '{' token. 
+    Toks.push_back(Tok);
+    ConsumeBrace();
+  }
+  // Consume everything up to (and including) the matching right brace.
   ConsumeAndStoreUntil(tok::r_brace, Toks);
 
   return FnD;
@@ -55,13 +63,17 @@
 
     // Consume the previously pushed token.
     ConsumeAnyToken();
-    assert(Tok.is(tok::l_brace) && "Inline method not starting with '{'");
+    assert((Tok.is(tok::l_brace) || Tok.is(tok::colon)) && 
+           "Inline method not starting with '{' or ':'");
 
     // Parse the method body. Function body parsing code is similar enough
     // to be re-used for method bodies as well.
     EnterScope(Scope::FnScope|Scope::DeclScope);
     Actions.ActOnStartOfFunctionDef(CurScope, LM.D);
 
+    if (Tok.is(tok::colon))
+      ParseConstructorInitializer(LM.D);
+
     ParseFunctionStatementBody(LM.D, Tok.getLocation(), Tok.getLocation());
 
     getCurTopClassStack().pop();

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=58749&r1=58748&r2=58749&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Tue Nov  4 22:29:56 2008
@@ -435,7 +435,8 @@
     }
 
     // function-definition:
-    if (Tok.is(tok::l_brace)) {
+    if (Tok.is(tok::l_brace)
+        || (DeclaratorInfo.isFunctionDeclarator() && Tok.is(tok::colon))) {
       if (!DeclaratorInfo.isFunctionDeclarator()) {
         Diag(Tok, diag::err_func_def_no_params);
         ConsumeBrace();
@@ -638,3 +639,97 @@
 
   Actions.ActOnFinishCXXClassDef(TagDecl);
 }
+
+/// ParseConstructorInitializer - Parse a C++ constructor initializer,
+/// which explicitly initializes the members or base classes of a
+/// class (C++ [class.base.init]). For example, the three initializers
+/// after the ':' in the Derived constructor below:
+///
+/// @code
+/// class Base { };
+/// class Derived : Base {
+///   int x;
+///   float f;
+/// public:
+///   Derived(float f) : Base(), x(17), f(f) { }
+/// };
+/// @endcode
+///
+/// [C++]  ctor-initializer: 
+///          ':' mem-initializer-list 
+///
+/// [C++]  mem-initializer-list: 
+///          mem-initializer 
+///          mem-initializer , mem-initializer-list 
+void Parser::ParseConstructorInitializer(DeclTy *ConstructorDecl) {
+  assert(Tok.is(tok::colon) && "Constructor initializer always starts with ':'");
+
+  SourceLocation ColonLoc = ConsumeToken();
+  
+  llvm::SmallVector<MemInitTy*, 4> MemInitializers;
+  
+  do {
+    MemInitResult MemInit = ParseMemInitializer(ConstructorDecl);
+    if (!MemInit.isInvalid)
+      MemInitializers.push_back(MemInit.Val);
+
+    if (Tok.is(tok::comma))
+      ConsumeToken();
+    else if (Tok.is(tok::l_brace))
+      break;
+    else {
+      // Skip over garbage, until we get to '{'.  Don't eat the '{'.
+      SkipUntil(tok::l_brace, true, true);
+      break;
+    }
+  } while (true);
+
+  Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc, 
+                               &MemInitializers[0], MemInitializers.size());
+}
+
+/// ParseMemInitializer - Parse a C++ member initializer, which is
+/// part of a constructor initializer that explicitly initializes one
+/// member or base class (C++ [class.base.init]). See
+/// ParseConstructorInitializer for an example.
+///
+/// [C++] mem-initializer:
+///         mem-initializer-id '(' expression-list[opt] ')'
+/// 
+/// [C++] mem-initializer-id:
+///         '::'[opt] nested-name-specifier[opt] class-name
+///         identifier
+Parser::MemInitResult Parser::ParseMemInitializer(DeclTy *ConstructorDecl) {
+  // FIXME: parse '::'[opt] nested-name-specifier[opt]
+
+  if (Tok.isNot(tok::identifier)) {
+    Diag(Tok.getLocation(), diag::err_expected_member_or_base_name);
+    return true;
+  }
+
+  // Get the identifier. This may be a member name or a class name,
+  // but we'll let the semantic analysis determine which it is.
+  IdentifierInfo *II = Tok.getIdentifierInfo();
+  SourceLocation IdLoc = ConsumeToken();
+
+  // Parse the '('.
+  if (Tok.isNot(tok::l_paren)) {
+    Diag(Tok.getLocation(), diag::err_expected_lparen);
+    return true;
+  }
+  SourceLocation LParenLoc = ConsumeParen();
+
+  // Parse the optional expression-list.
+  ExprListTy ArgExprs;
+  CommaLocsTy CommaLocs;
+  if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) {
+    SkipUntil(tok::r_paren);
+    return true;
+  }
+
+  SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+  return Actions.ActOnMemInitializer(ConstructorDecl, CurScope, II, IdLoc, 
+                                     LParenLoc, &ArgExprs[0], ArgExprs.size(), 
+                                     &CommaLocs[0], RParenLoc);
+}

Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=58749&r1=58748&r2=58749&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Tue Nov  4 22:29:56 2008
@@ -481,6 +481,10 @@
 ///         decl-specs      declarator declaration-list[opt] compound-statement
 /// [C90] function-definition: [C99 6.7.1] - implicit int result
 /// [C90]   decl-specs[opt] declarator declaration-list[opt] compound-statement
+/// [C++] function-definition: [C++ 8.4]
+///         decl-specifier-seq[opt] declarator ctor-initializer[opt] function-body
+/// [C++] function-definition: [C++ 8.4]
+///         decl-specifier-seq[opt] declarator function-try-block [TODO]
 ///
 Parser::DeclTy *Parser::ParseFunctionDefinition(Declarator &D) {
   const DeclaratorChunk &FnTypeInfo = D.getTypeObject(0);
@@ -504,8 +508,13 @@
   if (!FTI.hasPrototype && FTI.NumArgs != 0)
     ParseKNRParamDeclarations(D);
 
-  // We should have an opening brace now.
-  if (Tok.isNot(tok::l_brace)) {
+  if (getLang().CPlusPlus && Tok.is(tok::colon)) {
+    
+  }
+
+  // We should have either an opening brace or, in a C++ constructor,
+  // we may have a colon.
+  if (Tok.isNot(tok::l_brace) && Tok.isNot(tok::colon)) {
     Diag(Tok, diag::err_expected_fn_body);
 
     // Skip over garbage, until we get to '{'.  Don't eat the '{'.
@@ -516,8 +525,6 @@
       return 0;
   }
 
-  SourceLocation BraceLoc = Tok.getLocation();
-
   // Enter a scope for the function body.
   EnterScope(Scope::FnScope|Scope::DeclScope);
 
@@ -525,6 +532,12 @@
   // specified Declarator for the function.
   DeclTy *Res = Actions.ActOnStartOfFunctionDef(CurScope, D);
 
+  // If we have a colon, then we're probably parsing a C++
+  // ctor-initializer.
+  if (Tok.is(tok::colon))
+    ParseConstructorInitializer(Res);
+
+  SourceLocation BraceLoc = Tok.getLocation();
   return ParseFunctionStatementBody(Res, BraceLoc, BraceLoc);
 }
 

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=58749&r1=58748&r2=58749&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Nov  4 22:29:56 2008
@@ -809,6 +809,15 @@
                                            Declarator &D, ExprTy *BitfieldWidth,
                                            ExprTy *Init, DeclTy *LastInGroup);
 
+  virtual MemInitResult ActOnMemInitializer(DeclTy *ConstructorD,
+                                            Scope *S,
+                                            IdentifierInfo *MemberOrBase,
+                                            SourceLocation IdLoc,
+                                            SourceLocation LParenLoc,
+                                            ExprTy **Args, unsigned NumArgs,
+                                            SourceLocation *CommaLocs,
+                                            SourceLocation RParenLoc);
+
   void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl);
 
   virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=58749&r1=58748&r2=58749&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Nov  4 22:29:56 2008
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "Sema.h"
+#include "SemaInherit.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/TypeOrdering.h"
@@ -543,6 +544,111 @@
   return Member;
 }
 
+/// ActOnMemInitializer - Handle a C++ member initializer.
+Sema::MemInitResult 
+Sema::ActOnMemInitializer(DeclTy *ConstructorD,
+                          Scope *S,
+                          IdentifierInfo *MemberOrBase,
+                          SourceLocation IdLoc,
+                          SourceLocation LParenLoc,
+                          ExprTy **Args, unsigned NumArgs,
+                          SourceLocation *CommaLocs,
+                          SourceLocation RParenLoc) {
+  CXXConstructorDecl *Constructor 
+    = dyn_cast<CXXConstructorDecl>((Decl*)ConstructorD);
+  if (!Constructor) {
+    // The user wrote a constructor initializer on a function that is
+    // not a C++ constructor. Ignore the error for now, because we may
+    // have more member initializers coming; we'll diagnose it just
+    // once in ActOnMemInitializers.
+    return true;
+  }
+
+  CXXRecordDecl *ClassDecl = Constructor->getParent();
+
+  // C++ [class.base.init]p2:
+  //   Names in a mem-initializer-id are looked up in the scope of the
+  //   constructor’s class and, if not found in that scope, are looked
+  //   up in the scope containing the constructor’s
+  //   definition. [Note: if the constructor’s class contains a member
+  //   with the same name as a direct or virtual base class of the
+  //   class, a mem-initializer-id naming the member or base class and
+  //   composed of a single identifier refers to the class member. A
+  //   mem-initializer-id for the hidden base class may be specified
+  //   using a qualified name. ]
+  // Look for a member, first.
+  CXXFieldDecl *Member = ClassDecl->getMember(MemberOrBase);
+
+  // FIXME: Handle members of an anonymous union.
+
+  if (Member) {
+    // FIXME: Perform direct initialization of the member.
+    return new CXXBaseOrMemberInitializer(Member, (Expr **)Args, NumArgs);
+  }
+
+  // It didn't name a member, so see if it names a class.
+  TypeTy *BaseTy = isTypeName(*MemberOrBase, S);
+  if (!BaseTy)
+    return Diag(IdLoc, diag::err_mem_init_not_member_or_class,
+                MemberOrBase->getName(), SourceRange(IdLoc, RParenLoc));
+  
+  QualType BaseType = Context.getTypeDeclType((TypeDecl *)BaseTy);
+  if (!BaseType->isRecordType())
+    return Diag(IdLoc, diag::err_base_init_does_not_name_class,
+                BaseType.getAsString(), SourceRange(IdLoc, RParenLoc));
+
+  // C++ [class.base.init]p2:
+  //   [...] Unless the mem-initializer-id names a nonstatic data
+  //   member of the constructor’s class or a direct or virtual base
+  //   of that class, the mem-initializer is ill-formed. A
+  //   mem-initializer-list can initialize a base class using any
+  //   name that denotes that base class type.
+  
+  // First, check for a direct base class.
+  const CXXBaseSpecifier *DirectBaseSpec = 0;
+  for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
+       Base != ClassDecl->bases_end(); ++Base) {
+    if (Context.getCanonicalType(BaseType).getUnqualifiedType() == 
+        Context.getCanonicalType(Base->getType()).getUnqualifiedType()) {
+      // We found a direct base of this type. That's what we're
+      // initializing.
+      DirectBaseSpec = &*Base;
+      break;
+    }
+  }
+  
+  // Check for a virtual base class.
+  // FIXME: We might be able to short-circuit this if we know in
+  // advance that there are no virtual bases.
+  const CXXBaseSpecifier *VirtualBaseSpec = 0;
+  if (!DirectBaseSpec || !DirectBaseSpec->isVirtual()) {
+    // We haven't found a base yet; search the class hierarchy for a
+    // virtual base class.
+    BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+                    /*DetectVirtual=*/false);
+    if (IsDerivedFrom(Context.getTypeDeclType(ClassDecl), BaseType, Paths)) {
+      for (BasePaths::paths_iterator Path = Paths.begin(); 
+           Path != Paths.end(); ++Path) {
+        if (Path->back().Base->isVirtual()) {
+          VirtualBaseSpec = Path->back().Base;
+          break;
+        }
+      }
+    }
+  }
+
+  // C++ [base.class.init]p2:
+  //   If a mem-initializer-id is ambiguous because it designates both
+  //   a direct non-virtual base class and an inherited virtual base
+  //   class, the mem-initializer is ill-formed.
+  if (DirectBaseSpec && VirtualBaseSpec)
+    return Diag(IdLoc, diag::err_base_init_direct_and_virtual,
+                MemberOrBase->getName(), SourceRange(IdLoc, RParenLoc));
+
+  return new CXXBaseOrMemberInitializer(BaseType, (Expr **)Args, NumArgs);
+}
+
+
 void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
                                              DeclTy *TagDecl,
                                              SourceLocation LBrac,

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=58749&r1=58748&r2=58749&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Tue Nov  4 22:29:56 2008
@@ -546,7 +546,7 @@
     return TryCopyInitialization(SrcExpr, DestType);
   }
 
-  // Not enough support for the rest yet, actually.
+  // FIXME: Not enough support for the rest yet, actually.
   ImplicitConversionSequence ICS;
   ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
   return ICS;

Added: cfe/trunk/test/SemaCXX/constructor-initializer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constructor-initializer.cpp?rev=58749&view=auto

==============================================================================
--- cfe/trunk/test/SemaCXX/constructor-initializer.cpp (added)
+++ cfe/trunk/test/SemaCXX/constructor-initializer.cpp Tue Nov  4 22:29:56 2008
@@ -0,0 +1,43 @@
+// RUN: clang -fsyntax-only -verify %s
+class A { 
+  int m;
+};
+
+class B : public A { 
+public:
+  B() : A(), m(1), n(3.14) { }
+
+private:
+  int m;
+  float n;  
+};
+
+
+class C : public virtual B { 
+public:
+  C() : B() { }
+};
+
+class D : public C { 
+public:
+  D() : B(), C() { }
+};
+
+class E : public D, public B { 
+public:
+  E() : B(), D() { } // expected-error{{base class initializer 'B' names both a direct base class and an inherited virtual base class}}
+};
+
+
+typedef int INT;
+
+class F : public B { 
+public:
+  int B;
+
+  F() : B(17),
+        m(17), // expected-error{{member initializer 'm' does not name a non-static data member or base class}}
+        INT(17) // expected-error{{constructor initializer 'INT' does not name a class}}
+  { 
+  }
+};

Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=58749&r1=58748&r2=58749&view=diff

==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Tue Nov  4 22:29:56 2008
@@ -464,6 +464,7 @@
   <td></td>
   <td></td>
   <td></td>
+  <td></td>
 </tr>
 <tr>
   <td>    5.2.9 [expr.static.cast]</td>
@@ -616,7 +617,14 @@
 <tr><td>  12.5 [class.free]</td><td></td><td></td><td></td><td></td><td></td></tr>
 <tr><td>  12.6 [class.init]</td><td></td><td></td><td></td><td></td><td></td></tr>
 <tr><td>    12.6.1 [class.expl.init]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>    12.6.2 [class.base.init]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr>
+  <td>    12.6.2 [class.base.init]</td>
+  <td bgcolor="#FDD017" align="center"></td>
+  <td bgcolor="#FDD017" align="center"></td>
+  <td bgcolor="#F88017" align="center"></td>
+  <td bgcolor="#C11B17" align="center"></td>
+  <td>No actual direct initialization; implicit initialization not checked.</td>
+</tr>
 <tr><td>  12.7 [class.cdtor]</td><td></td><td></td><td></td><td></td><td></td></tr>
 <tr><td>  12.8 [class.copy]</td><td></td><td></td><td></td><td></td><td></td></tr>
 <tr><td>13 [over]</td><td></td><td></td><td></td><td></td><td></td></tr>





More information about the cfe-commits mailing list