diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -7158,17 +7158,25 @@ } std::bitset Attrs; - attr::Kind NewAttrKind = A->getKind(); QualType Desugared = Type; - const AttributedType *AT = dyn_cast(Type); - while (AT) { + for (;;) { + if (const TypedefType *TT = dyn_cast(Desugared)) { + Desugared = TT->desugar(); + continue; + } else if (const ElaboratedType *ET = dyn_cast(Desugared)) { + Desugared = ET->desugar(); + continue; + } + const AttributedType *AT = dyn_cast(Desugared); + if (!AT) + break; Attrs[AT->getAttrKind()] = true; Desugared = AT->getModifiedType(); - AT = dyn_cast(Desugared); } // You cannot specify duplicate type attributes, so if the attribute has // already been applied, flag it. + attr::Kind NewAttrKind = A->getKind(); if (Attrs[NewAttrKind]) { S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact) << PAttr; return true; @@ -7189,14 +7197,11 @@ return true; } - // Pointer type qualifiers can only operate on pointer types, but not - // pointer-to-member types. - // - // FIXME: Should we really be disallowing this attribute if there is any - // type sugar between it and the pointer (other than attributes)? Eg, this - // disallows the attribute on a parenthesized pointer. - // And if so, should we really allow *any* type attribute? + // Check the raw (i.e., desugared) Canonical type to see if it + // is a pointer type. if (!isa(Desugared)) { + // Pointer type qualifiers can only operate on pointer types, but not + // pointer-to-member types. if (Type->isMemberPointerType()) S.Diag(PAttr.getLoc(), diag::err_attribute_no_member_pointers) << PAttr; else diff --git a/clang/test/CodeGen/address-space-ptr32.c b/clang/test/CodeGen/address-space-ptr32.c --- a/clang/test/CodeGen/address-space-ptr32.c +++ b/clang/test/CodeGen/address-space-ptr32.c @@ -1,10 +1,40 @@ // RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-windows-msvc -fms-extensions -emit-llvm < %s | FileCheck %s +_Static_assert(sizeof(void *) == 8, "sizeof(void *) has unexpected value. Expected 8."); + int foo(void) { + // CHECK: define dso_local i32 @foo + // CHECK: %a = alloca i32 (i32) addrspace(270)*, align 4 + // CHECK: ret i32 4 int (*__ptr32 a)(int); return sizeof(a); } -// CHECK: define dso_local i32 @foo -// CHECK: %a = alloca i32 (i32) addrspace(270)*, align 4 -// CHECK: ret i32 4 +int bar(void) { + // CHECK: define dso_local i32 @bar + // CHECK: %p = alloca i32 addrspace(270)*, align 4 + // CHECK: ret i32 4 + int *__ptr32 p; + return sizeof(p); +} + + +int baz(void) { + // CHECK: define dso_local i32 @baz + // CHECK: %p = alloca i32 addrspace(270)*, align 4 + // CHECK: ret i32 4 + typedef int *__ptr32 IP32_PTR; + + IP32_PTR p; + return sizeof(p); +} + +int fugu(void) { + // CHECK: define dso_local i32 @fugu + // CHECK: %p = alloca i32 addrspace(270)*, align 4 + // CHECK: ret i32 4 + typedef int *int_star; + + int_star __ptr32 p; + return sizeof(p); +} diff --git a/clang/test/Sema/MicrosoftExtensions.c b/clang/test/Sema/MicrosoftExtensions.c --- a/clang/test/Sema/MicrosoftExtensions.c +++ b/clang/test/Sema/MicrosoftExtensions.c @@ -173,8 +173,28 @@ int *(__ptr32 __sptr wrong9); // expected-error {{'__sptr' attribute only applies to pointer arguments}} // expected-error {{'__ptr32' attribute only applies to pointer arguments}} +int *(__ptr32 wrong10); // expected-error {{'__ptr32' attribute only applies to pointer arguments}} + +int *(__ptr64 wrong11); // expected-error {{'__ptr64' attribute only applies to pointer arguments}} + +int *(__ptr32 __ptr64 wrong12); // expected-error {{'__ptr32' attribute only applies to pointer arguments}} // expected-error {{'__ptr64' attribute only applies to pointer arguments}} + typedef int *T; -T __ptr32 wrong10; // expected-error {{'__ptr32' attribute only applies to pointer arguments}} +T __ptr32 ok1; +T __ptr64 ok2; +T __ptr32 __ptr64 wrong13; // expected-error {{'__ptr32' and '__ptr64' attributes are not compatible}} + +typedef int *__ptr32 T1; +T1 ok3; +T1 __ptr32 wrong14; // expected-warning {{attribute '__ptr32' is already applied}} +T1 __ptr64 wrong15; // expected-error {{'__ptr32' and '__ptr64' attributes are not compatible}} + +typedef int *__ptr64 T2; +T2 ok4; +T2 __ptr64 wrong16; // expected-warning {{attribute '__ptr64' is already applied}} +T2 __ptr32 wrong17; // expected-error {{'__ptr32' and '__ptr64' attributes are not compatible}} + +typedef int *__ptr32 __ptr64 wrong18; // expected-error {{'__ptr32' and '__ptr64' attributes are not compatible}} typedef char *my_va_list; void __va_start(my_va_list *ap, ...); // expected-note {{passing argument to parameter 'ap' here}} diff --git a/clang/test/Sema/MicrosoftExtensions.cpp b/clang/test/Sema/MicrosoftExtensions.cpp --- a/clang/test/Sema/MicrosoftExtensions.cpp +++ b/clang/test/Sema/MicrosoftExtensions.cpp @@ -1,6 +1,5 @@ // RUN: %clang_cc1 -triple i686-windows %s -fsyntax-only -Wmicrosoft -verify -fms-extensions // RUN: %clang_cc1 -triple x86_64-windows %s -fsyntax-only -Wmicrosoft -verify -fms-extensions -// expected-no-diagnostics // Check that __ptr32/__ptr64 can be compared. int test_ptr_comparison(int *__ptr32 __uptr p32u, int *__ptr32 __sptr p32s, @@ -9,3 +8,23 @@ (p32u == p64) + (p32s == p64); } + +template +void bad(T __ptr32 a) { // expected-error {{'__ptr32' attribute only applies to pointer arguments}}` + (*a) += 1; +} + +template +void f(T a) { + (*a) += sizeof(a); + static_assert(sizeof(a) == size_expected, "instantiated template argument has unexpected size"); +} +void g(int *p) { + // instantiate for default sized pointer + f(p); +} + +void h(int *__ptr32 p) { + // instantiate for 32-bit pointer + f<4>(p); +}