diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-02-11 23:02:49 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-02-11 23:02:49 +0000 |
commit | 4e5cbdcbed0b0d8e1c319d70507886d66f8bda8b (patch) | |
tree | 5c7843528143b1e00b2c513c762ed1850c8aa081 /clang/lib/Sema/SemaOverload.cpp | |
parent | 318aea93bf1f9ea31d8e2889c6208aa4a277e774 (diff) | |
download | bcm5719-llvm-4e5cbdcbed0b0d8e1c319d70507886d66f8bda8b.tar.gz bcm5719-llvm-4e5cbdcbed0b0d8e1c319d70507886d66f8bda8b.zip |
Initial implementation of function overloading in C.
This commit adds a new attribute, "overloadable", that enables C++
function overloading in C. The attribute can only be added to function
declarations, e.g.,
int *f(int) __attribute__((overloadable));
If the "overloadable" attribute exists on a function with a given
name, *all* functions with that name (and in that scope) must have the
"overloadable" attribute. Sets of overloaded functions with the
"overloadable" attribute then follow the normal C++ rules for
overloaded functions, e.g., overloads must have different
parameter-type-lists from each other.
When calling an overloaded function in C, we follow the same
overloading rules as C++, with three extensions to the set of standard
conversions:
- A value of a given struct or union type T can be converted to the
type T. This is just the identity conversion. (In C++, this would
go through a copy constructor).
- A value of pointer type T* can be converted to a value of type U*
if T and U are compatible types. This conversion has Conversion
rank (it's considered a pointer conversion in C).
- A value of type T can be converted to a value of type U if T and U
are compatible (and are not both pointer types). This conversion
has Conversion rank (it's considered to be a new kind of
conversion unique to C, a "compatible" conversion).
Known defects (and, therefore, next steps):
1) The standard-conversion handling does not understand conversions
involving _Complex or vector extensions, so it is likely to get
these wrong. We need to add these conversions.
2) All overloadable functions with the same name will have the same
linkage name, which means we'll get a collision in the linker (if
not sooner). We'll need to mangle the names of these functions.
llvm-svn: 64336
Diffstat (limited to 'clang/lib/Sema/SemaOverload.cpp')
-rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 60 |
1 files changed, 39 insertions, 21 deletions
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index e40455b5c6d..e1939d329e9 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -45,6 +45,7 @@ GetConversionCategory(ImplicitConversionKind Kind) { ICC_Conversion, ICC_Conversion, ICC_Conversion, + ICC_Conversion, ICC_Conversion }; return Category[(int)Kind]; @@ -68,6 +69,7 @@ ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) { ICR_Conversion, ICR_Conversion, ICR_Conversion, + ICR_Conversion, ICR_Conversion }; return Rank[(int)Kind]; @@ -90,6 +92,7 @@ const char* GetImplicitConversionName(ImplicitConversionKind Kind) { "Pointer conversion", "Pointer-to-member conversion", "Boolean conversion", + "Compatible-types conversion", "Derived-to-base conversion" }; return Name[Kind]; @@ -371,7 +374,8 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, ImplicitConversionSequence ICS; if (IsStandardConversion(From, ToType, ICS.Standard)) ICS.ConversionKind = ImplicitConversionSequence::StandardConversion; - else if (IsUserDefinedConversion(From, ToType, ICS.UserDefined, + else if (getLangOptions().CPlusPlus && + IsUserDefinedConversion(From, ToType, ICS.UserDefined, !SuppressUserConversions, AllowExplicit)) { ICS.ConversionKind = ImplicitConversionSequence::UserDefinedConversion; // C++ [over.ics.user]p4: @@ -429,10 +433,6 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, { QualType FromType = From->getType(); - // There are no standard conversions for class types, so abort early. - if (FromType->isRecordType() || ToType->isRecordType()) - return false; - // Standard conversions (C++ [conv]) SCS.setAsIdentityConversion(); SCS.Deprecated = false; @@ -440,6 +440,15 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, SCS.FromTypePtr = FromType.getAsOpaquePtr(); SCS.CopyConstructor = 0; + // There are no standard conversions for class types in C++, so + // abort early. When overloading in C, however, we do permit + if (FromType->isRecordType() || ToType->isRecordType()) { + if (getLangOptions().CPlusPlus) + return false; + + // When we're overloading in C, we allow, as standard conversions, + } + // The first conversion can be an lvalue-to-rvalue conversion, // array-to-pointer conversion, or function-to-pointer conversion // (C++ 4p1). @@ -455,7 +464,10 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // If T is a non-class type, the type of the rvalue is the // cv-unqualified version of T. Otherwise, the type of the rvalue - // is T (C++ 4.1p1). + // is T (C++ 4.1p1). C++ can't get here with class types; in C, we + // just strip the qualifiers because they don't matter. + + // FIXME: Doesn't see through to qualifiers behind a typedef! FromType = FromType.getUnqualifiedType(); } // Array-to-pointer conversion (C++ 4.2) @@ -522,9 +534,10 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // point promotion, integral conversion, floating point conversion, // floating-integral conversion, pointer conversion, // pointer-to-member conversion, or boolean conversion (C++ 4p1). + // For overloading in C, this can also be a "compatible-type" + // conversion. bool IncompatibleObjC = false; - if (Context.getCanonicalType(FromType).getUnqualifiedType() == - Context.getCanonicalType(ToType).getUnqualifiedType()) { + if (Context.hasSameUnqualifiedType(FromType, ToType)) { // The unqualified versions of the types are the same: there's no // conversion to do. SCS.Second = ICK_Identity; @@ -580,6 +593,11 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, FromType->isMemberPointerType())) { SCS.Second = ICK_Boolean_Conversion; FromType = Context.BoolTy; + } + // Compatible conversions (Clang extension for C function overloading) + else if (!getLangOptions().CPlusPlus && + Context.typesAreCompatible(ToType, FromType)) { + SCS.Second = ICK_Compatible_Conversion; } else { // No second conversion required. SCS.Second = ICK_Identity; @@ -847,6 +865,16 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, return true; } + // When we're overloading in C, we allow a special kind of pointer + // conversion for compatible-but-not-identical pointee types. + if (!getLangOptions().CPlusPlus && + Context.typesAreCompatible(FromPointeeType, ToPointeeType)) { + ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, + ToPointeeType, + ToType, Context); + return true; + } + // C++ [conv.ptr]p3: // // An rvalue of type "pointer to cv D," where D is a class type, @@ -860,7 +888,8 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, // // Note that we do not check for ambiguity or inaccessibility // here. That is handled by CheckPointerConversion. - if (FromPointeeType->isRecordType() && ToPointeeType->isRecordType() && + if (getLangOptions().CPlusPlus && + FromPointeeType->isRecordType() && ToPointeeType->isRecordType() && IsDerivedFrom(FromPointeeType, ToPointeeType)) { ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, ToPointeeType, @@ -1756,18 +1785,7 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, ImplicitConversionSequence Sema::TryCopyInitialization(Expr *From, QualType ToType, bool SuppressUserConversions) { - if (!getLangOptions().CPlusPlus) { - // In C, copy initialization is the same as performing an assignment. - AssignConvertType ConvTy = - CheckSingleAssignmentConstraints(ToType, From); - ImplicitConversionSequence ICS; - if (getLangOptions().NoExtensions? ConvTy != Compatible - : ConvTy == Incompatible) - ICS.ConversionKind = ImplicitConversionSequence::BadConversion; - else - ICS.ConversionKind = ImplicitConversionSequence::StandardConversion; - return ICS; - } else if (ToType->isReferenceType()) { + if (ToType->isReferenceType()) { ImplicitConversionSequence ICS; CheckReferenceInit(From, ToType, &ICS, SuppressUserConversions); return ICS; |