forked from OSchip/llvm-project
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
This commit is contained in:
parent
cb0df597e0
commit
dbc5daf058
|
@ -68,6 +68,7 @@ public:
|
|||
CXXMethod,
|
||||
CXXConstructor,
|
||||
CXXDestructor,
|
||||
CXXConversion,
|
||||
Var,
|
||||
ImplicitParam,
|
||||
CXXClassVar,
|
||||
|
@ -91,7 +92,7 @@ public:
|
|||
TagFirst = Enum , TagLast = CXXRecord,
|
||||
RecordFirst = Record , RecordLast = CXXRecord,
|
||||
ValueFirst = EnumConstant , ValueLast = ParmVar,
|
||||
FunctionFirst = Function , FunctionLast = CXXDestructor,
|
||||
FunctionFirst = Function , FunctionLast = CXXConversion,
|
||||
VarFirst = Var , VarLast = ParmVar
|
||||
};
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ namespace clang {
|
|||
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 @@ public:
|
|||
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 @@ class CXXRecordDecl : public RecordDecl, public DeclContext {
|
|||
// 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 @@ public:
|
|||
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 @@ public:
|
|||
|
||||
// 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 @@ public:
|
|||
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 {
|
||||
|
||||
|
|
|
@ -1309,6 +1309,31 @@ DIAG(err_operator_overload_must_be_member, ERROR,
|
|||
"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=)")
|
||||
|
|
|
@ -42,9 +42,10 @@ namespace clang {
|
|||
/// 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 @@ public:
|
|||
/// 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".
|
||||
|
|
|
@ -610,7 +610,9 @@ public:
|
|||
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 @@ private:
|
|||
/// 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 @@ public:
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -475,6 +475,8 @@ private:
|
|||
/// simple-type-specifier.
|
||||
void ParseCXXSimpleTypeSpecifier(DeclSpec &DS);
|
||||
|
||||
bool ParseCXXTypeSpecifierSeq(DeclSpec &DS);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C++ if/switch/while/for condition expression.
|
||||
ExprResult ParseCXXCondition();
|
||||
|
@ -701,7 +703,7 @@ private:
|
|||
|
||||
/// 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 @@ private:
|
|||
//===--------------------------------------------------------------------===//
|
||||
// C++ 13.5: Overloaded operators [over.oper]
|
||||
IdentifierInfo *MaybeParseOperatorFunctionId();
|
||||
TypeTy *ParseConversionFunctionId();
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
@ -239,6 +239,7 @@ void Decl::addDeclKind(Kind k) {
|
|||
case CXXMethod:
|
||||
case CXXConstructor:
|
||||
case CXXDestructor:
|
||||
case CXXConversion:
|
||||
case CXXClassVar:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -48,6 +48,11 @@ void CXXRecordDecl::Destroy(ASTContext &C) {
|
|||
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 @@ CXXRecordDecl::addConstructor(ASTContext &Context,
|
|||
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 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
|
|||
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) {
|
||||
|
|
|
@ -1229,7 +1229,11 @@ void Parser::ParseDeclarator(Declarator &D) {
|
|||
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 @@ void Parser::ParseDeclarator(Declarator &D) {
|
|||
/// '*' 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 @@ void Parser::ParseDeclaratorInternal(Declarator &D) {
|
|||
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 @@ void Parser::ParseDeclaratorInternal(Declarator &D) {
|
|||
}
|
||||
|
||||
// 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 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
|
|||
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 ')'
|
||||
|
|
|
@ -292,6 +292,32 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
|
|||
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 @@ IdentifierInfo *Parser::MaybeParseOperatorFunctionId() {
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() &&
|
||||
|
|
|
@ -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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -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}}
|
||||
};
|
Loading…
Reference in New Issue