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) { };
};
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@58749 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 7a0bce8..3d0c805 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -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:
///
diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def
index 8517222..30238f6 100644
--- a/include/clang/Basic/DiagnosticKinds.def
+++ b/include/clang/Basic/DiagnosticKinds.def
@@ -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")
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index aa8710b..345f186 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -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,
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index bffe660..897c09d 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -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]
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 2170146..9f20ac8 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -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,
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index ca00034..7d977c1 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -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();
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 7d03c59..57fa193 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -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);
+}
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 6beaac0..625da6c 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -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);
}
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index ce70855..72b56de 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -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,
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index e4321f5..95d17fa 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -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,
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 22d7127..26fdb24 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -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;
diff --git a/test/SemaCXX/constructor-initializer.cpp b/test/SemaCXX/constructor-initializer.cpp
new file mode 100644
index 0000000..6b450b0
--- /dev/null
+++ b/test/SemaCXX/constructor-initializer.cpp
@@ -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}}
+ {
+ }
+};
diff --git a/www/cxx_status.html b/www/cxx_status.html
index da94910..f52f393 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -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>