From: Douglas Gregor Date: Wed, 18 Feb 2009 06:34:51 +0000 (+0000) Subject: Don't allow calls to functions marked "unavailable". There's more work X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c6666f8e9bbb7f31bf2e52f97137e738c4ca01d0;p=clang Don't allow calls to functions marked "unavailable". There's more work to do in this area, since there are other places that reference FunctionDecls. Don't allow "overloadable" functions (in C) to be declared without a prototype. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64897 91177308-0d34-0410-b5e6-96231b3b80d8 --- 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 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()) { + Diag(Fn->getSourceRange().getBegin(), diag::err_call_deleted_function) + << FDecl->getAttr() << FDecl->getDeclName() + << Fn->getSourceRange(); + Diag(FDecl->getLocation(), diag::note_deleted_function_here) + << FDecl->getAttr(); + 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}} +}