[cfe-commits] r58860 - in /cfe/trunk: include/clang/AST/DeclBase.h include/clang/AST/DeclCXX.h include/clang/Basic/DiagnosticKinds.def include/clang/Parse/Action.h include/clang/Parse/DeclSpec.h include/clang/Parse/Parser.h lib/AST/DeclBase.cpp lib/AST/DeclCXX.cpp lib/Parse/ParseDecl.cpp lib/Parse/ParseExprCXX.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp test/SemaCXX/conversion-function.cpp
Douglas Gregor
doug.gregor at gmail.com
Fri Nov 7 12:08:42 PST 2008
Author: dgregor
Date: Fri Nov 7 14:08:42 2008
New Revision: 58860
URL: http://llvm.org/viewvc/llvm-project?rev=58860&view=rev
Log:
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.
Added:
cfe/trunk/test/SemaCXX/conversion-function.cpp (with props)
Modified:
cfe/trunk/include/clang/AST/DeclBase.h
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/include/clang/Basic/DiagnosticKinds.def
cfe/trunk/include/clang/Parse/Action.h
cfe/trunk/include/clang/Parse/DeclSpec.h
cfe/trunk/include/clang/Parse/Parser.h
cfe/trunk/lib/AST/DeclBase.cpp
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/Parse/ParseDecl.cpp
cfe/trunk/lib/Parse/ParseExprCXX.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=58860&r1=58859&r2=58860&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Fri Nov 7 14:08:42 2008
@@ -68,6 +68,7 @@
CXXMethod,
CXXConstructor,
CXXDestructor,
+ CXXConversion,
Var,
ImplicitParam,
CXXClassVar,
@@ -91,7 +92,7 @@
TagFirst = Enum , TagLast = CXXRecord,
RecordFirst = Record , RecordLast = CXXRecord,
ValueFirst = EnumConstant , ValueLast = ParmVar,
- FunctionFirst = Function , FunctionLast = CXXDestructor,
+ FunctionFirst = Function , FunctionLast = CXXConversion,
VarFirst = Var , VarLast = ParmVar
};
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=58860&r1=58859&r2=58860&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Fri Nov 7 14:08:42 2008
@@ -21,6 +21,7 @@
class CXXRecordDecl;
class CXXConstructorDecl;
class CXXDestructorDecl;
+class CXXConversionDecl;
/// OverloadedFunctionDecl - An instance of this class represents a
/// set of overloaded functions. All of the functions have the same
@@ -53,8 +54,9 @@
void addOverload(FunctionDecl *FD) {
assert((!getNumFunctions() || (FD->getDeclContext() == getDeclContext())) &&
"Overloaded functions must all be in the same context");
- assert(FD->getIdentifier() == getIdentifier() &&
- "Overloaded functions must have the same name.");
+ assert((FD->getIdentifier() == getIdentifier() ||
+ isa<CXXConversionDecl>(FD)) &&
+ "Overloaded functions must have the same name or be conversions.");
Functions.push_back(FD);
}
@@ -238,12 +240,18 @@
// Destructor - The destructor of this C++ class.
CXXDestructorDecl *Destructor;
+ /// Conversions - Overload set containing the conversion functions
+ /// of this C++ class (but not its inherited conversion
+ /// functions). Each of the entries in this overload set is a
+ /// CXXConversionDecl.
+ OverloadedFunctionDecl Conversions;
+
CXXRecordDecl(TagKind TK, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id)
: RecordDecl(CXXRecord, TK, DC, L, Id), DeclContext(CXXRecord),
UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
Aggregate(true), Polymorphic(false), Bases(0), NumBases(0),
- Constructors(DC, Id), Destructor(0) { }
+ Constructors(DC, Id), Destructor(0), Conversions(DC, Id) { }
~CXXRecordDecl();
@@ -321,6 +329,19 @@
this->Destructor = Destructor;
}
+ /// getConversions - Retrieve the overload set containing all of the
+ /// conversion functions in this class.
+ OverloadedFunctionDecl *getConversionFunctions() {
+ return &Conversions;
+ }
+ const OverloadedFunctionDecl *getConversionFunctions() const {
+ return &Conversions;
+ }
+
+ /// addConversionFunction - Add a new conversion function to the
+ /// list of conversion functions.
+ void addConversionFunction(ASTContext &Context, CXXConversionDecl *ConvDecl);
+
/// isAggregate - Whether this class is an aggregate (C++
/// [dcl.init.aggr]), which is a class with no user-declared
/// constructors, no private or protected non-static data members,
@@ -418,7 +439,7 @@
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) {
- return D->getKind() >= CXXMethod && D->getKind() <= CXXConstructor;
+ return D->getKind() >= CXXMethod && D->getKind() <= CXXConversion;
}
static bool classof(const CXXMethodDecl *D) { return true; }
@@ -720,6 +741,60 @@
static CXXDestructorDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C);
};
+/// CXXConversionDecl - Represents a C++ conversion function within a
+/// class. For example:
+///
+/// @code
+/// class X {
+/// public:
+/// operator bool();
+/// };
+/// @endcode
+class CXXConversionDecl : public CXXMethodDecl {
+ /// Explicit - Whether this conversion function is marked
+ /// "explicit", meaning that it can only be applied when the user
+ /// explicitly wrote a cast. This is a C++0x feature.
+ bool Explicit : 1;
+
+ CXXConversionDecl(CXXRecordDecl *RD, SourceLocation L,
+ IdentifierInfo *Id, QualType T,
+ bool isInline, bool isExplicit)
+ : CXXMethodDecl(CXXConversion, RD, L, Id, T, false, isInline,
+ /*PrevDecl=*/0),
+ Explicit(isExplicit) { }
+
+public:
+ static CXXConversionDecl *Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation L, IdentifierInfo *Id,
+ QualType T, bool isInline,
+ bool isExplicit);
+
+ /// isExplicit - Whether this is an explicit conversion operator
+ /// (C++0x only). Explicit conversion operators are only considered
+ /// when the user has explicitly written a cast.
+ bool isExplicit() const { return Explicit; }
+
+ /// getConversionType - Returns the type that this conversion
+ /// function is converting to.
+ QualType getConversionType() const {
+ return getType()->getAsFunctionType()->getResultType();
+ }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) {
+ return D->getKind() == CXXConversion;
+ }
+ static bool classof(const CXXConversionDecl *D) { return true; }
+
+ /// EmitImpl - Serialize this CXXConversionDecl. Called by Decl::Emit.
+ // FIXME: Implement this.
+ //virtual void EmitImpl(llvm::Serializer& S) const;
+
+ /// CreateImpl - Deserialize a CXXConversionDecl. Called by Decl::Create.
+ // FIXME: Implement this.
+ static CXXConversionDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C);
+};
+
/// CXXClassVarDecl - Represents a static data member of a struct/union/class.
class CXXClassVarDecl : public VarDecl {
Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=58860&r1=58859&r2=58860&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Fri Nov 7 14:08:42 2008
@@ -1309,6 +1309,31 @@
"overloaded operator '%0' must be a non-static member function")
DIAG(err_operator_overload_post_incdec_must_be_int, ERROR,
"%0parameter of overloaded post-%1 operator must have type 'int' (not '%2')")
+DIAG(err_operator_missing_type_specifier, ERROR,
+ "missing type specifier after 'operator'")
+
+// C++ conversion functions
+DIAG(err_conv_function_not_member, ERROR,
+ "conversion function must be a non-static member function")
+DIAG(err_conv_function_return_type, ERROR,
+ "conversion function cannot have a return type")
+DIAG(err_conv_function_with_params, ERROR,
+ "conversion function cannot have any parameters")
+DIAG(err_conv_function_variadic, ERROR,
+ "conversion function cannot be variadic")
+DIAG(err_conv_function_to_array, ERROR,
+ "conversion function cannot convert to an array type")
+DIAG(err_conv_function_to_function, ERROR,
+ "conversion function cannot convert to a function type")
+DIAG(err_conv_function_redeclared, ERROR,
+ "conversion function cannot be redeclared")
+DIAG(warn_conv_to_self_not_used, WARNING,
+ "conversion function converting '%0' to itself will never be used")
+DIAG(warn_conv_to_base_not_used, WARNING,
+ "conversion function converting '%0' to its base class '%1' will never be used")
+DIAG(warn_conv_to_void_not_used, WARNING,
+ "conversion function converting '%0' to '%1' will never be used")
+
DIAG(warn_not_compound_assign, WARNING,
"use of unary operator that may be intended as compound assignment (%0=)")
Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=58860&r1=58859&r2=58860&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Fri Nov 7 14:08:42 2008
@@ -42,9 +42,10 @@
/// the parser has just done or is about to do when the method is called. They
/// are not requests that the actions module do the specified action.
///
-/// All of the methods here are optional except isTypeName(), which must be
-/// specified in order for the parse to complete accurately. The MinimalAction
-/// class does this bare-minimum of tracking to implement this functionality.
+/// All of the methods here are optional except isTypeName() and
+/// isCurrentClassName(), which must be specified in order for the
+/// parse to complete accurately. The MinimalAction class does this
+/// bare-minimum of tracking to implement this functionality.
class Action {
public:
/// Out-of-line virtual destructor to provide home for this class.
@@ -108,6 +109,14 @@
/// name of the innermost C++ class type currently being defined.
virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S) = 0;
+ /// getTypeAsString - Returns a string that describes the given
+ /// type. This callback is used in C++ to form identifiers for
+ /// special declarations that otherwise don't have simple names,
+ /// such as constructors, destructors, and conversion functions.
+ virtual std::string getTypeAsString(TypeTy *Type) {
+ return "<unknown type>";
+ }
+
/// ActOnDeclarator - This callback is invoked when a declarator is parsed and
/// 'Init' specifies the initializer if any. This is for things like:
/// "int X = 4" or "typedef int foo".
Modified: cfe/trunk/include/clang/Parse/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/DeclSpec.h?rev=58860&r1=58859&r2=58860&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Parse/DeclSpec.h Fri Nov 7 14:08:42 2008
@@ -610,7 +610,9 @@
DK_Abstract, // An abstract declarator (has no identifier)
DK_Normal, // A normal declarator (has an identifier).
DK_Constructor, // A C++ constructor (identifier is the class name)
- DK_Destructor // A C++ destructor (has no identifier)
+ DK_Destructor, // A C++ destructor (identifier is ~class name)
+ DK_Conversion // A C++ conversion function (identifier is
+ // "operator " then the type name)
};
private:
@@ -639,8 +641,9 @@
/// AsmLabel - The asm label, if specified.
Action::ExprTy *AsmLabel;
- // When Kind is DK_Constructor or DK_Destructor, the type associated
- // with the constructor or destructor.
+ // When Kind is DK_Constructor, DK_Destructor, or DK_Conversion, the
+ // type associated with the constructor, destructor, or conversion
+ // operator.
Action::TypeTy *Type;
public:
@@ -755,6 +758,16 @@
Type = Ty;
}
+ // SetConversionFunction - Set this declarator to be a C++
+ // conversion function declarator.
+ void SetConversionFunction(Action::TypeTy *Ty, IdentifierInfo *ID,
+ SourceLocation Loc) {
+ Identifier = ID;
+ IdentifierLoc = Loc;
+ Kind = DK_Conversion;
+ Type = Ty;
+ }
+
void AddTypeInfo(const DeclaratorChunk &TI) {
DeclTypeInfo.push_back(TI);
}
Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=58860&r1=58859&r2=58860&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Fri Nov 7 14:08:42 2008
@@ -475,6 +475,8 @@
/// simple-type-specifier.
void ParseCXXSimpleTypeSpecifier(DeclSpec &DS);
+ bool ParseCXXTypeSpecifierSeq(DeclSpec &DS);
+
//===--------------------------------------------------------------------===//
// C++ if/switch/while/for condition expression.
ExprResult ParseCXXCondition();
@@ -701,7 +703,7 @@
/// ParseDeclarator - Parse and verify a newly-initialized declarator.
void ParseDeclarator(Declarator &D);
- void ParseDeclaratorInternal(Declarator &D);
+ void ParseDeclaratorInternal(Declarator &D, bool PtrOperator = false);
void ParseTypeQualifierListOpt(DeclSpec &DS);
void ParseDirectDeclarator(Declarator &D);
void ParseParenDeclarator(Declarator &D);
@@ -737,6 +739,7 @@
//===--------------------------------------------------------------------===//
// C++ 13.5: Overloaded operators [over.oper]
IdentifierInfo *MaybeParseOperatorFunctionId();
+ TypeTy *ParseConversionFunctionId();
};
} // end namespace clang
Modified: cfe/trunk/lib/AST/DeclBase.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=58860&r1=58859&r2=58860&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclBase.cpp (original)
+++ cfe/trunk/lib/AST/DeclBase.cpp Fri Nov 7 14:08:42 2008
@@ -239,6 +239,7 @@
case CXXMethod:
case CXXConstructor:
case CXXDestructor:
+ case CXXConversion:
case CXXClassVar:
break;
}
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=58860&r1=58859&r2=58860&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Fri Nov 7 14:08:42 2008
@@ -48,6 +48,11 @@
if (isDefinition())
Destructor->Destroy(C);
+ for (OverloadedFunctionDecl::function_iterator func
+ = Conversions.function_begin();
+ func != Conversions.function_end(); ++func)
+ (*func)->Destroy(C);
+
RecordDecl::Destroy(C);
}
@@ -101,6 +106,11 @@
Constructors.addOverload(ConDecl);
}
+void CXXRecordDecl::addConversionFunction(ASTContext &Context,
+ CXXConversionDecl *ConvDecl) {
+ Conversions.addOverload(ConvDecl);
+}
+
CXXMethodDecl *
CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, IdentifierInfo *Id,
@@ -232,6 +242,14 @@
isImplicitlyDeclared);
}
+CXXConversionDecl *
+CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation L, IdentifierInfo *Id,
+ QualType T, bool isInline, bool isExplicit) {
+ void *Mem = C.getAllocator().Allocate<CXXConversionDecl>();
+ return new (Mem) CXXConversionDecl(RD, L, Id, T, isInline, isExplicit);
+}
+
CXXClassVarDecl *CXXClassVarDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, IdentifierInfo *Id,
QualType T, ScopedDecl *PrevDecl) {
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=58860&r1=58859&r2=58860&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Fri Nov 7 14:08:42 2008
@@ -1229,7 +1229,11 @@
ParseDeclaratorInternal(D);
}
-/// ParseDeclaratorInternal
+/// ParseDeclaratorInternal - Parse a C or C++ declarator. If
+/// PtrOperator is true, then this routine won't parse the final
+/// direct-declarator; therefore, it effectively parses the C++
+/// ptr-operator production.
+///
/// declarator: [C99 6.7.5]
/// pointer[opt] direct-declarator
/// [C++] '&' declarator [C++ 8p4, dcl.decl]
@@ -1239,13 +1243,21 @@
/// '*' type-qualifier-list[opt]
/// '*' type-qualifier-list[opt] pointer
///
-void Parser::ParseDeclaratorInternal(Declarator &D) {
+/// ptr-operator:
+/// '*' cv-qualifier-seq[opt]
+/// '&'
+/// [GNU] '&' restrict[opt] attributes[opt]
+/// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt] [TODO]
+void Parser::ParseDeclaratorInternal(Declarator &D, bool PtrOperator) {
tok::TokenKind Kind = Tok.getKind();
// Not a pointer, C++ reference, or block.
if (Kind != tok::star && (Kind != tok::amp || !getLang().CPlusPlus) &&
- (Kind != tok::caret || !getLang().Blocks))
- return ParseDirectDeclarator(D);
+ (Kind != tok::caret || !getLang().Blocks)) {
+ if (!PtrOperator)
+ ParseDirectDeclarator(D);
+ return;
+ }
// Otherwise, '*' -> pointer, '^' -> block, '&' -> reference.
SourceLocation Loc = ConsumeToken(); // Eat the * or &.
@@ -1257,7 +1269,7 @@
ParseTypeQualifierListOpt(DS);
// Recursively parse the declarator.
- ParseDeclaratorInternal(D);
+ ParseDeclaratorInternal(D, PtrOperator);
if (Kind == tok::star)
// Remember that we parsed a pointer type, and remember the type-quals.
D.AddTypeInfo(DeclaratorChunk::getPointer(DS.getTypeQualifiers(), Loc,
@@ -1290,7 +1302,7 @@
}
// Recursively parse the declarator.
- ParseDeclaratorInternal(D);
+ ParseDeclaratorInternal(D, PtrOperator);
if (D.getNumTypeObjects() > 0) {
// C++ [dcl.ref]p4: There shall be no references to references.
@@ -1382,7 +1394,13 @@
if (IdentifierInfo *II = MaybeParseOperatorFunctionId()) {
D.SetIdentifier(II, OperatorLoc);
} else {
- // This must be a user-defined conversion.
+ // This must be a conversion function (C++ [class.conv.fct]).
+ if (TypeTy *ConvType = ParseConversionFunctionId()) {
+ IdentifierInfo *II
+ = &PP.getIdentifierTable().get(std::string("operator ") +
+ Actions.getTypeAsString(ConvType));
+ D.SetConversionFunction(ConvType, II, OperatorLoc);
+ }
}
} else if (Tok.is(tok::l_paren)) {
// direct-declarator: '(' declarator ')'
Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=58860&r1=58859&r2=58860&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Fri Nov 7 14:08:42 2008
@@ -292,6 +292,32 @@
DS.Finish(Diags, PP.getSourceManager(), getLang());
}
+/// ParseCXXTypeSpecifierSeq - Parse a C++ type-specifier-seq (C++
+/// [dcl.name]), which is a non-empty sequence of type-specifiers,
+/// e.g., "const short int". Note that the DeclSpec is *not* finished
+/// by parsing the type-specifier-seq, because these sequences are
+/// typically followed by some form of declarator. Returns true and
+/// emits diagnostics if this is not a type-specifier-seq, false
+/// otherwise.
+///
+/// type-specifier-seq: [C++ 8.1]
+/// type-specifier type-specifier-seq[opt]
+///
+bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) {
+ DS.SetRangeStart(Tok.getLocation());
+ const char *PrevSpec = 0;
+ int isInvalid = 0;
+
+ // Parse one or more of the type specifiers.
+ if (!MaybeParseTypeSpecifier(DS, isInvalid, PrevSpec)) {
+ Diag(Tok.getLocation(), diag::err_operator_missing_type_specifier);
+ return true;
+ }
+ while (MaybeParseTypeSpecifier(DS, isInvalid, PrevSpec));
+
+ return false;
+}
+
/// MaybeParseOperatorFunctionId - Attempts to parse a C++ overloaded
/// operator name (C++ [over.oper]). If successful, returns the
/// predefined identifier that corresponds to that overloaded
@@ -365,3 +391,38 @@
return &PP.getIdentifierTable().getOverloadedOperator(Op);
}
}
+
+/// ParseConversionFunctionId - Parse a C++ conversion-function-id,
+/// which expresses the name of a user-defined conversion operator
+/// (C++ [class.conv.fct]p1). Returns the type that this operator is
+/// specifying a conversion for, or NULL if there was an error.
+///
+/// conversion-function-id: [C++ 12.3.2]
+/// operator conversion-type-id
+///
+/// conversion-type-id:
+/// type-specifier-seq conversion-declarator[opt]
+///
+/// conversion-declarator:
+/// ptr-operator conversion-declarator[opt]
+Parser::TypeTy *Parser::ParseConversionFunctionId() {
+ assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword");
+ ConsumeToken(); // 'operator'
+
+ // Parse the type-specifier-seq.
+ DeclSpec DS;
+ if (ParseCXXTypeSpecifierSeq(DS))
+ return 0;
+
+ // Parse the conversion-declarator, which is merely a sequence of
+ // ptr-operators.
+ Declarator D(DS, Declarator::TypeNameContext);
+ ParseDeclaratorInternal(D, /*PtrOperator=*/true);
+
+ // Finish up the type.
+ Action::TypeResult Result = Actions.ActOnTypeName(CurScope, D);
+ if (Result.isInvalid)
+ return 0;
+ else
+ return Result.Val;
+}
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=58860&r1=58859&r2=58860&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri Nov 7 14:08:42 2008
@@ -271,6 +271,7 @@
// 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 @@
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
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=58860&r1=58859&r2=58860&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Nov 7 14:08:42 2008
@@ -38,6 +38,11 @@
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 @@
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 @@
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() &&
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=58860&r1=58859&r2=58860&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Nov 7 14:08:42 2008
@@ -1004,6 +1004,82 @@
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 @@
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
//===----------------------------------------------------------------------===//
Added: cfe/trunk/test/SemaCXX/conversion-function.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/conversion-function.cpp?rev=58860&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/conversion-function.cpp (added)
+++ cfe/trunk/test/SemaCXX/conversion-function.cpp Fri Nov 7 14:08:42 2008
@@ -0,0 +1,42 @@
+// RUN: clang -fsyntax-only -verify %s
+class X {
+public:
+ operator bool();
+ operator int() const;
+};
+
+operator int(); // expected-error{{conversion function must be a non-static member function}}
+
+typedef int func_type(int);
+typedef int array_type[10];
+
+class Y {
+public:
+ void operator bool(int, ...) const; // expected-error{{conversion function cannot have a return type}} \
+ // expected-error{{conversion function cannot have any parameters}} \
+ // expected-error{{conversion function cannot be variadic}}
+ operator func_type(); // expected-error{{conversion function cannot convert to a function type}}
+ operator array_type(); // expected-error{{conversion function cannot convert to an array type}}
+};
+
+
+typedef int INT;
+typedef INT* INT_PTR;
+
+class Z {
+ operator int(); // expected-error{{previous declaration is here}}
+ operator int**(); // expected-error{{previous declaration is here}}
+
+ operator INT(); // expected-error{{conversion function cannot be redeclared}}
+ operator INT_PTR*(); // expected-error{{conversion function cannot be redeclared}}
+};
+
+
+class A { };
+
+class B : public A {
+public:
+ operator A&() const; // expected-warning{{conversion function converting 'class B' to its base class 'class A' will never be used}}
+ operator const void() const; // expected-warning{{conversion function converting 'class B' to 'void const' will never be used}}
+ operator const B(); // expected-warning{{conversion function converting 'class B' to itself will never be used}}
+};
Propchange: cfe/trunk/test/SemaCXX/conversion-function.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/trunk/test/SemaCXX/conversion-function.cpp
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cfe/trunk/test/SemaCXX/conversion-function.cpp
------------------------------------------------------------------------------
svn:mime-type = text/plain
More information about the cfe-commits
mailing list