diff options
author | Douglas Gregor <dgregor@apple.com> | 2008-10-31 09:07:45 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2008-10-31 09:07:45 +0000 |
commit | b48fe3812047e84164925c8938ce82be0624c40c (patch) | |
tree | 8af13a860c7c055c80382ca3f0b1f9f2db7b7b23 /lib/Sema/SemaDecl.cpp | |
parent | e10b0f236bc8487445bc99b8d14bd40666b1998d (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.cpp | 89 |
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 && |