aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-02-18 06:34:51 +0000
committerDouglas Gregor <dgregor@apple.com>2009-02-18 06:34:51 +0000
commitc6666f8e9bbb7f31bf2e52f97137e738c4ca01d0 (patch)
treedf0b4fbf0b7db30dc79a52ce27432d6e34af80d4
parentf4b136fb40aeedeaaa6ce7cdff22f375eb76c47b (diff)
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
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.def6
-rw-r--r--lib/Sema/SemaDecl.cpp22
-rw-r--r--lib/Sema/SemaExpr.cpp12
-rw-r--r--test/Sema/overloadable.c10
-rw-r--r--test/SemaCXX/attr-unavailable.cpp11
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}}
+}