Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -5508,7 +5508,7 @@ "incomplete result type %0 in function definition">; def err_atomic_specifier_bad_type : Error< "_Atomic cannot be applied to " - "%select{incomplete |array |function |reference |atomic |qualified |}0type " + "%select{array |function |reference |atomic |qualified |}0type " "%1 %select{||||||which is not trivially copyable}0">; // Expressions. Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -3144,7 +3144,7 @@ return ExprError(); } - // For a __c11 builtin, this should be a pointer to an _Atomic type. + // For a __c11 builtin, this should be a pointer to a complete _Atomic type. QualType AtomTy = pointerType->getPointeeType(); // 'A' QualType ValType = AtomTy; // 'C' if (IsC11) { @@ -3161,6 +3161,10 @@ return ExprError(); } ValType = AtomTy->getAs()->getValueType(); + + if (RequireCompleteType(DRE->getLocStart(), ValType, + diag::err_invalid_incomplete_type_use, ValType)) + return ExprError(); } else if (Form != Load && Form != LoadCopy) { if (ValType.isConstQualified()) { Diag(DRE->getLocStart(), diag::err_atomic_op_needs_non_const_pointer) Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -8019,25 +8019,21 @@ QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) { if (!T->isDependentType()) { - // FIXME: It isn't entirely clear whether incomplete atomic types - // are allowed or not; for simplicity, ban them for the moment. - if (RequireCompleteType(Loc, T, diag::err_atomic_specifier_bad_type, 0)) - return QualType(); - int DisallowedKind = -1; if (T->isArrayType()) - DisallowedKind = 1; + DisallowedKind = 0; else if (T->isFunctionType()) - DisallowedKind = 2; + DisallowedKind = 1; else if (T->isReferenceType()) - DisallowedKind = 3; + DisallowedKind = 2; else if (T->isAtomicType()) - DisallowedKind = 4; + DisallowedKind = 3; else if (T.hasQualifiers()) + DisallowedKind = 4; + else if (isCompleteType(Loc, T) && !T.isTriviallyCopyableType(Context)) + // Some other non-trivially-copyable type (probably a C++ class, or a C + // struct with a __weak or __strong field). DisallowedKind = 5; - else if (!T.isTriviallyCopyableType(Context)) - // Some other non-trivially-copyable type (probably a C++ class) - DisallowedKind = 6; if (DisallowedKind != -1) { Diag(Loc, diag::err_atomic_specifier_bad_type) << DisallowedKind << T; Index: test/CodeGen/c11atomics.c =================================================================== --- test/CodeGen/c11atomics.c +++ test/CodeGen/c11atomics.c @@ -474,3 +474,20 @@ // CHECK: ret i1 [[RES]] return __c11_atomic_compare_exchange_strong(addr, desired, *new, 5, 5); } + +int test_atomic_void_ptr(_Atomic void *addr) { + // CHECK-LABEL: @test_atomic_void_ptr(i8* %addr) + // CHECK: [[ADDR_ARG:%.*]] = alloca i8*, align 4 + // CHECK: [[ATOMIC_RES:%.*]] = alloca i32, align 4 + // CHECK: store i8* %addr, i8** [[ADDR_ARG]], align 4 + // CHECK: [[ADDR_LOCK_FREE:%.*]] = load i8*, i8** [[ADDR_ARG]], align 4 + // CHECK: call arm_aapcscc i32 @__atomic_is_lock_free(i32 1, i8* [[ADDR_LOCK_FREE]]) + // CHECK: [[ADDR:%.*]] = load i8*, i8** [[ADDR_ARG]], align 4 + // CHECK: [[CAST1:%.*]] = bitcast i8* [[ADDR]] to i32* + // CHECK: [[CAST2:%.*]] = bitcast i32* [[CAST1]] to i8* + // CHECK: call arm_aapcscc i32 @__atomic_load_4(i8* [[CAST2]], i32 5) + // CHECK: [[RES:%.*]] = load i32, i32* [[ATOMIC_RES]], align 4 + // CHECK: ret i32 [[RES]] + (void)__atomic_is_lock_free(1, addr); + return (int)__c11_atomic_load((_Atomic int *)addr, 5); +} Index: test/Sema/atomic-type.c =================================================================== --- test/Sema/atomic-type.c +++ test/Sema/atomic-type.c @@ -16,7 +16,17 @@ extern _Atomic(int (*)(int(*)[10], int(*)[10])) mergetest; _Atomic(int()) error1; // expected-error {{_Atomic cannot be applied to function type}} -_Atomic(struct ErrorS) error2; // expected-error {{_Atomic cannot be applied to incomplete type}} expected-note {{forward declaration}} +_Atomic(struct ErrorS) error2; _Atomic(int[10]) error3; // expected-error {{_Atomic cannot be applied to array type}} _Atomic(const int) error4; // expected-error {{_Atomic cannot be applied to qualified type}} _Atomic(_Atomic(int)) error5; // expected-error {{_Atomic cannot be applied to atomic type}} + +void g(_Atomic void *ptr); +void h(_Atomic struct Incomplete *ptr); // expected-warning {{declaration of 'struct Incomplete' will not be visible outside of this function}} + +void test_atomic_void_ptr(_Atomic void *addr) { + int i; + (void)__atomic_load(addr, &i, 5); // expected-error {{address argument to atomic operation must be a pointer to a trivially-copyable type ('_Atomic(void) *' invalid)}} + (void)__c11_atomic_load(addr, 5); // expected-error {{invalid use of incomplete type 'void'}} + _Static_assert(__atomic_is_lock_free(1, addr), ""); +} Index: test/Sema/atomic-type.cpp =================================================================== --- test/Sema/atomic-type.cpp +++ test/Sema/atomic-type.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 %s -verify -fsyntax-only + +struct S; + +void f(_Atomic S *s); + +struct S { int a, b; }; + +void f(_Atomic S *s) { + S s2; + (void)__atomic_load(s, &s2, 5); // expected-error {{address argument to atomic operation must be a pointer to a trivially-copyable type ('_Atomic(S) *' invalid)}} + (void)__c11_atomic_load(s, 5); +} +