31 changes: 19 additions & 12 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1743,12 +1743,13 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
}

QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
unsigned CVRA, const DeclSpec *DS) {
unsigned CVRAU, const DeclSpec *DS) {
if (T.isNull())
return QualType();

// Convert from DeclSpec::TQ to Qualifiers::TQ by just dropping TQ_atomic.
unsigned CVR = CVRA & ~DeclSpec::TQ_atomic;
// Convert from DeclSpec::TQ to Qualifiers::TQ by just dropping TQ_atomic and
// TQ_unaligned;
unsigned CVR = CVRAU & ~DeclSpec::TQ_atomic & ~DeclSpec::TQ_unaligned;

// C11 6.7.3/5:
// If the same qualifier appears more than once in the same
Expand All @@ -1758,7 +1759,7 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
// It's not specified what happens when the _Atomic qualifier is applied to
// a type specified with the _Atomic specifier, but we assume that this
// should be treated as if the _Atomic qualifier appeared multiple times.
if (CVRA & DeclSpec::TQ_atomic && !T->isAtomicType()) {
if (CVRAU & DeclSpec::TQ_atomic && !T->isAtomicType()) {
// C11 6.7.3/5:
// If other qualifiers appear along with the _Atomic qualifier in a
// specifier-qualifier-list, the resulting type is the so-qualified
Expand All @@ -1775,7 +1776,9 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
return BuildQualifiedType(T, Loc, Split.Quals);
}

return BuildQualifiedType(T, Loc, Qualifiers::fromCVRMask(CVR), DS);
Qualifiers Q = Qualifiers::fromCVRMask(CVR);
Q.setUnaligned(CVRAU & DeclSpec::TQ_unaligned);
return BuildQualifiedType(T, Loc, Q, DS);
}

/// \brief Build a paren type including \p T.
Expand Down Expand Up @@ -2617,28 +2620,30 @@ void Sema::diagnoseIgnoredQualifiers(unsigned DiagID, unsigned Quals,
SourceLocation ConstQualLoc,
SourceLocation VolatileQualLoc,
SourceLocation RestrictQualLoc,
SourceLocation AtomicQualLoc) {
SourceLocation AtomicQualLoc,
SourceLocation UnalignedQualLoc) {
if (!Quals)
return;

struct Qual {
const char *Name;
unsigned Mask;
SourceLocation Loc;
} const QualKinds[4] = {
} const QualKinds[5] = {
{ "const", DeclSpec::TQ_const, ConstQualLoc },
{ "volatile", DeclSpec::TQ_volatile, VolatileQualLoc },
{ "restrict", DeclSpec::TQ_restrict, RestrictQualLoc },
{ "_Atomic", DeclSpec::TQ_atomic, AtomicQualLoc }
{ "_Atomic", DeclSpec::TQ_atomic, AtomicQualLoc },
{ "__unaligned", DeclSpec::TQ_unaligned, UnalignedQualLoc }
};

SmallString<32> QualStr;
unsigned NumQuals = 0;
SourceLocation Loc;
FixItHint FixIts[4];
FixItHint FixIts[5];

// Build a string naming the redundant qualifiers.
for (unsigned I = 0; I != 4; ++I) {
for (unsigned I = 0; I != 5; ++I) {
if (Quals & QualKinds[I].Mask) {
if (!QualStr.empty()) QualStr += ' ';
QualStr += QualKinds[I].Name;
Expand Down Expand Up @@ -2690,7 +2695,8 @@ static void diagnoseRedundantReturnTypeQualifiers(Sema &S, QualType RetTy,
SourceLocation::getFromRawEncoding(PTI.ConstQualLoc),
SourceLocation::getFromRawEncoding(PTI.VolatileQualLoc),
SourceLocation::getFromRawEncoding(PTI.RestrictQualLoc),
SourceLocation::getFromRawEncoding(PTI.AtomicQualLoc));
SourceLocation::getFromRawEncoding(PTI.AtomicQualLoc),
SourceLocation::getFromRawEncoding(PTI.UnalignedQualLoc));
return;
}

Expand Down Expand Up @@ -2726,7 +2732,8 @@ static void diagnoseRedundantReturnTypeQualifiers(Sema &S, QualType RetTy,
D.getDeclSpec().getConstSpecLoc(),
D.getDeclSpec().getVolatileSpecLoc(),
D.getDeclSpec().getRestrictSpecLoc(),
D.getDeclSpec().getAtomicSpecLoc());
D.getDeclSpec().getAtomicSpecLoc(),
D.getDeclSpec().getUnalignedSpecLoc());
}

static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
Expand Down
11 changes: 11 additions & 0 deletions clang/test/CodeGenCXX/mangle-ms-cxx11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -293,3 +293,14 @@ int PR26105() {
}
// CHECK-DAG: @"\01??R<lambda_0>@?0??PR26105@@YAHXZ@QBE@H@Z"
// CHECK-DAG: @"\01??R<lambda_1>@?0???R<lambda_0>@?0??PR26105@@YAHXZ@QBE@H@Z@QBE@H@Z"

int __unaligned * unaligned_foo1() { return 0; }
int __unaligned * __unaligned * unaligned_foo2() { return 0; }
__unaligned int unaligned_foo3() { return 0; }
void unaligned_foo4(int __unaligned *p1) {}

// CHECK-DAG: @"\01?unaligned_foo1@@YAPFAHXZ"
// CHECK-DAG: @"\01?unaligned_foo2@@YAPFAPFAHXZ"
// CHECK-DAG: @"\01?unaligned_foo3@@YAHXZ"
// CHECK-DAG: @"\01?unaligned_foo4@@YAXPFAH@Z"

8 changes: 8 additions & 0 deletions clang/test/Sema/MicrosoftExtensions.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,11 @@ void myprintf(const char *f, ...) {
__va_start(ap, f); // expected-warning {{incompatible pointer types passing 'my_va_list'}}
}
}

// __unaligned handling
void test_unaligned() {
__unaligned int *p1 = 0;
int *p2 = p1; // expected-warning {{initializing 'int *' with an expression of type '__unaligned int *' discards qualifiers}}
__unaligned int *p3 = p2;
}

4 changes: 2 additions & 2 deletions clang/test/Sema/address_spaces.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ void foo(_AS3 float *a,
_AS1 int arrarr[5][5]; // expected-error {{automatic variable qualified with an address space}}

__attribute__((address_space(-1))) int *_boundsA; // expected-error {{address space is negative}}
__attribute__((address_space(0xFFFFFF))) int *_boundsB;
__attribute__((address_space(0x7FFFFF))) int *_boundsB;
__attribute__((address_space(0x1000000))) int *_boundsC; // expected-error {{address space is larger than the maximum supported}}
// chosen specifically to overflow 32 bits and come out reasonable
__attribute__((address_space(4294967500))) int *_boundsD; // expected-error {{address space is larger than the maximum supported}}
Expand Down Expand Up @@ -71,4 +71,4 @@ __attribute__((address_space("12"))) int *i; // expected-error {{'address_space'
// Clang extension doesn't forbid operations on pointers to different address spaces.
char* cmp(_AS1 char *x, _AS2 char *y) {
return x < y ? x : y; // expected-warning {{pointer type mismatch ('__attribute__((address_space(1))) char *' and '__attribute__((address_space(2))) char *')}}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only

#define OPENCL_CONSTANT 16776962
#define OPENCL_CONSTANT 8388354
int __attribute__((address_space(OPENCL_CONSTANT))) c[3] = {0};

void foo() {
Expand Down
41 changes: 40 additions & 1 deletion clang/test/SemaCXX/MicrosoftExtensions.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 %s -triple i686-pc-win32 -fsyntax-only -Wmicrosoft -Wc++11-extensions -Wno-long-long -verify -fms-extensions -fexceptions -fcxx-exceptions
// RUN: %clang_cc1 %s -triple i686-pc-win32 -fsyntax-only -Wmicrosoft -Wc++11-extensions -Wno-long-long -verify -fms-extensions -fexceptions -fcxx-exceptions -DTEST1
// RUN: %clang_cc1 %s -triple i686-pc-win32 -fsyntax-only -Wmicrosoft -Wc++11-extensions -Wno-long-long -verify -fexceptions -fcxx-exceptions -DTEST2

#if TEST1

// Microsoft doesn't validate exception specification.
namespace microsoft_exception_spec {
Expand Down Expand Up @@ -80,7 +82,32 @@ struct M {
// __unaligned handling
typedef char __unaligned *aligned_type;
typedef struct UnalignedTag { int f; } __unaligned *aligned_type2;
typedef char __unaligned aligned_type3;

// Check that __unaligned qualifier can be used for overloading
void foo_unaligned(int *arg) {}
void foo_unaligned(__unaligned int *arg) {}
void foo_unaligned(int arg) {} // expected-note {{previous definition is here}}
void foo_unaligned(__unaligned int arg) {} // expected-error {{redefinition of 'foo_unaligned'}}
class A_unaligned {};
class B_unaligned : public A_unaligned {};
int foo_unaligned(__unaligned A_unaligned *arg) { return 0; }
void *foo_unaligned(B_unaligned *arg) { return 0; }

void test_unaligned() {
int *p1 = 0;
foo_unaligned(p1);

__unaligned int *p2 = 0;
foo_unaligned(p2);

__unaligned B_unaligned *p3 = 0;
int p4 = foo_unaligned(p3);

B_unaligned *p5 = p3; // expected-error {{cannot initialize a variable of type 'B_unaligned *' with an lvalue of type '__unaligned B_unaligned *'}}

__unaligned B_unaligned *p6 = p3;
}

template<typename T> void h1(T (__stdcall M::* const )()) { }

Expand Down Expand Up @@ -420,3 +447,15 @@ struct S {

int S::fn() { return 0; } // expected-warning {{is missing exception specification}}
}

#elif TEST2

// Check that __unaligned is not recognized if MS extensions are not enabled
typedef char __unaligned *aligned_type; // expected-error {{expected ';' after top level declarator}}

#else

#error Unknown test mode

#endif