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:
Douglas Gregor 2008-11-05 04:29:56 +00:00
Родитель e839b15d7d
Коммит 7ad8390f79
13 изменённых файлов: 473 добавлений и 17 удалений

Просмотреть файл

@ -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
// constructors class and, if not found in that scope, are looked
// up in the scope containing the constructors
// definition. [Note: if the constructors 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 constructors 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>&nbsp;&nbsp;&nbsp;&nbsp;5.2.9 [expr.static.cast]</td>
@ -616,7 +617,14 @@ welcome!</p>
<tr><td>&nbsp;&nbsp;12.5 [class.free]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>&nbsp;&nbsp;12.6 [class.init]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;12.6.1 [class.expl.init]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;12.6.2 [class.base.init]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;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>&nbsp;&nbsp;12.7 [class.cdtor]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>&nbsp;&nbsp;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>