From: Nikola Smiljanic Date: Thu, 16 Jul 2015 01:06:17 +0000 (+0000) Subject: PR10405 - Desugar FunctionType and TemplateSpecializationType if any type that appear... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bba7fea0d03ff10b44bac565c22ee6db5b400192;p=clang PR10405 - Desugar FunctionType and TemplateSpecializationType if any type that appears inside needs to be desugared. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@242371 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index dddaa5af6f..5b66f58344 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -66,11 +66,63 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) { continue; } - // Don't desugar template specializations, unless it's an alias template. - if (const TemplateSpecializationType *TST - = dyn_cast(Ty)) - if (!TST->isTypeAlias()) + // Desugar FunctionType if return type or any parameter type should be + // desugared. Preserve nullability attribute on desugared types. + if (const FunctionType *FT = dyn_cast(Ty)) { + bool DesugarReturn = false; + QualType SugarRT = FT->getReturnType(); + QualType RT = Desugar(Context, SugarRT, DesugarReturn); + if (auto nullability = AttributedType::stripOuterNullability(SugarRT)) { + RT = Context.getAttributedType( + AttributedType::getNullabilityAttrKind(*nullability), RT, RT); + } + + bool DesugarArgument = false; + SmallVector Args; + const FunctionProtoType *FPT = dyn_cast(FT); + if (FPT) { + for (QualType SugarPT : FPT->param_types()) { + QualType PT = Desugar(Context, SugarPT, DesugarArgument); + if (auto nullability = + AttributedType::stripOuterNullability(SugarPT)) { + PT = Context.getAttributedType( + AttributedType::getNullabilityAttrKind(*nullability), PT, PT); + } + Args.push_back(PT); + } + } + + if (DesugarReturn || DesugarArgument) { + ShouldAKA = true; + QT = FPT ? Context.getFunctionType(RT, Args, FPT->getExtProtoInfo()) + : Context.getFunctionNoProtoType(RT, FT->getExtInfo()); break; + } + } + + // Desugar template specializations if any template argument should be + // desugared. + if (const TemplateSpecializationType *TST = + dyn_cast(Ty)) { + if (!TST->isTypeAlias()) { + bool DesugarArgument = false; + SmallVector Args; + for (unsigned I = 0, N = TST->getNumArgs(); I != N; ++I) { + const TemplateArgument &Arg = TST->getArg(I); + if (Arg.getKind() == TemplateArgument::Type) + Args.push_back(Desugar(Context, Arg.getAsType(), DesugarArgument)); + else + Args.push_back(Arg); + } + + if (DesugarArgument) { + ShouldAKA = true; + QT = Context.getTemplateSpecializationType( + TST->getTemplateName(), Args.data(), Args.size(), QT); + } + break; + } + } // Don't desugar magic Objective-C types. if (QualType(Ty,0) == Context.getObjCIdType() || diff --git a/test/ASTMerge/function.c b/test/ASTMerge/function.c index 89e1c699c3..650f719d1f 100644 --- a/test/ASTMerge/function.c +++ b/test/ASTMerge/function.c @@ -3,7 +3,7 @@ // RUN: not %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s // RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only -verify %s -// CHECK: function2.c:3:6: error: external function 'f1' declared with incompatible types in different translation units ('void (Int, double)' vs. 'void (int, float)') +// CHECK: function2.c:3:6: error: external function 'f1' declared with incompatible types in different translation units ('void (Int, double)' (aka 'void (int, double)') vs. 'void (int, float)') // CHECK: function1.c:2:6: note: declared here with type 'void (int, float)' // CHECK: function2.c:5:6: error: external function 'f3' declared with incompatible types in different translation units ('void (int)' vs. 'void (void)') // CHECK: function1.c:4:6: note: declared here with type 'void (void)' diff --git a/test/Misc/diag-aka-types.cpp b/test/Misc/diag-aka-types.cpp index 3a00b7122e..c386504a6c 100644 --- a/test/Misc/diag-aka-types.cpp +++ b/test/Misc/diag-aka-types.cpp @@ -45,3 +45,20 @@ void helper(callback cb) {} // expected-note{{candidate function not viable: no void test() { helper(&ns::str::method); // expected-error{{no matching function for call to 'helper'}} } + +template +class A {}; + +int a1 = A(); // expected-error{{no viable conversion from 'A' (aka 'A') to 'int'}} +int a2 = A>(); // expected-error{{no viable conversion from 'A >' (aka 'A >') to 'int'}} +int a3 = A<__typeof(1 + 2)>(); // expected-error{{no viable conversion from 'A' (aka 'A') to 'int'}} +int a4 = A>(); // expected-error{{no viable conversion from 'A >' (aka 'A >') to 'int'}} + +using B = A; +int a5 = B(); // expected-error{{no viable conversion from 'B' (aka 'A') to 'int'}} + +decltype(void()) (&f1)() = 0; // expected-error{{non-const lvalue reference to type 'decltype(void()) ()' (aka 'void ()') cannot bind to a temporary of type 'int'}} +decltype(void()) (&f2)(int) = 0; // expected-error{{non-const lvalue reference to type 'decltype(void()) (int)' (aka 'void (int)') cannot bind to a temporary of type 'int'}} +void (&f3)(decltype(1 + 2)) = 0; // expected-error{{non-const lvalue reference to type 'void (decltype(1 + 2))' (aka 'void (int)') cannot bind to a temporary of type 'int'}} +decltype(1+2) (&f4)(double, decltype(1 + 2)) = 0; // expected-error{{non-const lvalue reference to type 'decltype(1 + 2) (double, decltype(1 + 2))' (aka 'int (double, int)') cannot bind to a temporary of type 'int'}} +auto (&f5)() -> decltype(1+2) = 0; // expected-error{{non-const lvalue reference to type 'auto () -> decltype(1 + 2)' (aka 'auto () -> int') cannot bind to a temporary of type 'int'}} diff --git a/test/Sema/nullability.c b/test/Sema/nullability.c index 59644c4193..8a621d3b5f 100644 --- a/test/Sema/nullability.c +++ b/test/Sema/nullability.c @@ -47,6 +47,7 @@ typedef _Nonnull int *(^ block_type_3)(int, int); typedef _Nonnull int *(* function_pointer_type_3)(int, int); typedef _Nonnull int_ptr (^ block_type_4)(int, int); typedef _Nonnull int_ptr (* function_pointer_type_4)(int, int); +typedef void (* function_pointer_type_5)(int_ptr _Nonnull); void acceptFunctionPtr(_Nonnull int *(*)(void)); void acceptBlockPtr(_Nonnull int *(^)(void)); @@ -55,7 +56,8 @@ void testBlockFunctionPtrNullability() { float *fp; fp = (function_pointer_type_3)0; // expected-warning{{from 'function_pointer_type_3' (aka 'int * _Nonnull (*)(int, int)')}} fp = (block_type_3)0; // expected-error{{from incompatible type 'block_type_3' (aka 'int * _Nonnull (^)(int, int)')}} - fp = (function_pointer_type_4)0; // expected-warning{{from 'function_pointer_type_4' (aka 'int_ptr _Nonnull (*)(int, int)')}} + fp = (function_pointer_type_4)0; // expected-warning{{from 'function_pointer_type_4' (aka 'int * _Nonnull (*)(int, int)')}} + fp = (function_pointer_type_5)0; // expected-warning{{from 'function_pointer_type_5' (aka 'void (*)(int * _Nonnull)')}} fp = (block_type_4)0; // expected-error{{from incompatible type 'block_type_4' (aka 'int_ptr _Nonnull (^)(int, int)')}} acceptFunctionPtr(0); // no-warning diff --git a/test/Sema/pointer-addition.c b/test/Sema/pointer-addition.c index 667fe9a68c..c71e96114b 100644 --- a/test/Sema/pointer-addition.c +++ b/test/Sema/pointer-addition.c @@ -14,10 +14,10 @@ void a(S* b, void* c) { b = 1+b; // expected-error {{arithmetic on a pointer to an incomplete type}} /* The next couple tests are only pedantic warnings in gcc */ void (*d)(S*,void*) = a; - d += 1; // expected-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' is a GNU extension}} - d++; // expected-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' is a GNU extension}} - d--; // expected-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' is a GNU extension}} - d -= 1; // expected-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' is a GNU extension}} - (void)(1 + d); // expected-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' is a GNU extension}} + d += 1; // expected-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' (aka 'void (struct S *, void *)') is a GNU extension}} + d++; // expected-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' (aka 'void (struct S *, void *)') is a GNU extension}} + d--; // expected-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' (aka 'void (struct S *, void *)') is a GNU extension}} + d -= 1; // expected-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' (aka 'void (struct S *, void *)') is a GNU extension}} + (void)(1 + d); // expected-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' (aka 'void (struct S *, void *)') is a GNU extension}} e++; // expected-error {{arithmetic on a pointer to an incomplete type}} } diff --git a/test/SemaTemplate/class-template-id.cpp b/test/SemaTemplate/class-template-id.cpp index 5bbc70c955..50cb3ef59e 100644 --- a/test/SemaTemplate/class-template-id.cpp +++ b/test/SemaTemplate/class-template-id.cpp @@ -9,9 +9,9 @@ A *foo(A *ptr, A const *ptr2, A *ptr3) { if (ptr) return ptr; // okay else if (ptr2) - return ptr2; // expected-error{{cannot initialize return object of type 'A *' with an lvalue of type 'const A *'}} + return ptr2; // expected-error{{cannot initialize return object of type 'A *' (aka 'A *') with an lvalue of type 'const A *'}} else { - return ptr3; // expected-error{{cannot initialize return object of type 'A *' with an lvalue of type 'A *'}} + return ptr3; // expected-error{{cannot initialize return object of type 'A *' (aka 'A *') with an lvalue of type 'A *'}} } }