"%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,
"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")
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;
// 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
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);
+}
+
--- /dev/null
+// 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}}
+}