aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaDecl.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2008-12-15 21:24:18 +0000
committerDouglas Gregor <dgregor@apple.com>2008-12-15 21:24:18 +0000
commit9e7d9de3ef538c1473248238b76a6d7b16f5f684 (patch)
tree272828d09e3dd9dfbcbd05538158ee64fa7312fe /lib/Sema/SemaDecl.cpp
parent9fed5169477cfca54e97069bca035f6453b1ab84 (diff)
Place constructors and destructors into the DeclContext of the class,
just like all other members, and remove the special variables in CXXRecordDecl to store them. This eliminates a lot of special-case code for constructors and destructors, including ActOnConstructor/ActOnDeclarator and special lookup rules in LookupDecl. The result is far more uniform and manageable. Diagnose the redeclaration of member functions. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61048 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaDecl.cpp')
-rw-r--r--lib/Sema/SemaDecl.cpp121
1 files changed, 71 insertions, 50 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index fbf89ae311..577cc7a97e 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -138,20 +138,20 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) {
FD->getDeclName());
Ovl->addOverload(cast<FunctionDecl>(Prev));
- // If there is an ame binding for the existing FunctionDecl,
- // remove it.
- for (IdentifierResolver::iterator I
- = IdResolver.begin(FD->getDeclName(), FD->getDeclContext(),
- false/*LookInParentCtx*/),
- E = IdResolver.end(); I != E; ++I) {
- if (*I == Prev) {
- IdResolver.RemoveDecl(*I);
- S->RemoveDecl(*I);
- break;
- }
- }
+ // If there is a name binding for the existing FunctionDecl,
+ // remove it.
+ for (IdentifierResolver::iterator I
+ = IdResolver.begin(FD->getDeclName(), FD->getDeclContext(),
+ false/*LookInParentCtx*/),
+ E = IdResolver.end(); I != E; ++I) {
+ if (*I == Prev) {
+ IdResolver.RemoveDecl(*I);
+ S->RemoveDecl(*I);
+ break;
+ }
+ }
- // Add the name binding for the OverloadedFunctionDecl.
+ // Add the name binding for the OverloadedFunctionDecl.
IdResolver.AddDecl(Ovl);
// Update the context with the newly-created overloaded
@@ -246,24 +246,6 @@ Decl *Sema::LookupDecl(DeclarationName Name, unsigned NSI, Scope *S,
} else if (LookupCtx) {
assert(getLangOptions().CPlusPlus && "No qualified name lookup in C");
- switch (Name.getNameKind()) {
- case DeclarationName::CXXConstructorName:
- if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(LookupCtx))
- return const_cast<CXXRecordDecl *>(Record)->getConstructors();
- else
- return 0;
-
- case DeclarationName::CXXDestructorName:
- if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(LookupCtx))
- return Record->getDestructor();
- else
- return 0;
-
- default:
- // Normal name lookup.
- break;
- }
-
// Perform qualified name lookup into the LookupCtx.
// FIXME: Will need to look into base classes and such.
DeclContext::lookup_const_iterator I, E;
@@ -565,6 +547,26 @@ Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, bool &Redeclaration) {
Diag(Old->getLocation(), PrevDiag);
return New;
}
+
+ // C++ [class.mem]p1:
+ // [...] A member shall not be declared twice in the
+ // member-specification, except that a nested class or member
+ // class template can be declared and then later defined.
+ if (OldMethod->getLexicalDeclContext() ==
+ NewMethod->getLexicalDeclContext()) {
+ unsigned NewDiag;
+ if (isa<CXXConstructorDecl>(OldMethod))
+ NewDiag = diag::err_constructor_redeclared;
+ else if (isa<CXXDestructorDecl>(NewMethod))
+ NewDiag = diag::err_destructor_redeclared;
+ else if (isa<CXXConversionDecl>(NewMethod))
+ NewDiag = diag::err_conv_function_redeclared;
+ else
+ NewDiag = diag::err_member_redeclared;
+
+ Diag(New->getLocation(), NewDiag);
+ Diag(Old->getLocation(), PrevDiag);
+ }
}
// (C++98 8.3.5p3):
@@ -1117,6 +1119,11 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
// Handle attributes.
ProcessDeclAttributes(NewFD, D);
+ // Set the lexical context. If the declarator has a C++
+ // scope specifier, the lexical context will be different
+ // from the semantic context.
+ NewFD->setLexicalDeclContext(CurContext);
+
// Handle GNU asm-label extension (encoded as an attribute).
if (Expr *E = (Expr*) D.getAsmLabel()) {
// The parser guarantees this is a string.
@@ -1189,18 +1196,33 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
}
}
- // C++ constructors and destructors are handled by separate
- // routines, since they don't require any declaration merging (C++
- // [class.mfct]p2) and they aren't ever pushed into scope, because
- // they can't be found by name lookup anyway (C++ [class.ctor]p2).
- if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD))
- return ActOnConstructorDeclarator(Constructor);
- else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(NewFD))
- return ActOnDestructorDeclarator(Destructor);
-
- // Extra checking for conversion functions, including recording
- // the conversion function in its class.
- if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(NewFD))
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) {
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(DC);
+
+ // C++ [class.copy]p3:
+ // A declaration of a constructor for a class X is ill-formed if
+ // its first parameter is of type (optionally cv-qualified) X and
+ // either there are no other parameters or else all other
+ // parameters have default arguments.
+ if ((Constructor->getNumParams() == 1) ||
+ (Constructor->getNumParams() > 1 &&
+ Constructor->getParamDecl(1)->getDefaultArg() != 0)) {
+ QualType ParamType = Constructor->getParamDecl(0)->getType();
+ QualType ClassTy = Context.getTagDeclType(ClassDecl);
+ if (Context.getCanonicalType(ParamType).getUnqualifiedType()
+ == ClassTy) {
+ Diag(Constructor->getLocation(), diag::err_constructor_byvalue_arg)
+ << SourceRange(Constructor->getParamDecl(0)->getLocation());
+ Constructor->setInvalidDecl();
+ }
+ }
+
+ // Notify the class that we've added a constructor.
+ ClassDecl->addedConstructor(Context, Constructor);
+ }
+ else if (isa<CXXDestructorDecl>(NewFD))
+ cast<CXXRecordDecl>(NewFD->getParent())->setUserDeclaredDestructor(true);
+ else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(NewFD))
ActOnConversionDeclarator(Conversion);
// Extra checking for C++ overloaded operators (C++ [over.oper]).
@@ -1268,11 +1290,6 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
CheckCXXDefaultArguments(NewFD);
}
- // Set the lexical context. If the declarator has a C++
- // scope specifier, the lexical context will be different
- // from the semantic context.
- NewFD->setLexicalDeclContext(CurContext);
-
return NewFD;
}
}
@@ -1965,7 +1982,9 @@ void Sema::ActOnUninitializedDecl(DeclTy *dcl) {
// function return type, in the declaration of a class member
// within its class declaration (9.2), and where the extern
// specifier is explicitly used.
- if (Type->isReferenceType() && Var->getStorageClass() != VarDecl::Extern) {
+ if (Type->isReferenceType() &&
+ Var->getStorageClass() != VarDecl::Extern &&
+ Var->getStorageClass() != VarDecl::PrivateExtern) {
Diag(Var->getLocation(), diag::err_reference_var_requires_init)
<< Var->getDeclName()
<< SourceRange(Var->getLocation(), Var->getLocation());
@@ -1984,7 +2003,9 @@ void Sema::ActOnUninitializedDecl(DeclTy *dcl) {
QualType InitType = Type;
if (const ArrayType *Array = Context.getAsArrayType(Type))
InitType = Array->getElementType();
- if (InitType->isRecordType()) {
+ if (Var->getStorageClass() != VarDecl::Extern &&
+ Var->getStorageClass() != VarDecl::PrivateExtern &&
+ InitType->isRecordType()) {
const CXXConstructorDecl *Constructor
= PerformInitializationByConstructor(InitType, 0, 0,
Var->getLocation(),