[cfe-commits] r66734 - in /cfe/trunk: include/clang/AST/Decl.h include/clang/Basic/DiagnosticSemaKinds.def lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp test/SemaCXX/class.cpp test/SemaCXX/virtuals.cpp
Douglas Gregor
dgregor at apple.com
Wed Mar 11 16:00:04 PDT 2009
Author: dgregor
Date: Wed Mar 11 18:00:04 2009
New Revision: 66734
URL: http://llvm.org/viewvc/llvm-project?rev=66734&view=rev
Log:
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.
Modified:
cfe/trunk/include/clang/AST/Decl.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/test/SemaCXX/class.cpp
cfe/trunk/test/SemaCXX/virtuals.cpp
Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=66734&r1=66733&r2=66734&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Wed Mar 11 18:00:04 2009
@@ -344,6 +344,19 @@
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)
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def?rev=66734&r1=66733&r2=66734&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def Wed Mar 11 18:00:04 2009
@@ -248,6 +248,8 @@
"'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_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,
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=66734&r1=66733&r2=66734&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Mar 11 18:00:04 2009
@@ -1431,10 +1431,15 @@
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 @@
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 @@
}
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 @@
if (InvalidDecl)
NewFD->setInvalidDecl();
+
+ isVirtualOkay = true;
} else {
Diag(D.getIdentifierLoc(), diag::err_destructor_not_member);
@@ -1811,12 +1823,16 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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;
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=66734&r1=66733&r2=66734&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Mar 11 18:00:04 2009
@@ -588,72 +588,8 @@
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));
Modified: cfe/trunk/test/SemaCXX/class.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/class.cpp?rev=66734&r1=66733&r2=66734&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/class.cpp (original)
+++ cfe/trunk/test/SemaCXX/class.cpp Wed Mar 11 18:00:04 2009
@@ -35,7 +35,7 @@
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 @@
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();
Modified: cfe/trunk/test/SemaCXX/virtuals.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/virtuals.cpp?rev=66734&r1=66733&r2=66734&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/virtuals.cpp (original)
+++ cfe/trunk/test/SemaCXX/virtuals.cpp Wed Mar 11 18:00:04 2009
@@ -8,10 +8,15 @@
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;
More information about the cfe-commits
mailing list