aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaDecl.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2008-10-31 09:07:45 +0000
committerDouglas Gregor <dgregor@apple.com>2008-10-31 09:07:45 +0000
commitb48fe3812047e84164925c8938ce82be0624c40c (patch)
tree8af13a860c7c055c80382ca3f0b1f9f2db7b7b23 /lib/Sema/SemaDecl.cpp
parente10b0f236bc8487445bc99b8d14bd40666b1998d (diff)
Add support for parsing and representing C++ constructor declarations.
Notes: - Constructors are never found by name lookup, so they'll never get pushed into any scope. Instead, they are stored as an OverloadedFunctionDecl in CXXRecordDecl for easy overloading. - There's a new action isCurrentClassName that determines whether an identifier is the name of the innermost class currently being defined; we use this to identify the declarator-id grammar rule that refers to a type-name. - MinimalAction does *not* support parsing constructors. - We now handle virtual and explicit function specifiers. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@58499 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaDecl.cpp')
-rw-r--r--lib/Sema/SemaDecl.cpp89
1 files changed, 88 insertions, 1 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 2306151279..16053cecdb 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -737,8 +737,88 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
}
bool isInline = D.getDeclSpec().isInlineSpecified();
+ bool isVirtual = D.getDeclSpec().isVirtualSpecified();
+ bool isExplicit = D.getDeclSpec().isExplicitSpecified();
+
FunctionDecl *NewFD;
- if (D.getContext() == Declarator::MemberContext) {
+ if (isCurrentClassName(*II, S)) {
+ // This is a C++ constructor declaration.
+ assert(D.getContext() == Declarator::MemberContext &&
+ "Constructors can only be declared in a member context");
+
+ // C++ [class.ctor]p3:
+ // A constructor shall not be virtual (10.3) or static (9.4). A
+ // constructor can be invoked for a const, volatile or const
+ // volatile object. A constructor shall not be declared const,
+ // volatile, or const volatile (9.3.2).
+ if (isVirtual) {
+ Diag(D.getIdentifierLoc(),
+ diag::err_constructor_cannot_be,
+ "virtual",
+ SourceRange(D.getDeclSpec().getVirtualSpecLoc()),
+ SourceRange(D.getIdentifierLoc()));
+ isVirtual = false;
+ }
+ if (SC == FunctionDecl::Static) {
+ Diag(D.getIdentifierLoc(),
+ diag::err_constructor_cannot_be,
+ "static",
+ SourceRange(D.getDeclSpec().getStorageClassSpecLoc()),
+ SourceRange(D.getIdentifierLoc()));
+ isVirtual = false;
+ }
+ if (D.getDeclSpec().hasTypeSpecifier()) {
+ // Constructors don't have return types, but the parser will
+ // happily parse something like:
+ //
+ // class X {
+ // float X(float);
+ // };
+ //
+ // The return type will be eliminated later.
+ Diag(D.getIdentifierLoc(),
+ diag::err_constructor_return_type,
+ SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()),
+ SourceRange(D.getIdentifierLoc()));
+ }
+ if (R->getAsFunctionTypeProto()->getTypeQuals() != 0) {
+ DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
+ if (FTI.TypeQuals & QualType::Const)
+ Diag(D.getIdentifierLoc(),
+ diag::err_invalid_qualified_constructor,
+ "const",
+ SourceRange(D.getIdentifierLoc()));
+ if (FTI.TypeQuals & QualType::Volatile)
+ Diag(D.getIdentifierLoc(),
+ diag::err_invalid_qualified_constructor,
+ "volatile",
+ SourceRange(D.getIdentifierLoc()));
+ if (FTI.TypeQuals & QualType::Restrict)
+ Diag(D.getIdentifierLoc(),
+ diag::err_invalid_qualified_constructor,
+ "restrict",
+ SourceRange(D.getIdentifierLoc()));
+ }
+
+ // Rebuild the function type "R" without any type qualifiers (in
+ // case any of the errors above fired) and with "void" as the
+ // return type, since constructors don't have return types. We
+ // *always* have to do this, because GetTypeForDeclarator will
+ // put in a result type of "int" when none was specified.
+ const FunctionTypeProto *Proto = R->getAsFunctionTypeProto();
+ R = Context.getFunctionType(Context.VoidTy, Proto->arg_type_begin(),
+ Proto->getNumArgs(),
+ Proto->isVariadic(),
+ 0);
+
+ // Create the new declaration
+ NewFD = CXXConstructorDecl::Create(Context,
+ cast<CXXRecordDecl>(CurContext),
+ D.getIdentifierLoc(), II, R,
+ isExplicit, isInline,
+ /*isImplicitlyDeclared=*/false);
+
+ } else if (D.getContext() == Declarator::MemberContext) {
// This is a C++ method declaration.
NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(CurContext),
D.getIdentifierLoc(), II, R,
@@ -826,6 +906,13 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
}
}
+ // C++ constructors are handled by a separate routine, 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 *ConDecl = dyn_cast<CXXConstructorDecl>(NewFD))
+ return ActOnConstructorDeclarator(ConDecl);
+
// Merge the decl with the existing one if appropriate. Since C functions
// are in a flat namespace, make sure we consider decls in outer scopes.
if (PrevDecl &&