aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Attr.h9
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.def6
-rw-r--r--include/clang/Parse/AttributeList.h1
-rw-r--r--lib/Parse/AttributeList.cpp3
-rw-r--r--lib/Sema/SemaDecl.cpp44
-rw-r--r--lib/Sema/SemaDeclAttr.cpp16
-rw-r--r--lib/Sema/SemaExpr.cpp6
-rw-r--r--lib/Sema/SemaExprCXX.cpp2
-rw-r--r--lib/Sema/SemaLookup.cpp23
-rw-r--r--lib/Sema/SemaOverload.cpp60
-rw-r--r--lib/Sema/SemaOverload.h31
11 files changed, 160 insertions, 41 deletions
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
index 38e2b9ecb1..d446a352fb 100644
--- a/include/clang/AST/Attr.h
+++ b/include/clang/AST/Attr.h
@@ -43,6 +43,7 @@ public:
NoThrow,
ObjCGC,
ObjCNSObject,
+ Overloadable, // Clang-specific
Packed,
StdCall,
TransparentUnion,
@@ -429,6 +430,14 @@ static bool classof(const Attr *A) { return A->getKind() == ObjCNSObject; }
static bool classof(const ObjCNSObjectAttr *A) { return true; }
};
+class OverloadableAttr : public Attr {
+public:
+ OverloadableAttr() : Attr(Overloadable) { }
+
+ static bool classof(const Attr *A) { return A->getKind() == Overloadable; }
+ static bool classof(const OverloadableAttr *) { return true; }
+};
+
class BlocksAttr : public Attr {
public:
enum BlocksAttrTypes {
diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def
index 9cec83a411..9319fb0a4e 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.def
+++ b/include/clang/Basic/DiagnosticSemaKinds.def
@@ -393,6 +393,12 @@ DIAG(err_attribute_cleanup_func_arg_incompatible_type, ERROR,
// Clang-Specific Attributes
DIAG(err_attribute_iboutlet_non_ivar, ERROR,
"'iboutlet' attribute can only be applied to instance variables")
+DIAG(err_attribute_overloadable_not_function, ERROR,
+ "'overloadable' attribute can only be applied to a function")
+DIAG(err_attribute_overloadable_missing, ERROR,
+ "overloaded function %0 must have the 'overloadable' attribute")
+DIAG(note_attribute_overloadable_prev_overload, NOTE,
+ "previous overload of function is here")
// Function Parameter Semantic Analysis.
DIAG(err_param_with_void_type, ERROR,
diff --git a/include/clang/Parse/AttributeList.h b/include/clang/Parse/AttributeList.h
index bca12a3e60..147fa1bd56 100644
--- a/include/clang/Parse/AttributeList.h
+++ b/include/clang/Parse/AttributeList.h
@@ -62,6 +62,7 @@ public:
AT_nonnull,
AT_noreturn,
AT_nothrow,
+ AT_overloadable, // Clang-specific
AT_packed,
AT_pure,
AT_stdcall,
diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp
index eb0527dcf9..954e93e056 100644
--- a/lib/Parse/AttributeList.cpp
+++ b/lib/Parse/AttributeList.cpp
@@ -98,6 +98,9 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
if (!memcmp(Str, "constructor", 11)) return AT_constructor;
if (!memcmp(Str, "unavailable", 11)) return AT_unavailable;
break;
+ case 12:
+ if (!memcmp(Str, "overloadable", 12)) return AT_overloadable;
+ break;
case 13:
if (!memcmp(Str, "address_space", 13)) return AT_address_space;
if (!memcmp(Str, "always_inline", 13)) return AT_always_inline;
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index a3e0232987..de06ca610c 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -113,6 +113,25 @@ void Sema::PopDeclContext() {
CurContext = getContainingDC(CurContext);
}
+/// \brief Determine whether we allow overloading of the function
+/// PrevDecl with another declaration.
+///
+/// This routine determines whether overloading is possible, not
+/// whether some new function is actually an overload. It will return
+/// true in C++ (where we can always provide overloads) or, as an
+/// extension, in C when the previous function is already an
+/// overloaded function declaration or has the "overloadable"
+/// attribute.
+static bool AllowOverloadingOfFunction(Decl *PrevDecl, ASTContext &Context) {
+ if (Context.getLangOptions().CPlusPlus)
+ return true;
+
+ if (isa<OverloadedFunctionDecl>(PrevDecl))
+ return true;
+
+ return PrevDecl->getAttr<OverloadableAttr>() != 0;
+}
+
/// Add this decl to the scope shadowed decl chains.
void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) {
// Move up the scope chain until we find the nearest enclosing
@@ -173,7 +192,8 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) {
return;
}
}
- } else if (getLangOptions().CPlusPlus && isa<FunctionDecl>(D)) {
+ } else if (isa<FunctionDecl>(D) &&
+ AllowOverloadingOfFunction(D, Context)) {
// We are pushing the name of a function, which might be an
// overloaded name.
FunctionDecl *FD = cast<FunctionDecl>(D);
@@ -1637,15 +1657,16 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// 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.
+ bool OverloadableAttrRequired = false;
bool Redeclaration = false;
if (PrevDecl &&
(!getLangOptions().CPlusPlus||isDeclInScope(PrevDecl, DC, S))) {
- // If C++, determine whether NewFD is an overload of PrevDecl or
+ // Determine whether NewFD is an overload of PrevDecl or
// a declaration that requires merging. If it's an overload,
// there's no more work to do here; we'll just add the new
// function to the scope.
OverloadedFunctionDecl::function_iterator MatchedDecl;
- if (!getLangOptions().CPlusPlus ||
+ if (!AllowOverloadingOfFunction(PrevDecl, Context) ||
!IsOverload(NewFD, PrevDecl, MatchedDecl)) {
Decl *OldDecl = PrevDecl;
@@ -1672,6 +1693,12 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
}
}
+
+ // If we're in C, this new declaration better have the
+ // "overloadable" attribute on it.
+ if (!getLangOptions().CPlusPlus &&
+ PrevDecl->getAttr<OverloadableAttr>())
+ OverloadableAttrRequired = true;
}
if (D.getCXXScopeSpec().isSet() &&
@@ -1712,6 +1739,17 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// (for example to check for conflicts, etc).
ProcessDeclAttributes(NewFD, D);
+ if (OverloadableAttrRequired && !NewFD->getAttr<OverloadableAttr>()) {
+ // If a function name is overloadable in C, then every function
+ // with that name must be marked "overloadable".
+ Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing)
+ << NewFD;
+ if (PrevDecl)
+ Diag(PrevDecl->getLocation(),
+ diag::note_attribute_overloadable_prev_overload);
+ NewFD->addAttr(new OverloadableAttr);
+ }
+
if (getLangOptions().CPlusPlus) {
// In C++, check default arguments now that we have merged decls. Unless
// the lexical context is the class, because in this case this is done
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 2a6da06f71..b4e3dd99ac 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -593,6 +593,21 @@ static void HandleObjCNSObject(Decl *d, const AttributeList &Attr, Sema &S) {
d->addAttr(new ObjCNSObjectAttr);
}
+static void
+HandleOverloadableAttr(Decl *D, const AttributeList &Attr, Sema &S) {
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+
+ if (!isa<FunctionDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_overloadable_not_function);
+ return;
+ }
+
+ D->addAttr(new OverloadableAttr);
+}
+
static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (!Attr.getParameterName()) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
@@ -1301,6 +1316,7 @@ static void ProcessDeclAttribute(Decl *D, const AttributeList &Attr, Sema &S) {
HandleTransparentUnionAttr(D, Attr, S);
break;
case AttributeList::AT_objc_gc: HandleObjCGCAttr (D, Attr, S); break;
+ case AttributeList::AT_overloadable:HandleOverloadableAttr(D, Attr, S); break;
case AttributeList::AT_nsobject: HandleObjCNSObject (D, Attr, S); break;
case AttributeList::AT_blocks: HandleBlocksAttr (D, Attr, S); break;
case AttributeList::AT_sentinel: HandleSentinelAttr (D, Attr, S); break;
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index c2051a5016..4ac7214518 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1909,12 +1909,16 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
Ovl = dyn_cast<OverloadedFunctionDecl>(DRExpr->getDecl());
}
- if (getLangOptions().CPlusPlus && (FDecl || Ovl || UnqualifiedName)) {
+ if (Ovl || (getLangOptions().CPlusPlus && (FDecl || UnqualifiedName))) {
// We don't perform ADL for builtins.
if (FDecl && FDecl->getIdentifier() &&
FDecl->getIdentifier()->getBuiltinID())
ADL = false;
+ // We don't perform ADL in C.
+ if (!getLangOptions().CPlusPlus)
+ ADL = false;
+
if (Ovl || ADL) {
FDecl = ResolveOverloadedCallFn(Fn, DRExpr? DRExpr->getDecl() : 0,
UnqualifiedName, LParenLoc, Args,
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 4bfd4fa0b5..6ce8331555 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -809,6 +809,8 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
case ICK_Integral_Conversion:
case ICK_Floating_Conversion:
case ICK_Floating_Integral:
+ case ICK_Compatible_Conversion:
+ // FIXME: Go deeper to get the unqualified type!
FromType = ToType.getUnqualifiedType();
ImpCastExprToType(From, FromType);
break;
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index ee4c14d0ca..f4bfe5ca3c 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -776,8 +776,29 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind,
for (IdentifierResolver::iterator I = IdResolver.begin(Name),
IEnd = IdResolver.end();
I != IEnd; ++I)
- if ((*I)->isInIdentifierNamespace(IDNS))
+ if ((*I)->isInIdentifierNamespace(IDNS)) {
+ if ((*I)->getAttr<OverloadableAttr>()) {
+ // If this declaration has the "overloadable" attribute, we
+ // might have a set of overloaded functions.
+
+ // Figure out what scope the identifier is in.
+ while (!(S->getFlags() & Scope::DeclScope) || !S->isDeclScope(*I))
+ S = S->getParent();
+
+ // Find the last declaration in this scope (with the same
+ // name, naturally).
+ IdentifierResolver::iterator LastI = I;
+ for (++LastI; LastI != IEnd; ++LastI) {
+ if (!S->isDeclScope(*LastI))
+ break;
+ }
+
+ return LookupResult::CreateLookupResult(Context, I, LastI);
+ }
+
+ // We have a single lookup result.
return LookupResult::CreateLookupResult(Context, *I);
+ }
} else {
// Perform C++ unqualified name lookup.
std::pair<bool, LookupResult> MaybeResult =
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index e40455b5c6..e1939d329e 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/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;
diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h
index 096bbf56c9..2511c2d6ea 100644
--- a/lib/Sema/SemaOverload.h
+++ b/lib/Sema/SemaOverload.h
@@ -26,21 +26,22 @@ namespace clang {
/// match with Table 9 of (C++ 13.3.3.1.1) and are listed such that
/// better conversion kinds have smaller values.
enum ImplicitConversionKind {
- ICK_Identity = 0, ///< Identity conversion (no conversion)
- ICK_Lvalue_To_Rvalue, ///< Lvalue-to-rvalue conversion (C++ 4.1)
- ICK_Array_To_Pointer, ///< Array-to-pointer conversion (C++ 4.2)
- ICK_Function_To_Pointer, ///< Function-to-pointer (C++ 4.3)
- ICK_Qualification, ///< Qualification conversions (C++ 4.4)
- ICK_Integral_Promotion, ///< Integral promotions (C++ 4.5)
- ICK_Floating_Promotion, ///< Floating point promotions (C++ 4.6)
- ICK_Integral_Conversion, ///< Integral conversions (C++ 4.7)
- ICK_Floating_Conversion, ///< Floating point conversions (C++ 4.8)
- ICK_Floating_Integral, ///< Floating-integral conversions (C++ 4.9)
- ICK_Pointer_Conversion, ///< Pointer conversions (C++ 4.10)
- ICK_Pointer_Member, ///< Pointer-to-member conversions (C++ 4.11)
- ICK_Boolean_Conversion, ///< Boolean conversions (C++ 4.12)
- ICK_Derived_To_Base, ///< Derived-to-base (C++ [over.best.ics][)
- ICK_Num_Conversion_Kinds ///< The number of conversion kinds
+ ICK_Identity = 0, ///< Identity conversion (no conversion)
+ ICK_Lvalue_To_Rvalue, ///< Lvalue-to-rvalue conversion (C++ 4.1)
+ ICK_Array_To_Pointer, ///< Array-to-pointer conversion (C++ 4.2)
+ ICK_Function_To_Pointer, ///< Function-to-pointer (C++ 4.3)
+ ICK_Qualification, ///< Qualification conversions (C++ 4.4)
+ ICK_Integral_Promotion, ///< Integral promotions (C++ 4.5)
+ ICK_Floating_Promotion, ///< Floating point promotions (C++ 4.6)
+ ICK_Integral_Conversion, ///< Integral conversions (C++ 4.7)
+ ICK_Floating_Conversion, ///< Floating point conversions (C++ 4.8)
+ ICK_Floating_Integral, ///< Floating-integral conversions (C++ 4.9)
+ ICK_Pointer_Conversion, ///< Pointer conversions (C++ 4.10)
+ ICK_Pointer_Member, ///< Pointer-to-member conversions (C++ 4.11)
+ ICK_Boolean_Conversion, ///< Boolean conversions (C++ 4.12)
+ ICK_Compatible_Conversion, ///< Conversions between compatible types in C99
+ ICK_Derived_To_Base, ///< Derived-to-base (C++ [over.best.ics])
+ ICK_Num_Conversion_Kinds ///< The number of conversion kinds
};
/// ImplicitConversionCategory - The category of an implicit