summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2008-11-07 20:08:42 +0000
committerDouglas Gregor <dgregor@apple.com>2008-11-07 20:08:42 +0000
commitdbc5daf05882c1c1934b35d5899b6ca53ce4cff9 (patch)
treeaf766082edf0c17460eb8950a94a9b87000fec02 /clang/lib/Sema
parentcb0df597e0f7f43b14cbed1f9dd1f39b22fe08be (diff)
downloadbcm5719-llvm-dbc5daf05882c1c1934b35d5899b6ca53ce4cff9.tar.gz
bcm5719-llvm-dbc5daf05882c1c1934b35d5899b6ca53ce4cff9.zip
Parsing, ASTs, and semantic analysis for the declaration of conversion
functions in C++, e.g., struct X { operator bool() const; }; Note that these conversions don't actually do anything, since we don't yet have the ability to use them for implicit or explicit conversions. llvm-svn: 58860
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/Sema.h4
-rw-r--r--clang/lib/Sema/SemaDecl.cpp23
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp135
3 files changed, 162 insertions, 0 deletions
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h
index f9dd25788cd..d1da9e2944a 100644
--- a/clang/lib/Sema/Sema.h
+++ b/clang/lib/Sema/Sema.h
@@ -271,6 +271,7 @@ private:
// Symbol table / Decl tracking callbacks: SemaDecl.cpp.
//
virtual TypeTy *isTypeName(const IdentifierInfo &II, Scope *S);
+ virtual std::string getTypeAsString(TypeTy *Type);
virtual DeclTy *ActOnDeclarator(Scope *S, Declarator &D, DeclTy *LastInGroup);
virtual DeclTy *ActOnParamDeclarator(Scope *S, Declarator &D);
virtual void ActOnParamDefaultArgument(DeclTy *param,
@@ -845,8 +846,11 @@ public:
FunctionDecl::StorageClass& SC);
bool CheckDestructorDeclarator(Declarator &D, QualType &R,
FunctionDecl::StorageClass& SC);
+ bool CheckConversionDeclarator(Declarator &D, QualType &R,
+ FunctionDecl::StorageClass& SC);
DeclTy *ActOnConstructorDeclarator(CXXConstructorDecl *Constructor);
DeclTy *ActOnDestructorDeclarator(CXXDestructorDecl *Destructor);
+ DeclTy *ActOnConversionDeclarator(CXXConversionDecl *Conversion);
//===--------------------------------------------------------------------===//
// C++ Derived Classes
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index fd94c80d8b9..12a4b08e919 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -38,6 +38,11 @@ Sema::TypeTy *Sema::isTypeName(const IdentifierInfo &II, Scope *S) {
return 0;
}
+std::string Sema::getTypeAsString(TypeTy *Type) {
+ QualType Ty = QualType::getFromOpaquePtr(Type);
+ return Ty.getAsString();
+}
+
DeclContext *Sema::getDCParent(DeclContext *DC) {
// If CurContext is a ObjC method, getParent() will return NULL.
if (isa<ObjCMethodDecl>(DC))
@@ -835,6 +840,22 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
if (isInvalidDecl)
NewFD->setInvalidDecl();
+ } else if (D.getKind() == Declarator::DK_Conversion) {
+ if (D.getContext() != Declarator::MemberContext) {
+ Diag(D.getIdentifierLoc(),
+ diag::err_conv_function_not_member);
+ return 0;
+ } else {
+ bool isInvalidDecl = CheckConversionDeclarator(D, R, SC);
+
+ NewFD = CXXConversionDecl::Create(Context,
+ cast<CXXRecordDecl>(CurContext),
+ D.getIdentifierLoc(), II, R,
+ isInline, isExplicit);
+
+ if (isInvalidDecl)
+ NewFD->setInvalidDecl();
+ }
} else if (D.getContext() == Declarator::MemberContext) {
// This is a C++ method declaration.
NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(CurContext),
@@ -931,6 +952,8 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
return ActOnConstructorDeclarator(Constructor);
else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(NewFD))
return ActOnDestructorDeclarator(Destructor);
+ else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(NewFD))
+ return ActOnConversionDeclarator(Conversion);
// Extra checking for C++ overloaded operators (C++ [over.oper]).
if (NewFD->isOverloadedOperator() &&
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 09f4cbd2a6a..fe7efbae5f8 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -1004,6 +1004,82 @@ bool Sema::CheckDestructorDeclarator(Declarator &D, QualType &R,
return isInvalid;
}
+/// CheckConversionDeclarator - Called by ActOnDeclarator to check the
+/// well-formednes of the conversion function declarator @p D with
+/// type @p R. If there are any errors in the declarator, this routine
+/// will emit diagnostics and return true. Otherwise, it will return
+/// false. Either way, the type @p R will be updated to reflect a
+/// well-formed type for the conversion operator.
+bool Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
+ FunctionDecl::StorageClass& SC) {
+ bool isInvalid = false;
+
+ // C++ [class.conv.fct]p1:
+ // Neither parameter types nor return type can be specified. The
+ // type of a conversion function (8.3.5) is “function taking no
+ // parameter returning conversion-type-id.”
+ if (SC == FunctionDecl::Static) {
+ Diag(D.getIdentifierLoc(),
+ diag::err_conv_function_not_member,
+ "static",
+ SourceRange(D.getDeclSpec().getStorageClassSpecLoc()),
+ SourceRange(D.getIdentifierLoc()));
+ isInvalid = true;
+ SC = FunctionDecl::None;
+ }
+ if (D.getDeclSpec().hasTypeSpecifier()) {
+ // Conversion functions don't have return types, but the parser will
+ // happily parse something like:
+ //
+ // class X {
+ // float operator bool();
+ // };
+ //
+ // The return type will be changed later anyway.
+ Diag(D.getIdentifierLoc(),
+ diag::err_conv_function_return_type,
+ SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()),
+ SourceRange(D.getIdentifierLoc()));
+ }
+
+ // Make sure we don't have any parameters.
+ if (R->getAsFunctionTypeProto()->getNumArgs() > 0) {
+ Diag(D.getIdentifierLoc(), diag::err_conv_function_with_params);
+
+ // Delete the parameters.
+ DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
+ if (FTI.NumArgs) {
+ delete [] FTI.ArgInfo;
+ FTI.NumArgs = 0;
+ FTI.ArgInfo = 0;
+ }
+ }
+
+ // Make sure the conversion function isn't variadic.
+ if (R->getAsFunctionTypeProto()->isVariadic())
+ Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic);
+
+ // C++ [class.conv.fct]p4:
+ // The conversion-type-id shall not represent a function type nor
+ // an array type.
+ QualType ConvType = QualType::getFromOpaquePtr(D.getDeclaratorIdType());
+ if (ConvType->isArrayType()) {
+ Diag(D.getIdentifierLoc(), diag::err_conv_function_to_array);
+ ConvType = Context.getPointerType(ConvType);
+ } else if (ConvType->isFunctionType()) {
+ Diag(D.getIdentifierLoc(), diag::err_conv_function_to_function);
+ ConvType = Context.getPointerType(ConvType);
+ }
+
+ // Rebuild the function type "R" without any parameters (in case any
+ // of the errors above fired) and with the conversion type as the
+ // return type.
+ R = Context.getFunctionType(ConvType, 0, 0, false,
+ R->getAsFunctionTypeProto()->getTypeQuals());
+
+ return isInvalid;
+}
+
/// ActOnConstructorDeclarator - Called by ActOnDeclarator to complete
/// the declaration of the given C++ constructor ConDecl that was
/// built from declarator D. This routine is responsible for checking
@@ -1092,6 +1168,65 @@ Sema::DeclTy *Sema::ActOnDestructorDeclarator(CXXDestructorDecl *Destructor) {
return (DeclTy *)Destructor;
}
+/// ActOnConversionDeclarator - Called by ActOnDeclarator to complete
+/// the declaration of the given C++ conversion function. This routine
+/// is responsible for recording the conversion function in the C++
+/// class, if possible.
+Sema::DeclTy *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
+ assert(Conversion && "Expected to receive a conversion function declaration");
+
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CurContext);
+
+ // Make sure we aren't redeclaring the conversion function.
+ QualType ConvType = Context.getCanonicalType(Conversion->getConversionType());
+ OverloadedFunctionDecl *Conversions = ClassDecl->getConversionFunctions();
+ for (OverloadedFunctionDecl::function_iterator Func
+ = Conversions->function_begin();
+ Func != Conversions->function_end(); ++Func) {
+ CXXConversionDecl *OtherConv = cast<CXXConversionDecl>(*Func);
+ if (ConvType == Context.getCanonicalType(OtherConv->getConversionType())) {
+ Diag(Conversion->getLocation(), diag::err_conv_function_redeclared);
+ Diag(OtherConv->getLocation(),
+ OtherConv->isThisDeclarationADefinition()?
+ diag::err_previous_definition
+ : diag::err_previous_declaration);
+ Conversion->setInvalidDecl();
+ return (DeclTy *)Conversion;
+ }
+ }
+
+ // C++ [class.conv.fct]p1:
+ // [...] A conversion function is never used to convert a
+ // (possibly cv-qualified) object to the (possibly cv-qualified)
+ // same object type (or a reference to it), to a (possibly
+ // cv-qualified) base class of that type (or a reference to it),
+ // or to (possibly cv-qualified) void.
+ // FIXME: Suppress this warning if the conversion function ends up
+ // being a virtual function that overrides a virtual function in a
+ // base class.
+ QualType ClassType
+ = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl));
+ if (const ReferenceType *ConvTypeRef = ConvType->getAsReferenceType())
+ ConvType = ConvTypeRef->getPointeeType();
+ if (ConvType->isRecordType()) {
+ ConvType = Context.getCanonicalType(ConvType).getUnqualifiedType();
+ if (ConvType == ClassType)
+ Diag(Conversion->getLocation(), diag::warn_conv_to_self_not_used,
+ ClassType.getAsString());
+ else if (IsDerivedFrom(ClassType, ConvType))
+ Diag(Conversion->getLocation(), diag::warn_conv_to_base_not_used,
+ ClassType.getAsString(),
+ ConvType.getAsString());
+ } else if (ConvType->isVoidType()) {
+ Diag(Conversion->getLocation(), diag::warn_conv_to_void_not_used,
+ ClassType.getAsString(), ConvType.getAsString());
+ }
+
+ ClassDecl->addConversionFunction(Context, Conversion);
+
+ return (DeclTy *)Conversion;
+}
+
//===----------------------------------------------------------------------===//
// Namespace Handling
//===----------------------------------------------------------------------===//
OpenPOWER on IntegriCloud