diff options
-rw-r--r-- | include/clang/AST/Attr.h | 9 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.def | 6 | ||||
-rw-r--r-- | include/clang/Parse/AttributeList.h | 1 | ||||
-rw-r--r-- | lib/Parse/AttributeList.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 44 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 16 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 23 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 60 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.h | 31 |
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 |