diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 10dd3523fa7a..47c0b613f559 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1123,9 +1123,6 @@ class ASTContext : public RefCountedBase { CanQualType SignedCharTy, ShortTy, IntTy, LongTy, LongLongTy, Int128Ty; CanQualType UnsignedCharTy, UnsignedShortTy, UnsignedIntTy, UnsignedLongTy; CanQualType IntCapTy, UnsignedIntCapTy; - // Non-provenance carrying intcap_t types - QualType NoProvenanceIntCapTy; - QualType NoProvenanceUnsignedIntCapTy; CanQualType UnsignedLongLongTy, UnsignedInt128Ty; CanQualType FloatTy, DoubleTy, LongDoubleTy, Float128Ty, Ibm128Ty; CanQualType ShortAccumTy, AccumTy, diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 2d8c107fa776..68091cfe12c3 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1334,12 +1334,6 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target, InitBuiltinType(IntCapTy, BuiltinType::IntCap); InitBuiltinType(UnsignedIntCapTy, BuiltinType::UIntCap); - if (Target.SupportsCapabilities()) { - NoProvenanceIntCapTy = - getAttributedType(attr::CHERINoProvenance, IntCapTy, IntCapTy); - NoProvenanceUnsignedIntCapTy = getAttributedType( - attr::CHERINoProvenance, UnsignedIntCapTy, UnsignedIntCapTy); - } // GNU extension, __float128 for IEEE quadruple precision InitBuiltinType(Float128Ty, BuiltinType::Float128); @@ -10994,15 +10988,20 @@ QualType ASTContext::getNonProvenanceCarryingType(QualType T) const { // if (!Target->SupportsCapabilities()) // return T; // XXX: should probably assert instead? assert(Target->SupportsCapabilities()); - // Must be called with either intcap_t or uintcap_t - if (const BuiltinType *BT = dyn_cast(T.getCanonicalType())) { - if (BT->getKind() == BuiltinType::IntCap) - return NoProvenanceIntCapTy; - if (BT->getKind() == BuiltinType::UIntCap) - return NoProvenanceUnsignedIntCapTy; - } - llvm_unreachable("Invalid type passed to getNonProvenanceCarryingType"); - return T; + // Must be called with either intcap_t or uintcap_t (or atomic variants + // thereof) + assert(T->isIntCapType() && + "Invalid type passed to getNonProvenanceCarryingType"); + if (const AtomicType *AT = dyn_cast(T.getDesugaredType(*this))) { + QualType VT = AT->getValueType(); + if (VT->hasAttr(attr::CHERINoProvenance)) + return T; + return getAtomicType(getNonProvenanceCarryingType(VT)); + } + if (T->hasAttr(attr::CHERINoProvenance)) + return T; + return const_cast(this)->getAttributedType( + attr::CHERINoProvenance, T, T); } QualType ASTContext::getCorrespondingUnsignedType(QualType T) const { diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 1a47542feabf..3b2284c14cc9 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -2102,16 +2102,8 @@ QualType CastExpr::checkProvenanceImpl(QualType Ty, const ASTContext &C, NPC_ValueDependentIsNotNull)) ExprCanCarryProvenance = false; - if (!ExprCanCarryProvenance) { - // FIXME: allowing __uintcap_t as the underlying type for enums is not - // ideal, as this means we need a const_cast here. - if (Ty->isEnumeralType()) { - return const_cast(C).getAttributedType( - attr::CHERINoProvenance, Ty, Ty); - } else { - return C.getNonProvenanceCarryingType(Ty); - } - } + if (!ExprCanCarryProvenance) + return C.getNonProvenanceCarryingType(Ty); return Ty; } diff --git a/clang/test/Sema/cheri/atomic-init.c b/clang/test/Sema/cheri/atomic-init.c new file mode 100644 index 000000000000..f99458e8face --- /dev/null +++ b/clang/test/Sema/cheri/atomic-init.c @@ -0,0 +1,28 @@ +// RUN: %cheri_cc1 %s -ast-dump | FileCheck %s +// RUN: %cheri_purecap_cc1 %s -ast-dump | FileCheck %s + +/// Crashed with "Invalid type passed to getNonProvenanceCarryingType" due to +/// not handling AtomicType +// CHECK: VarDecl {{.*}} <{{.*}}:[[@LINE+4]]:1, col:22> col:18 x '_Atomic(__intcap)' cinit +// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Atomic(__intcap __attribute__((cheri_no_provenance)))' +// CHECK-NEXT: ImplicitCastExpr {{.*}} '__intcap __attribute__((cheri_no_provenance))':'__intcap' +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0 +_Atomic __intcap x = 0; + +/// Check we preserve typedefs where possible +typedef __intcap T; +typedef _Atomic T AT; +// CHECK: VarDecl {{.*}} <{{.*}}:[[@LINE+4]]:1, col:8> col:4 y 'AT':'_Atomic(T)' cinit +// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Atomic(T __attribute__((cheri_no_provenance)))' +// CHECK-NEXT: ImplicitCastExpr {{.*}} '__intcap __attribute__((cheri_no_provenance))':'__intcap' +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0 +AT y = 0; + +/// Check that we don't duplicate attributes when preserving typdefs +typedef __intcap __attribute__((cheri_no_provenance)) TNP; +typedef _Atomic TNP ATNP; +// CHECK: VarDecl {{.*}} <{{.*}}:[[@LINE+4]]:1, col:10> col:6 z 'ATNP':'_Atomic(TNP)' cinit +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'ATNP':'_Atomic(TNP)' +// CHECK-NEXT: ImplicitCastExpr {{.*}} '__intcap __attribute__((cheri_no_provenance))':'__intcap' +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0 +ATNP z = 0; diff --git a/clang/test/SemaCXX/cheri/cap-provenance-auto.cpp b/clang/test/SemaCXX/cheri/cap-provenance-auto.cpp index 5b04176a33c2..84a627bb61da 100644 --- a/clang/test/SemaCXX/cheri/cap-provenance-auto.cpp +++ b/clang/test/SemaCXX/cheri/cap-provenance-auto.cpp @@ -10,8 +10,8 @@ typedef __no_provenance unsigned __intcap no_provenance_uintptr_t; void test_auto(uintptr_t prov, no_provenance_uintptr_t noprov) { // CHECK-LABEL: {{.+}} test_auto 'void (uintptr_t, no_provenance_uintptr_t)' - auto zero = static_cast(0); // CHECK: VarDecl {{.+}} col:8 used zero 'unsigned __intcap __attribute__((cheri_no_provenance))':'unsigned __intcap' cinit{{$}} - const auto const_zero = static_cast(0); // CHECK: VarDecl {{.+}} col:14 const_zero 'unsigned __intcap const __attribute__((cheri_no_provenance))':'const unsigned __intcap' cinit{{$}} + auto zero = static_cast(0); // CHECK: VarDecl {{.+}} col:8 used zero 'uintptr_t __attribute__((cheri_no_provenance))':'unsigned __intcap' cinit{{$}} + const auto const_zero = static_cast(0); // CHECK: VarDecl {{.+}} col:14 const_zero 'uintptr_t const __attribute__((cheri_no_provenance))':'const unsigned __intcap' cinit{{$}} zero = prov; zero = prov; zero = noprov; @@ -28,14 +28,14 @@ void test_auto_assign(uintptr_t prov, no_provenance_uintptr_t noprov) { void test_return_type_lambda(uintptr_t prov, no_provenance_uintptr_t noprov) { // CHECK-LABEL: {{.+}} test_return_type_lambda 'void (uintptr_t, no_provenance_uintptr_t)' - auto lambda = []() { return static_cast(0); }; // CHECK: CXXMethodDecl {{.+}} col:17 used constexpr operator() 'unsigned __intcap () const __attribute__((cheri_no_provenance))' inline - auto from_lambda = lambda(); // CHECK: VarDecl {{.+}} col:8 used from_lambda 'unsigned __intcap __attribute__((cheri_no_provenance))':'unsigned __intcap' cinit{{$}} - const auto const_from_lambda = lambda(); // CHECK: VarDecl {{.+}} col:14 referenced const_from_lambda 'const unsigned __intcap __attribute__((cheri_no_provenance))':'const unsigned __intcap' cinit{{$}} + auto lambda = []() { return static_cast(0); }; // CHECK: CXXMethodDecl {{.+}} col:17 used constexpr operator() 'uintptr_t () const __attribute__((cheri_no_provenance))' inline + auto from_lambda = lambda(); // CHECK: VarDecl {{.+}} col:8 used from_lambda 'uintptr_t __attribute__((cheri_no_provenance))':'unsigned __intcap' cinit{{$}} + const auto const_from_lambda = lambda(); // CHECK: VarDecl {{.+}} col:14 referenced const_from_lambda 'const uintptr_t __attribute__((cheri_no_provenance))':'const unsigned __intcap' cinit{{$}} from_lambda = const_from_lambda; from_lambda = prov; from_lambda = noprov; } -auto return_noprov() { // CHECK: FunctionDecl {{.+}} line:[[@LINE]]:6 return_noprov 'unsigned __intcap () __attribute__((cheri_no_provenance))' +auto return_noprov() { // CHECK: FunctionDecl {{.+}} line:[[@LINE]]:6 return_noprov 'uintptr_t () __attribute__((cheri_no_provenance))' return static_cast(0); }