From: Fariborz Jahanian Date: Wed, 5 Oct 2011 00:05:34 +0000 (+0000) Subject: c: assignment/init of a function pointer whose function(s) X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=53c8167d7a007daae87f342c0fedd03f1dcf1b62;p=clang c: assignment/init of a function pointer whose function(s) return to one which does not return (has noreturn attribute) should warn as it is an unsafe assignment. // rdar://10095762 c++ already handles this. This is the c version. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@141141 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 5e0c78409d..6f68c2dc2f 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -5543,13 +5543,13 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, if (lbaseInfo.getProducesResult() != rbaseInfo.getProducesResult()) return QualType(); - // It's noreturn if either type is. - // FIXME: some uses, e.g. conditional exprs, really want this to be 'both'. - bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn(); - if (NoReturn != lbaseInfo.getNoReturn()) + // functypes which return are preferred over those that do not. + if (lbaseInfo.getNoReturn() && !rbaseInfo.getNoReturn()) allLTypes = false; - if (NoReturn != rbaseInfo.getNoReturn()) + else if (!lbaseInfo.getNoReturn() && rbaseInfo.getNoReturn()) allRTypes = false; + // FIXME: some uses, e.g. conditional exprs, really want this to be 'both'. + bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn(); FunctionType::ExtInfo einfo = lbaseInfo.withNoReturn(NoReturn); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 707d577f61..242fcfacde 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -5277,6 +5277,9 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) { // General pointer incompatibility takes priority over qualifiers. return Sema::IncompatiblePointer; } + if (!S.getLangOptions().CPlusPlus && + S.IsNoReturnConversion(ltrans, rtrans, ltrans)) + return Sema::IncompatiblePointer; return ConvTy; } diff --git a/test/Sema/initialize-noreturn.c b/test/Sema/initialize-noreturn.c new file mode 100644 index 0000000000..5557862871 --- /dev/null +++ b/test/Sema/initialize-noreturn.c @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 %s -fsyntax-only -verify +// rdar://10095762 + +typedef void (*Fn_noret)(void) __attribute__((noreturn)); +typedef void (*Fn_ret)(void); + +void foo(void); +void foo_noret(void) __attribute__((noreturn)); + +void test() { + Fn_noret fn2 = &foo; // expected-warning {{incompatible pointer types initializing 'Fn_noret'}} + Fn_noret fn3 = &foo_noret; + Fn_ret fn4 = &foo_noret; + Fn_ret fn5 = &foo; +} +