зеркало из https://github.com/microsoft/clang.git
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
This commit is contained in:
Родитель
e839b15d7d
Коммит
7ad8390f79
|
@ -395,6 +395,105 @@ protected:
|
|||
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:
|
||||
///
|
||||
|
|
|
@ -562,6 +562,8 @@ DIAG(warn_statement_disambiguation, WARNING,
|
|||
"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_expected_class_name, ERROR,
|
|||
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")
|
||||
|
|
|
@ -58,6 +58,7 @@ public:
|
|||
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 @@ public:
|
|||
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 @@ public:
|
|||
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,
|
||||
|
|
|
@ -74,7 +74,8 @@ public:
|
|||
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 @@ private:
|
|||
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 @@ private:
|
|||
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]
|
||||
|
|
|
@ -109,6 +109,39 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const {
|
|||
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,
|
||||
|
|
|
@ -23,7 +23,8 @@ Parser::DeclTy *
|
|||
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 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D) {
|
|||
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 @@ void Parser::ParseLexedMethodDefs() {
|
|||
|
||||
// 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();
|
||||
|
|
|
@ -435,7 +435,8 @@ Parser::DeclTy *Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) {
|
|||
}
|
||||
|
||||
// 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 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
|
|||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -481,6 +481,10 @@ Parser::DeclTy *Parser::ParseDeclarationOrFunctionDefinition() {
|
|||
/// 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 @@ Parser::DeclTy *Parser::ParseFunctionDefinition(Declarator &D) {
|
|||
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 @@ Parser::DeclTy *Parser::ParseFunctionDefinition(Declarator &D) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
SourceLocation BraceLoc = Tok.getLocation();
|
||||
|
||||
// Enter a scope for the function body.
|
||||
EnterScope(Scope::FnScope|Scope::DeclScope);
|
||||
|
||||
|
@ -525,6 +532,12 @@ Parser::DeclTy *Parser::ParseFunctionDefinition(Declarator &D) {
|
|||
// 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -809,6 +809,15 @@ public:
|
|||
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,
|
||||
|
|
|
@ -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 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
|
|||
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,
|
||||
|
|
|
@ -546,7 +546,7 @@ Sema::TryDirectInitialization(Expr *SrcExpr, QualType DestType)
|
|||
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;
|
||||
|
|
|
@ -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}}
|
||||
{
|
||||
}
|
||||
};
|
|
@ -464,6 +464,7 @@ welcome!</p>
|
|||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 5.2.9 [expr.static.cast]</td>
|
||||
|
@ -616,7 +617,14 @@ welcome!</p>
|
|||
<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>
|
||||
|
|
Загрузка…
Ссылка в новой задаче