diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index c6fb4920c41f..4d1db633f582 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -302,7 +302,7 @@ def err_expected_selector_for_method : Error< "expected selector for Objective-C method">; def err_expected_property_name : Error<"expected property name">; -def warn_cheri_capability_attribute_location : Warning< +def warn_cheri_capability_qualifier_location : Warning< "use of __capability before the pointer type is deprecated">, InGroup; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index d302f1015935..d2447e8ee453 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1298,9 +1298,12 @@ def note_cheri_func_noproto_explanation : Note< "values from the argument registers.">; def note_cheri_func_decl_add_types : Note< "candidate function declaration needs parameter types">; -def err_cheri_capability_attribute_ambiguous : Error< +def err_cheri_capability_qualifier_not_supported : Error< + "use of __capability is not supported without CHERI; " + "specify an appropriate -march= or -mcpu=">; +def err_cheri_capability_qualifier_ambiguous : Error< "use of __capability is ambiguous">; -def err_cheri_capability_attribute_pointers_only : Error< +def err_cheri_capability_qualifier_pointers_only : Error< "__capability only applies to pointers; type here is %0">; def err_objc_var_decl_inclass : diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 48d94f8b2ae7..f6a15e758fcb 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -888,8 +888,14 @@ void Parser::ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs) { void Parser::ParseCapabilityQualifier(ParsedAttributes &Attrs) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = Tok.getLocation(); - Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, - ParsedAttr::AS_Keyword); + // Report an error if the target does not support CHERI. + // TODO: we should not treat __capability as a keyword for non-CHERI. + // See https://github.com/CTSRD-CHERI/llvm-project/issues/706. + if (!getTargetInfo().SupportsCapabilities()) + Diag(AttrNameLoc, diag::err_cheri_capability_qualifier_not_supported); + else + Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + ParsedAttr::AS_Keyword); } static bool VersionNumberSeparator(const char Separator) { diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 1fb0078371c9..b43124bb8b89 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -6372,8 +6372,7 @@ fillDependentPointerTypeLoc(DependentPointerTypeLoc DPTL, } } - llvm_unreachable( - "no cheri_capability attribute found at the expected location!"); + llvm_unreachable("no __capability qualifier found at the expected location!"); } static void fillMatrixTypeLoc(MatrixTypeLoc MTL, @@ -8213,18 +8212,19 @@ QualType Sema::BuildPointerInterpretationAttr(QualType T, } else if (T->isDependentType()) { T = Context.getDependentPointerType(T, PIK, QualifierLoc); } else { - Diag(QualifierLoc, diag::err_cheri_capability_attribute_pointers_only) - << T; + Diag(QualifierLoc, diag::err_cheri_capability_qualifier_pointers_only) << T; } return T; } -/// HandleCHERICapabilityAttr - Process the cheri_capability attribute. It is +/// HandleCHERICapabilityQualifier - Process the __capability qualifier. It is /// only applicable to pointer and reference types and specifies that this /// pointer/reference should be treated as a capability. -static void HandleCHERICapabilityAttr(QualType &CurType, TypeProcessingState &state, - TypeAttrLocation TAL, ParsedAttr& attr) { +static void HandleCHERICapabilityQualifier(QualType &CurType, + TypeProcessingState &state, + TypeAttrLocation TAL, + ParsedAttr &attr) { Declarator &declarator = state.getDeclarator(); Sema& S = state.getSema(); std::string Name = attr.getAttrName()->getName().str(); @@ -8256,14 +8256,15 @@ static void HandleCHERICapabilityAttr(QualType &CurType, TypeProcessingState &st if (nextChunk.Kind == DeclaratorChunk::Pointer) { auto Attr = nextChunk.getAttrs(); if (!Attr.hasAttribute(ParsedAttr::AT_CHERICapability)) { - S.Diag(nextChunk.Loc, diag::err_cheri_capability_attribute_ambiguous); + S.Diag(nextChunk.Loc, + diag::err_cheri_capability_qualifier_ambiguous); return; } } } // Output a deprecated usage warning with a FixItHint - S.Diag(chunk.Loc, diag::warn_cheri_capability_attribute_location) + S.Diag(chunk.Loc, diag::warn_cheri_capability_qualifier_location) << FixItHint::CreateRemoval(attr.getRange()) << FixItHint::CreateInsertion(chunk.Loc.getLocWithOffset(1), " " + Name + " "); @@ -8333,6 +8334,7 @@ static void HandleCHERICapabilityAttr(QualType &CurType, TypeProcessingState &st llvm_unreachable("Unknown type attribute location"); } + assert(S.Context.getTargetInfo().SupportsCapabilities()); CurType = S.BuildPointerInterpretationAttr(CurType, PIK_Capability, attr.getLoc()); } @@ -8645,7 +8647,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, case ParsedAttr::AT_CHERICapability: attr.setUsedAsTypeAttr(); - HandleCHERICapabilityAttr(type, state, TAL, attr); + HandleCHERICapabilityQualifier(type, state, TAL, attr); break; case ParsedAttr::AT_CHERINoSubobjectBounds: attr.setUsedAsTypeAttr(); diff --git a/clang/test/Parser/capability-qualifier-non-cheri.c b/clang/test/Parser/capability-qualifier-non-cheri.c new file mode 100644 index 000000000000..5d0b64854680 --- /dev/null +++ b/clang/test/Parser/capability-qualifier-non-cheri.c @@ -0,0 +1,8 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +/// Using __capability without the appropriate -march string previously +/// crashed clang during codegen instead of emitting an error earlier. +// RUN: %clang_cc1 -triple riscv64 -fsyntax-only %s -verify=no-cheri +// RUN: %clang_cc1 -triple riscv64 -target-feature +xcheri -fsyntax-only %s -verify=cheri +// cheri-no-diagnostics + +void *__capability foo; // no-cheri-error{{use of __capability is not supported without CHERI; specify an appropriate -march= or -mcpu=}} diff --git a/clang/test/Sema/cheri/cheri-capability-attr-invalid-type.c b/clang/test/Sema/cheri/cheri-capability-attr-invalid-type.c deleted file mode 100644 index 4c687b5bb2c6..000000000000 --- a/clang/test/Sema/cheri/cheri-capability-attr-invalid-type.c +++ /dev/null @@ -1,28 +0,0 @@ -// RUN: not %cheri_cc1 -target-abi n64 -fsyntax-only %s 2>&1 | FileCheck %s -// Test case for https://github.com/CTSRD-CHERI/clang/issues/157 -// We only check if the compiler crashes - -// CHECK: * - -#define a(b) \ - { \ - typedef __typeof__(b) c; \ - __capability c d; } -int e() { - int *pipv = (a(pip)); -} - - -# define ZEXPORT -# define FAR -typedef unsigned char Byte; -# define Bytef Byte FAR -#define cheri_ptr_to_bounded_cap(ptr) __extension__({ \ - typedef __typeof__(ptr) __ptr_type; \ - typedef __capability __ptr_type __cap_type; \ - z_stream; -typedef z_stream FAR * __capability z_streamp; -int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) Bytef *dest; -{ - z_stream stream; - z_streamp stream_cap = cheri_ptr_to_bounded_cap(&stream); diff --git a/clang/test/Sema/cheri/cheri-capability-qualifier-typo-correction.c b/clang/test/Sema/cheri/cheri-capability-qualifier-typo-correction.c new file mode 100644 index 000000000000..7fdb91c58c65 --- /dev/null +++ b/clang/test/Sema/cheri/cheri-capability-qualifier-typo-correction.c @@ -0,0 +1,14 @@ +// RUN: %cheri_cc1 -target-abi n64 -fsyntax-only %s -verify +/// Test case for https://github.com/CTSRD-CHERI/clang/issues/157 +/// Applying __capability qualifier to a typedef as part of typo correction used to crash. + +#define a(b) \ + __extension__({ \ + typedef __typeof__(b) c; \ + __capability c d; \ + }) +int e() { + int *__capability pipv = a(pip); // expected-error{{use of undeclared identifier 'pip'; did you mean 'pipv'?}} + // expected-error@-1{{initializing 'int * __capability' with an expression of incompatible type 'void'}} + // expected-note@-2{{'pipv' declared here}} +}