Index: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td @@ -1496,7 +1496,8 @@ "%select{none|const|restrict|const and restrict|volatile|const and volatile|" "volatile and restrict|const, volatile, and restrict}5 vs " "%select{none|const|restrict|const and restrict|volatile|const and volatile|" - "volatile and restrict|const, volatile, and restrict}6)}4">; + "volatile and restrict|const, volatile, and restrict}6)" + "|: cannot take the address of a potentially disabled function}4">; def err_lvalue_to_rvalue_ref : Error<"rvalue reference %diff{to type $ cannot " "bind to lvalue of type $|cannot bind to incompatible lvalue}0,1">; @@ -2967,7 +2968,8 @@ "%select{none|const|restrict|const and restrict|volatile|const and volatile" "|volatile and restrict|const, volatile, and restrict}3 but found " "%select{none|const|restrict|const and restrict|volatile|const and volatile" - "|volatile and restrict|const, volatile, and restrict}4)}2">; + "|volatile and restrict|const, volatile, and restrict}4)" + "| made ineligible by enable_if}2">; def note_ovl_candidate_inherited_constructor : Note<"inherited from here">; def note_ovl_candidate_illegal_constructor : Note< @@ -5662,7 +5664,8 @@ "%select{none|const|restrict|const and restrict|volatile|const and volatile|" "volatile and restrict|const, volatile, and restrict}2 vs " "%select{none|const|restrict|const and restrict|volatile|const and volatile|" - "volatile and restrict|const, volatile, and restrict}3)}1">; + "volatile and restrict|const, volatile, and restrict}3)" + "|: mismatch in enable_if attributes}1">; def warn_using_directive_in_header : Warning< "using namespace directive in global context in header">, InGroup, DefaultIgnore; @@ -5899,7 +5902,8 @@ "%select{none|const|restrict|const and restrict|volatile|const and volatile|" "volatile and restrict|const, volatile, and restrict}5 vs " "%select{none|const|restrict|const and restrict|volatile|const and volatile|" - "volatile and restrict|const, volatile, and restrict}6)}4">; + "volatile and restrict|const, volatile, and restrict}6)" + "|: cannot take the address of a potentially disabled function}4">; def err_typecheck_missing_return_type_incompatible : Error< "%diff{return type $ must match previous return type $|" "return type must match previous return type}0,1 when %select{block " Index: cfe/trunk/include/clang/Sema/Sema.h =================================================================== --- cfe/trunk/include/clang/Sema/Sema.h +++ cfe/trunk/include/clang/Sema/Sema.h @@ -2440,11 +2440,13 @@ bool PartialOverloading = false); // Emit as a 'note' the specific overload candidate - void NoteOverloadCandidate(FunctionDecl *Fn, QualType DestType = QualType()); + void NoteOverloadCandidate(FunctionDecl *Fn, QualType DestType = QualType(), + bool TakingAddress = false); - // Emit as a series of 'note's all template and non-templates - // identified by the expression Expr - void NoteAllOverloadCandidates(Expr* E, QualType DestType = QualType()); + // Emit as a series of 'note's all template and non-templates identified by + // the expression Expr + void NoteAllOverloadCandidates(Expr *E, QualType DestType = QualType(), + bool TakingAddress = false); /// Check the enable_if expressions on the given function. Returns the first /// failing attribute, or NULL if they were all successful. Index: cfe/trunk/lib/Sema/SemaCast.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaCast.cpp +++ cfe/trunk/lib/Sema/SemaCast.cpp @@ -2236,6 +2236,16 @@ return; } + // Overloads are allowed with C extensions, so we need to support them. + if (SrcExpr.get()->getType() == Self.Context.OverloadTy) { + DeclAccessPair DAP; + if (FunctionDecl *FD = Self.ResolveAddressOfOverloadedFunction( + SrcExpr.get(), DestType, /*Complain=*/true, DAP)) + SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr.get(), DAP, FD); + else + return; + assert(SrcExpr.isUsable()); + } SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.get()); if (SrcExpr.isInvalid()) return; Index: cfe/trunk/lib/Sema/SemaExpr.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp +++ cfe/trunk/lib/Sema/SemaExpr.cpp @@ -7274,6 +7274,15 @@ // structures. // FIXME: We also fall through for atomics; not sure what should // happen there, though. + } else if (RHS.get()->getType() == Context.OverloadTy) { + // As a set of extensions to C, we support overloading on functions. These + // functions need to be resolved here. + DeclAccessPair DAP; + if (FunctionDecl *FD = ResolveAddressOfOverloadedFunction( + RHS.get(), LHSType, /*Complain=*/false, DAP)) + RHS = FixOverloadedFunctionReference(RHS.get(), DAP, FD); + else + return Incompatible; } // C99 6.5.16.1p1: the left operand is a pointer and the right is @@ -11986,7 +11995,7 @@ if (SecondType == Context.OverloadTy) NoteAllOverloadCandidates(OverloadExpr::find(SrcExpr).Expression, - FirstType); + FirstType, /*TakingAddress=*/true); if (CheckInferredResultType) EmitRelatedResultTypeNote(SrcExpr); Index: cfe/trunk/lib/Sema/SemaInit.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaInit.cpp +++ cfe/trunk/lib/Sema/SemaInit.cpp @@ -6599,6 +6599,8 @@ case SK_CAssignment: { QualType SourceType = CurInit.get()->getType(); + // Save off the initial CurInit in case we need to emit a diagnostic + ExprResult InitialCurInit = CurInit; ExprResult Result = CurInit; Sema::AssignConvertType ConvTy = S.CheckSingleAssignmentConstraints(Step->Type, Result, true, @@ -6621,7 +6623,7 @@ bool Complained; if (S.DiagnoseAssignmentResult(ConvTy, Kind.getLocation(), Step->Type, SourceType, - CurInit.get(), + InitialCurInit.get(), getAssignmentAction(Entity, true), &Complained)) { PrintInitLocationNote(S, Entity); Index: cfe/trunk/lib/Sema/SemaOverload.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp +++ cfe/trunk/lib/Sema/SemaOverload.cpp @@ -2508,7 +2508,8 @@ ft_parameter_arity, ft_parameter_mismatch, ft_return_type, - ft_qualifer_mismatch + ft_qualifer_mismatch, + ft_addr_enable_if }; /// HandleFunctionTypeMismatch - Gives diagnostic information for differeing @@ -8683,20 +8684,37 @@ } // end anonymous namespace +static bool isFunctionAlwaysEnabled(const ASTContext &Ctx, + const FunctionDecl *FD) { + for (auto *EnableIf : FD->specific_attrs()) { + bool AlwaysTrue; + if (!EnableIf->getCond()->EvaluateAsBooleanCondition(AlwaysTrue, Ctx)) + return false; + if (!AlwaysTrue) + return false; + } + return true; +} + // Notes the location of an overload candidate. -void Sema::NoteOverloadCandidate(FunctionDecl *Fn, QualType DestType) { +void Sema::NoteOverloadCandidate(FunctionDecl *Fn, QualType DestType, + bool TakingAddress) { std::string FnDesc; OverloadCandidateKind K = ClassifyOverloadCandidate(*this, Fn, FnDesc); PartialDiagnostic PD = PDiag(diag::note_ovl_candidate) << (unsigned) K << FnDesc; - HandleFunctionTypeMismatch(PD, Fn->getType(), DestType); + if (TakingAddress && !isFunctionAlwaysEnabled(Context, Fn)) + PD << ft_addr_enable_if; + else + HandleFunctionTypeMismatch(PD, Fn->getType(), DestType); Diag(Fn->getLocation(), PD); MaybeEmitInheritedConstructorNote(*this, Fn); } // Notes the location of all overload candidates designated through // OverloadedExpr -void Sema::NoteAllOverloadCandidates(Expr* OverloadedExpr, QualType DestType) { +void Sema::NoteAllOverloadCandidates(Expr *OverloadedExpr, QualType DestType, + bool TakingAddress) { assert(OverloadedExpr->getType() == Context.OverloadTy); OverloadExpr::FindResult Ovl = OverloadExpr::find(OverloadedExpr); @@ -8707,10 +8725,11 @@ I != IEnd; ++I) { if (FunctionTemplateDecl *FunTmpl = dyn_cast((*I)->getUnderlyingDecl()) ) { - NoteOverloadCandidate(FunTmpl->getTemplatedDecl(), DestType); + NoteOverloadCandidate(FunTmpl->getTemplatedDecl(), DestType, + TakingAddress); } else if (FunctionDecl *Fun = dyn_cast((*I)->getUnderlyingDecl()) ) { - NoteOverloadCandidate(Fun, DestType); + NoteOverloadCandidate(Fun, DestType, TakingAddress); } } } @@ -10035,7 +10054,12 @@ Specialization = cast(Specialization->getCanonicalDecl()); assert(S.isSameOrCompatibleFunctionType( Context.getCanonicalType(Specialization->getType()), - Context.getCanonicalType(TargetFunctionType))); + Context.getCanonicalType(TargetFunctionType)) || + (!S.getLangOpts().CPlusPlus && TargetType->isVoidPointerType())); + + if (!isFunctionAlwaysEnabled(S.Context, Specialization)) + return false; + Matches.push_back(std::make_pair(CurAccessFunPair, Specialization)); return true; } @@ -10066,13 +10090,17 @@ return false; } + if (!isFunctionAlwaysEnabled(S.Context, FunDecl)) + return false; + QualType ResultTy; if (Context.hasSameUnqualifiedType(TargetFunctionType, FunDecl->getType()) || S.IsNoReturnConversion(FunDecl->getType(), TargetFunctionType, - ResultTy)) { - Matches.push_back(std::make_pair(CurAccessFunPair, - cast(FunDecl->getCanonicalDecl()))); + ResultTy) || + (!S.getLangOpts().CPlusPlus && TargetType->isVoidPointerType())) { + Matches.push_back(std::make_pair( + CurAccessFunPair, cast(FunDecl->getCanonicalDecl()))); FoundNonTemplateFunction = true; return true; } @@ -10174,7 +10202,8 @@ << OvlExpr->getName() << TargetFunctionType << OvlExpr->getSourceRange(); if (FailedCandidates.empty()) - S.NoteAllOverloadCandidates(OvlExpr, TargetFunctionType); + S.NoteAllOverloadCandidates(OvlExpr, TargetFunctionType, + /*TakingAddress=*/true); else { // We have some deduction failure messages. Use them to diagnose // the function templates, and diagnose the non-template candidates @@ -10184,7 +10213,8 @@ I != IEnd; ++I) if (FunctionDecl *Fun = dyn_cast((*I)->getUnderlyingDecl())) - S.NoteOverloadCandidate(Fun, TargetFunctionType); + S.NoteOverloadCandidate(Fun, TargetFunctionType, + /*TakingAddress=*/true); FailedCandidates.NoteCandidates(S, OvlExpr->getLocStart()); } } @@ -10222,7 +10252,8 @@ S.Diag(OvlExpr->getLocStart(), diag::err_addr_ovl_ambiguous) << OvlExpr->getName() << OvlExpr->getSourceRange(); - S.NoteAllOverloadCandidates(OvlExpr, TargetFunctionType); + S.NoteAllOverloadCandidates(OvlExpr, TargetFunctionType, + /*TakingAddress=*/true); } bool hadMultipleCandidates() const { return (OvlExpr->getNumDecls() > 1); } Index: cfe/trunk/test/CodeGen/enable_if.c =================================================================== --- cfe/trunk/test/CodeGen/enable_if.c +++ cfe/trunk/test/CodeGen/enable_if.c @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-pc-linux-gnu | FileCheck %s + +// Verifying that we do, in fact, select the correct function in the following +// cases. + +void foo(int m) __attribute__((overloadable, enable_if(m > 0, ""))); +void foo(int m) __attribute__((overloadable)); + +// CHECK-LABEL: define void @test1 +void test1() { + // CHECK: store void (i32)* @_Z3fooi + void (*p)(int) = foo; + // CHECK: store void (i32)* @_Z3fooi + void (*p2)(int) = &foo; + // CHECK: store void (i32)* @_Z3fooi + p = foo; + // CHECK: store void (i32)* @_Z3fooi + p = &foo; + + // CHECK: store i8* bitcast (void (i32)* @_Z3fooi to i8*) + void *vp1 = (void*)&foo; + // CHECK: store i8* bitcast (void (i32)* @_Z3fooi to i8*) + void *vp2 = (void*)foo; + // CHECK: store i8* bitcast (void (i32)* @_Z3fooi to i8*) + vp1 = (void*)&foo; + // CHECK: store i8* bitcast (void (i32)* @_Z3fooi to i8*) + vp1 = (void*)foo; +} + +void bar(int m) __attribute__((overloadable, enable_if(m > 0, ""))); +void bar(int m) __attribute__((overloadable, enable_if(1, ""))); +// CHECK-LABEL: define void @test2 +void test2() { + // CHECK: store void (i32)* @_Z3barUa9enable_ifIXLi1EEEi + void (*p)(int) = bar; + // CHECK: store void (i32)* @_Z3barUa9enable_ifIXLi1EEEi + void (*p2)(int) = &bar; + // CHECK: store void (i32)* @_Z3barUa9enable_ifIXLi1EEEi + p = bar; + // CHECK: store void (i32)* @_Z3barUa9enable_ifIXLi1EEEi + p = &bar; + + // CHECK: store i8* bitcast (void (i32)* @_Z3barUa9enable_ifIXLi1EEEi to i8*) + void *vp1 = (void*)&bar; + // CHECK: store i8* bitcast (void (i32)* @_Z3barUa9enable_ifIXLi1EEEi to i8*) + void *vp2 = (void*)bar; + // CHECK: store i8* bitcast (void (i32)* @_Z3barUa9enable_ifIXLi1EEEi to i8*) + vp1 = (void*)&bar; + // CHECK: store i8* bitcast (void (i32)* @_Z3barUa9enable_ifIXLi1EEEi to i8*) + vp1 = (void*)bar; +} Index: cfe/trunk/test/Sema/enable_if.c =================================================================== --- cfe/trunk/test/Sema/enable_if.c +++ cfe/trunk/test/Sema/enable_if.c @@ -91,6 +91,12 @@ #endif } +void test5() { + int (*p1)(int) = &isdigit2; + int (*p2)(int) = isdigit2; + void *p3 = (void *)&isdigit2; + void *p4 = (void *)isdigit2; +} #ifndef CODEGEN __attribute__((enable_if(n == 0, "chosen when 'n' is zero"))) void f1(int n); // expected-error{{use of undeclared identifier 'n'}} @@ -109,4 +115,23 @@ const int cst = 7; void return_cst(void) __attribute__((overloadable)) __attribute__((enable_if(cst == 7, "chosen when 'cst' is 7"))); void test_return_cst() { return_cst(); } + +void f2(void) __attribute__((overloadable)) __attribute__((enable_if(1, "always chosen"))); +void f2(void) __attribute__((overloadable)) __attribute__((enable_if(0, "never chosen"))); +void f2(void) __attribute__((overloadable)); +void test6() { + void (*p1)(void) = &f2; // expected-error{{initializing 'void (*)(void)' with an expression of incompatible type ''}} expected-note@119{{candidate function}} expected-note@120{{candidate function made ineligible by enable_if}} expected-note@121{{candidate function}} + void (*p2)(void) = f2; // expected-error{{initializing 'void (*)(void)' with an expression of incompatible type ''}} expected-note@119{{candidate function}} expected-note@120{{candidate function made ineligible by enable_if}} expected-note@121{{candidate function}} + void *p3 = (void*)&f2; // expected-error{{address of overloaded function 'f2' is ambiguous}} expected-note@119{{candidate function}} expected-note@120{{candidate function made ineligible by enable_if}} expected-note@121{{candidate function}} + void *p4 = (void*)f2; // expected-error{{address of overloaded function 'f2' is ambiguous}} expected-note@119{{candidate function}} expected-note@120{{candidate function made ineligible by enable_if}} expected-note@121{{candidate function}} +} + +void f3(int m) __attribute__((overloadable)) __attribute__((enable_if(m >= 0, "positive"))); +void f3(int m) __attribute__((overloadable)) __attribute__((enable_if(m < 0, "negative"))); +void test7() { + void (*p1)(int) = &f3; // expected-error{{initializing 'void (*)(int)' with an expression of incompatible type ''}} expected-note@129{{candidate function made ineligible by enable_if}} expected-note@130{{candidate function made ineligible by enable_if}} + void (*p2)(int) = f3; // expected-error{{initializing 'void (*)(int)' with an expression of incompatible type ''}} expected-note@129{{candidate function made ineligible by enable_if}} expected-note@130{{candidate function made ineligible by enable_if}} + void *p3 = (void*)&f3; // expected-error{{address of overloaded function 'f3' does not match required type 'void'}} expected-note@129{{candidate function made ineligible by enable_if}} expected-note@130{{candidate function made ineligible by enable_if}} + void *p4 = (void*)f3; // expected-error{{address of overloaded function 'f3' does not match required type 'void'}} expected-note@129{{candidate function made ineligible by enable_if}} expected-note@130{{candidate function made ineligible by enable_if}} +} #endif Index: cfe/trunk/test/SemaCXX/enable_if.cpp =================================================================== --- cfe/trunk/test/SemaCXX/enable_if.cpp +++ cfe/trunk/test/SemaCXX/enable_if.cpp @@ -163,3 +163,74 @@ fn3(sizeof(T) == 1); } } + +namespace FnPtrs { + int ovlFoo(int m) __attribute__((enable_if(m > 0, ""))); + int ovlFoo(int m); + + void test() { + // Assignment gives us a different code path than declarations, and `&foo` + // gives us a different code path than `foo` + int (*p)(int) = ovlFoo; + int (*p2)(int) = &ovlFoo; + int (*a)(int); + a = ovlFoo; + a = &ovlFoo; + } + + int ovlBar(int) __attribute__((enable_if(true, ""))); + int ovlBar(int m) __attribute__((enable_if(false, ""))); + void test2() { + int (*p)(int) = ovlBar; + int (*p2)(int) = &ovlBar; + int (*a)(int); + a = ovlBar; + a = &ovlBar; + } + + int ovlConflict(int m) __attribute__((enable_if(true, ""))); + int ovlConflict(int m); + void test3() { + int (*p)(int) = ovlConflict; // expected-error{{address of overloaded function 'ovlConflict' is ambiguous}} expected-note@191{{candidate function}} expected-note@192{{candidate function}} + int (*p2)(int) = &ovlConflict; // expected-error{{address of overloaded function 'ovlConflict' is ambiguous}} expected-note@191{{candidate function}} expected-note@192{{candidate function}} + int (*a)(int); + a = ovlConflict; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@191{{candidate function}} expected-note@192{{candidate function}} + a = &ovlConflict; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@191{{candidate function}} expected-note@192{{candidate function}} + } + + template + T templated(T m) __attribute__((enable_if(true, ""))) { return T(); } + template + T templated(T m) __attribute__((enable_if(false, ""))) { return T(); } + void test4() { + int (*p)(int) = templated; + int (*p2)(int) = &templated; + int (*a)(int); + a = templated; + a = &templated; + } + + template + T templatedBar(T m) __attribute__((enable_if(m > 0, ""))) { return T(); } + void test5() { + int (*p)(int) = templatedBar; // expected-error{{address of overloaded function 'templatedBar' does not match required type 'int (int)'}} expected-note@214{{candidate function made ineligible by enable_if}} + int (*p2)(int) = &templatedBar; // expected-error{{address of overloaded function 'templatedBar' does not match required type 'int (int)'}} expected-note@214{{candidate function made ineligible by enable_if}} + int (*a)(int); + a = templatedBar; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@214{{candidate function made ineligible by enable_if}} + a = &templatedBar; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@214{{candidate function made ineligible by enable_if}} + } + + template + T templatedConflict(T m) __attribute__((enable_if(false, ""))) { return T(); } + template + T templatedConflict(T m) __attribute__((enable_if(true, ""))) { return T(); } + template + T templatedConflict(T m) { return T(); } + void test6() { + int (*p)(int) = templatedConflict; // expected-error{{address of overloaded function 'templatedConflict' is ambiguous}} expected-note@224{{candidate function made ineligible by enable_if}} expected-note@226{{candidate function}} expected-note@228{{candidate function}} + int (*p0)(int) = &templatedConflict; // expected-error{{address of overloaded function 'templatedConflict' is ambiguous}} expected-note@224{{candidate function made ineligible by enable_if}} expected-note@226{{candidate function}} expected-note@228{{candidate function}} + int (*a)(int); + a = templatedConflict; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@226{{candidate function}} expected-note@228{{candidate function}} + a = &templatedConflict; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@226{{candidate function}} expected-note@228{{candidate function}} + } +}