diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.def | 6 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 22 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 12 | ||||
-rw-r--r-- | test/Sema/overloadable.c | 10 | ||||
-rw-r--r-- | test/SemaCXX/attr-unavailable.cpp | 11 |
5 files changed, 56 insertions, 5 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def index 19d9b65ffa..16692412dc 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.def +++ b/include/clang/Basic/DiagnosticSemaKinds.def @@ -418,6 +418,8 @@ DIAG(err_attribute_overloadable_missing, ERROR, "%select{overloaded function|redeclaration of}0 %1 must have the 'overloadable' attribute") DIAG(note_attribute_overloadable_prev_overload, NOTE, "previous overload of function is here") +DIAG(err_attribute_overloadable_no_prototype, ERROR, + "'overloadable' function %0 must have a prototype") // Function Parameter Semantic Analysis. DIAG(err_param_with_void_type, ERROR, @@ -1051,6 +1053,10 @@ DIAG(err_typecheck_call_too_few_args, ERROR, "too few arguments to %select{function|block|method}0 call") DIAG(err_typecheck_call_too_many_args, ERROR, "too many arguments to %select{function|block|method}0 call") +DIAG(err_call_deleted_function, ERROR, + "call to function %1 that has been intentionally %select{deleted|made unavailable}0 ") +DIAG(note_deleted_function_here, NOTE, + "%select{deleted|unavailable}0 function is declared here") DIAG(warn_cannot_pass_non_pod_arg_to_vararg, WARNING, "cannot pass object of non-POD type %0 through variadic " "%select{function|block|method}1; call will abort at runtime") diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 55e2a92476..0543b0adc6 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1763,11 +1763,27 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, OverloadedFunctionDecl::function_iterator MatchedDecl; if (!getLangOptions().CPlusPlus && - AllowOverloadingOfFunction(PrevDecl, Context)) + AllowOverloadingOfFunction(PrevDecl, Context)) { OverloadableAttrRequired = true; - if (!AllowOverloadingOfFunction(PrevDecl, Context) || - !IsOverload(NewFD, PrevDecl, MatchedDecl)) { + // Functions marked "overloadable" must have a prototype (that + // we can't get through declaration merging). + if (!R->getAsFunctionTypeProto()) { + Diag(NewFD->getLocation(), diag::err_attribute_overloadable_no_prototype) + << NewFD; + InvalidDecl = true; + Redeclaration = true; + + // Turn this into a variadic function with no parameters. + R = Context.getFunctionType(R->getAsFunctionType()->getResultType(), + 0, 0, true, 0); + NewFD->setType(R); + } + } + + if (PrevDecl && + (!AllowOverloadingOfFunction(PrevDecl, Context) || + !IsOverload(NewFD, PrevDecl, MatchedDecl))) { Redeclaration = true; Decl *OldDecl = PrevDecl; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index c0b61bf8d7..48f338e475 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -2032,13 +2032,21 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, // Make the call expr early, before semantic checks. This guarantees cleanup // of arguments and function on error. - // FIXME: Except that llvm::OwningPtr uses delete, when it really must be - // Destroy(), or nothing gets cleaned up. ExprOwningPtr<CallExpr> TheCall(this, new (Context) CallExpr(Context, Fn, Args, NumArgs, Context.BoolTy, RParenLoc)); + // Check for a call to a (FIXME: deleted) or unavailable function. + if (FDecl && FDecl->getAttr<UnavailableAttr>()) { + Diag(Fn->getSourceRange().getBegin(), diag::err_call_deleted_function) + << FDecl->getAttr<UnavailableAttr>() << FDecl->getDeclName() + << Fn->getSourceRange(); + Diag(FDecl->getLocation(), diag::note_deleted_function_here) + << FDecl->getAttr<UnavailableAttr>(); + return ExprError(); + } + const FunctionType *FuncT; if (!Fn->getType()->isBlockPointerType()) { // C99 6.5.2.2p1 - "The expression that denotes the called function shall diff --git a/test/Sema/overloadable.c b/test/Sema/overloadable.c index afac741070..136f8e93d7 100644 --- a/test/Sema/overloadable.c +++ b/test/Sema/overloadable.c @@ -37,4 +37,14 @@ void test_struct(struct X x, struct Y y) { double *f(int) __attribute__((overloadable)); // expected-error{{conflicting types for 'f'}} +double promote(float) __attribute__((__overloadable__)); +double promote(double) __attribute__((__overloadable__)); +long double promote(long double) __attribute__((__overloadable__)); + +void promote() __attribute__((__overloadable__)); // expected-error{{'overloadable' function 'promote' must have a prototype}} + +void test_promote(short* sp) { + promote(1.0); +} + diff --git a/test/SemaCXX/attr-unavailable.cpp b/test/SemaCXX/attr-unavailable.cpp new file mode 100644 index 0000000000..140008a4cb --- /dev/null +++ b/test/SemaCXX/attr-unavailable.cpp @@ -0,0 +1,11 @@ +// RUN: clang -fsyntax-only -verify %s + +int &foo(int); +double &foo(double); +void foo(...) __attribute__((__unavailable__)); // expected-note{{unavailable function is declared here}} + +void test_foo(short* sp) { + int &ir = foo(1); + double &dr = foo(1.0); + foo(sp); // expected-error{{call to function 'foo' that has been intentionally made unavailable}} +} |