Move most of the checking from ActOnCXXMemberDeclarator to other, more general routines. This is a step toward separating the checking logic from Declarators, which in turn is required for template instantiation.
llvm-svn: 66734
This commit is contained in:
parent
d9065c4e29
commit
0c88030abd
|
@ -344,6 +344,19 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
/// \brief Determines whether this is a static data member.
|
||||
///
|
||||
/// This will only be true in C++, and applies to, e.g., the
|
||||
/// variable 'x' in:
|
||||
/// \code
|
||||
/// struct S {
|
||||
/// static int x;
|
||||
/// };
|
||||
/// \endcode
|
||||
bool isStaticDataMember() const {
|
||||
return getDeclContext()->isRecord();
|
||||
}
|
||||
|
||||
/// isFileVarDecl - Returns true for file scoped variable declaration.
|
||||
bool isFileVarDecl() const {
|
||||
if (getKind() != Decl::Var)
|
||||
|
|
|
@ -248,6 +248,8 @@ DIAG(err_mutable_nonmember, ERROR,
|
|||
"'mutable' can only be applied to member variables")
|
||||
DIAG(err_virtual_non_function, ERROR,
|
||||
"'virtual' can only appear on non-static member functions")
|
||||
DIAG(err_virtual_out_of_class, ERROR,
|
||||
"'virtual' can only be specified inside the class definition")
|
||||
DIAG(err_static_not_bitfield, ERROR,
|
||||
"static member %0 cannot be a bit-field")
|
||||
DIAG(err_typedef_not_bitfield, ERROR,
|
||||
|
@ -1229,6 +1231,10 @@ DIAG(err_base_init_does_not_name_class, ERROR,
|
|||
DIAG(err_base_init_direct_and_virtual, ERROR,
|
||||
"base class initializer %0 names both a direct base class and an"
|
||||
" inherited virtual base class")
|
||||
DIAG(err_in_class_initializer_non_integral_type, ERROR,
|
||||
"in-class initializer has non-integral, non-enumeration type %0")
|
||||
DIAG(err_in_class_initializer_non_constant, ERROR,
|
||||
"in-class initializer is not an integral constant expression")
|
||||
|
||||
// C++ anonymous unions and GNU anonymous structs/unions
|
||||
DIAG(ext_anonymous_union, EXTENSION,
|
||||
|
|
|
@ -1431,10 +1431,15 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
|||
DC = 0;
|
||||
}
|
||||
|
||||
// Check that there are no default arguments (C++ only).
|
||||
if (getLangOptions().CPlusPlus)
|
||||
if (getLangOptions().CPlusPlus) {
|
||||
// Check that there are no default arguments (C++ only).
|
||||
CheckExtraCXXDefaultArguments(D);
|
||||
|
||||
if (D.getDeclSpec().isVirtualSpecified())
|
||||
Diag(D.getDeclSpec().getVirtualSpecLoc(),
|
||||
diag::err_virtual_non_function);
|
||||
}
|
||||
|
||||
TypedefDecl *NewTD = ParseTypedefDecl(S, D, R, LastDeclarator);
|
||||
if (!NewTD) return 0;
|
||||
|
||||
|
@ -1580,6 +1585,10 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (D.getDeclSpec().isVirtualSpecified())
|
||||
Diag(D.getDeclSpec().getVirtualSpecLoc(),
|
||||
diag::err_virtual_non_function);
|
||||
|
||||
bool ThreadSpecified = D.getDeclSpec().isThreadSpecified();
|
||||
if (!DC->isRecord() && S->getFnParent() == 0) {
|
||||
// C99 6.9p2: The storage-class specifiers auto and register shall not
|
||||
|
@ -1751,9 +1760,10 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
|||
}
|
||||
|
||||
bool isInline = D.getDeclSpec().isInlineSpecified();
|
||||
// bool isVirtual = D.getDeclSpec().isVirtualSpecified();
|
||||
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
|
||||
bool isExplicit = D.getDeclSpec().isExplicitSpecified();
|
||||
|
||||
bool isVirtualOkay = false;
|
||||
FunctionDecl *NewFD;
|
||||
if (D.getKind() == Declarator::DK_Constructor) {
|
||||
// This is a C++ constructor declaration.
|
||||
|
@ -1784,6 +1794,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
|||
|
||||
if (InvalidDecl)
|
||||
NewFD->setInvalidDecl();
|
||||
|
||||
isVirtualOkay = true;
|
||||
} else {
|
||||
Diag(D.getIdentifierLoc(), diag::err_destructor_not_member);
|
||||
|
||||
|
@ -1811,12 +1823,16 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
|||
|
||||
if (InvalidDecl)
|
||||
NewFD->setInvalidDecl();
|
||||
|
||||
isVirtualOkay = true;
|
||||
}
|
||||
} else if (DC->isRecord()) {
|
||||
// This is a C++ method declaration.
|
||||
NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC),
|
||||
D.getIdentifierLoc(), Name, R,
|
||||
(SC == FunctionDecl::Static), isInline);
|
||||
|
||||
isVirtualOkay = (SC != FunctionDecl::Static);
|
||||
} else {
|
||||
NewFD = FunctionDecl::Create(Context, DC,
|
||||
D.getIdentifierLoc(),
|
||||
|
@ -1835,6 +1851,34 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
|||
// from the semantic context.
|
||||
NewFD->setLexicalDeclContext(CurContext);
|
||||
|
||||
// C++ [dcl.fct.spec]p5:
|
||||
// The virtual specifier shall only be used in declarations of
|
||||
// nonstatic class member functions that appear within a
|
||||
// member-specification of a class declaration; see 10.3.
|
||||
//
|
||||
// FIXME: Checking the 'virtual' specifier is not sufficient. A
|
||||
// function is also virtual if it overrides an already virtual
|
||||
// function. This is important to do here because it's part of the
|
||||
// declaration.
|
||||
if (isVirtual && !InvalidDecl) {
|
||||
if (!isVirtualOkay) {
|
||||
Diag(D.getDeclSpec().getVirtualSpecLoc(),
|
||||
diag::err_virtual_non_function);
|
||||
} else if (!CurContext->isRecord()) {
|
||||
// 'virtual' was specified outside of the class.
|
||||
Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_out_of_class)
|
||||
<< CodeModificationHint::CreateRemoval(
|
||||
SourceRange(D.getDeclSpec().getVirtualSpecLoc()));
|
||||
} else {
|
||||
// Okay: Add virtual to the method.
|
||||
cast<CXXMethodDecl>(NewFD)->setVirtual();
|
||||
CXXRecordDecl *CurClass = cast<CXXRecordDecl>(DC);
|
||||
CurClass->setAggregate(false);
|
||||
CurClass->setPOD(false);
|
||||
CurClass->setPolymorphic(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle GNU asm-label extension (encoded as an attribute).
|
||||
if (Expr *E = (Expr*) D.getAsmLabel()) {
|
||||
// The parser guarantees this is a string.
|
||||
|
@ -2109,9 +2153,38 @@ void Sema::AddInitializerToDecl(DeclTy *dcl, ExprArg init, bool DirectInit) {
|
|||
if (RealDecl == 0)
|
||||
return;
|
||||
|
||||
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) {
|
||||
// With declarators parsed the way they are, the parser cannot
|
||||
// distinguish between a normal initializer and a pure-specifier.
|
||||
// Thus this grotesque test.
|
||||
IntegerLiteral *IL;
|
||||
Expr *Init = static_cast<Expr *>(init.get());
|
||||
if ((IL = dyn_cast<IntegerLiteral>(Init)) && IL->getValue() == 0 &&
|
||||
Context.getCanonicalType(IL->getType()) == Context.IntTy) {
|
||||
if (Method->isVirtual())
|
||||
Method->setPure();
|
||||
else {
|
||||
Diag(Method->getLocation(), diag::err_non_virtual_pure)
|
||||
<< Method->getDeclName() << Init->getSourceRange();
|
||||
Method->setInvalidDecl();
|
||||
}
|
||||
} else {
|
||||
Diag(Method->getLocation(), diag::err_member_function_initialization)
|
||||
<< Method->getDeclName() << Init->getSourceRange();
|
||||
Method->setInvalidDecl();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
VarDecl *VDecl = dyn_cast<VarDecl>(RealDecl);
|
||||
if (!VDecl) {
|
||||
Diag(RealDecl->getLocation(), diag::err_illegal_initializer);
|
||||
if (getLangOptions().CPlusPlus &&
|
||||
RealDecl->getLexicalDeclContext()->isRecord() &&
|
||||
isa<NamedDecl>(RealDecl))
|
||||
Diag(RealDecl->getLocation(), diag::err_member_initialization)
|
||||
<< cast<NamedDecl>(RealDecl)->getDeclName();
|
||||
else
|
||||
Diag(RealDecl->getLocation(), diag::err_illegal_initializer);
|
||||
RealDecl->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
|
@ -2150,6 +2223,52 @@ void Sema::AddInitializerToDecl(DeclTy *dcl, ExprArg init, bool DirectInit) {
|
|||
CheckForConstantInitializer(Init, DclT);
|
||||
}
|
||||
}
|
||||
} else if (VDecl->isStaticDataMember() &&
|
||||
VDecl->getLexicalDeclContext()->isRecord()) {
|
||||
// This is an in-class initialization for a static data member, e.g.,
|
||||
//
|
||||
// struct S {
|
||||
// static const int value = 17;
|
||||
// };
|
||||
|
||||
// Attach the initializer
|
||||
VDecl->setInit(Init);
|
||||
|
||||
// C++ [class.mem]p4:
|
||||
// A member-declarator can contain a constant-initializer only
|
||||
// if it declares a static member (9.4) of const integral or
|
||||
// const enumeration type, see 9.4.2.
|
||||
QualType T = VDecl->getType();
|
||||
if (!T->isDependentType() &&
|
||||
(!Context.getCanonicalType(T).isConstQualified() ||
|
||||
!T->isIntegralType())) {
|
||||
Diag(VDecl->getLocation(), diag::err_member_initialization)
|
||||
<< VDecl->getDeclName() << Init->getSourceRange();
|
||||
VDecl->setInvalidDecl();
|
||||
} else {
|
||||
// C++ [class.static.data]p4:
|
||||
// If a static data member is of const integral or const
|
||||
// enumeration type, its declaration in the class definition
|
||||
// can specify a constant-initializer which shall be an
|
||||
// integral constant expression (5.19).
|
||||
if (!Init->isTypeDependent() &&
|
||||
!Init->getType()->isIntegralType()) {
|
||||
// We have a non-dependent, non-integral or enumeration type.
|
||||
Diag(Init->getSourceRange().getBegin(),
|
||||
diag::err_in_class_initializer_non_integral_type)
|
||||
<< Init->getType() << Init->getSourceRange();
|
||||
VDecl->setInvalidDecl();
|
||||
} else if (!Init->isTypeDependent() && !Init->isValueDependent()) {
|
||||
// Check whether the expression is a constant expression.
|
||||
llvm::APSInt Value;
|
||||
SourceLocation Loc;
|
||||
if (!Init->isIntegerConstantExpr(Value, Context, &Loc)) {
|
||||
Diag(Loc, diag::err_in_class_initializer_non_constant)
|
||||
<< Init->getSourceRange();
|
||||
VDecl->setInvalidDecl();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (VDecl->isFileVarDecl()) {
|
||||
if (VDecl->getStorageClass() == VarDecl::Extern)
|
||||
Diag(VDecl->getLocation(), diag::warn_extern_init);
|
||||
|
@ -3252,6 +3371,7 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
|
|||
Sema::DeclTy *Sema::ActOnField(Scope *S, DeclTy *TagD,
|
||||
SourceLocation DeclStart,
|
||||
Declarator &D, ExprTy *BitfieldWidth) {
|
||||
|
||||
return HandleField(S, static_cast<RecordDecl*>(TagD), DeclStart, D,
|
||||
static_cast<Expr*>(BitfieldWidth),
|
||||
AS_public);
|
||||
|
@ -3269,9 +3389,14 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
|
|||
|
||||
QualType T = GetTypeForDeclarator(D, S);
|
||||
|
||||
if (getLangOptions().CPlusPlus)
|
||||
if (getLangOptions().CPlusPlus) {
|
||||
CheckExtraCXXDefaultArguments(D);
|
||||
|
||||
if (D.getDeclSpec().isVirtualSpecified())
|
||||
Diag(D.getDeclSpec().getVirtualSpecLoc(),
|
||||
diag::err_virtual_non_function);
|
||||
}
|
||||
|
||||
NamedDecl *PrevDecl = LookupName(S, II, LookupMemberName, true);
|
||||
if (PrevDecl && !isDeclInScope(PrevDecl, Record, S))
|
||||
PrevDecl = 0;
|
||||
|
|
|
@ -588,72 +588,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
|
|||
|
||||
assert((Name || isInstField) && "No identifier for non-field ?");
|
||||
|
||||
if (DS.isVirtualSpecified()) {
|
||||
if (!isFunc || DS.getStorageClassSpec() == DeclSpec::SCS_static) {
|
||||
Diag(DS.getVirtualSpecLoc(), diag::err_virtual_non_function);
|
||||
Member->setInvalidDecl();
|
||||
} else {
|
||||
cast<CXXMethodDecl>(Member)->setVirtual();
|
||||
CXXRecordDecl *CurClass = cast<CXXRecordDecl>(CurContext);
|
||||
CurClass->setAggregate(false);
|
||||
CurClass->setPOD(false);
|
||||
CurClass->setPolymorphic(true);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: The above definition of virtual is not sufficient. A function is
|
||||
// also virtual if it overrides an already virtual function. This is important
|
||||
// to do here because it decides the validity of a pure specifier.
|
||||
|
||||
if (Init) {
|
||||
// C++ 9.2p4: A member-declarator can contain a constant-initializer only
|
||||
// if it declares a static member of const integral or const enumeration
|
||||
// type.
|
||||
if (VarDecl *CVD = dyn_cast<VarDecl>(Member)) {
|
||||
// ...static member of...
|
||||
CVD->setInit(Init);
|
||||
// ...const integral or const enumeration type.
|
||||
if (Context.getCanonicalType(CVD->getType()).isConstQualified() &&
|
||||
CVD->getType()->isIntegralType()) {
|
||||
// constant-initializer
|
||||
if (CheckForConstantInitializer(Init, CVD->getType()))
|
||||
Member->setInvalidDecl();
|
||||
|
||||
} else {
|
||||
// not const integral.
|
||||
Diag(Loc, diag::err_member_initialization)
|
||||
<< Name << Init->getSourceRange();
|
||||
Member->setInvalidDecl();
|
||||
}
|
||||
|
||||
} else {
|
||||
// not static member. perhaps virtual function?
|
||||
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member)) {
|
||||
// With declarators parsed the way they are, the parser cannot
|
||||
// distinguish between a normal initializer and a pure-specifier.
|
||||
// Thus this grotesque test.
|
||||
IntegerLiteral *IL;
|
||||
if ((IL = dyn_cast<IntegerLiteral>(Init)) && IL->getValue() == 0 &&
|
||||
Context.getCanonicalType(IL->getType()) == Context.IntTy) {
|
||||
if (MD->isVirtual())
|
||||
MD->setPure();
|
||||
else {
|
||||
Diag(Loc, diag::err_non_virtual_pure)
|
||||
<< Name << Init->getSourceRange();
|
||||
Member->setInvalidDecl();
|
||||
}
|
||||
} else {
|
||||
Diag(Loc, diag::err_member_function_initialization)
|
||||
<< Name << Init->getSourceRange();
|
||||
Member->setInvalidDecl();
|
||||
}
|
||||
} else {
|
||||
Diag(Loc, diag::err_member_initialization)
|
||||
<< Name << Init->getSourceRange();
|
||||
Member->setInvalidDecl();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Init)
|
||||
AddInitializerToDecl(Member, ExprArg(*this, Init), false);
|
||||
|
||||
if (isInstField) {
|
||||
FieldCollector->Add(cast<FieldDecl>(Member));
|
||||
|
|
|
@ -35,7 +35,7 @@ public:
|
|||
int i = 0; // expected-error {{error: 'i' can only be initialized if it is a static const integral data member}}
|
||||
static int si = 0; // expected-error {{error: 'si' can only be initialized if it is a static const integral data member}}
|
||||
static const NestedC ci = 0; // expected-error {{error: 'ci' can only be initialized if it is a static const integral data member}}
|
||||
static const int nci = vs; // expected-error {{error: initializer element is not a compile-time constant}}
|
||||
static const int nci = vs; // expected-error {{in-class initializer is not an integral constant expression}}
|
||||
static const int vi = 0;
|
||||
static const E evi = 0;
|
||||
|
||||
|
@ -53,7 +53,7 @@ public:
|
|||
|
||||
typedef int A;
|
||||
|
||||
virtual int viv; // expected-error {{error: 'virtual' can only appear on non-static member functions}}
|
||||
virtual int viv; // expected-error {{'virtual' can only appear on non-static member functions}}
|
||||
virtual static int vsif(); // expected-error {{error: 'virtual' can only appear on non-static member functions}}
|
||||
virtual int vif();
|
||||
|
||||
|
|
|
@ -8,10 +8,15 @@ class A {
|
|||
void i() = 1; // expected-error {{initializer on function does not look like a pure-specifier}}
|
||||
void j() = 0u; // expected-error {{initializer on function does not look like a pure-specifier}}
|
||||
|
||||
|
||||
void k();
|
||||
|
||||
public:
|
||||
A(int);
|
||||
};
|
||||
|
||||
virtual void A::k() { } // expected-error{{'virtual' can only be specified inside the class definition}}
|
||||
|
||||
class B : public A {
|
||||
// Needs to recognize that overridden function is virtual.
|
||||
//void g() = 0;
|
||||
|
|
Loading…
Reference in New Issue