Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove old __capability workaround #709

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -1622,8 +1622,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// Return the unique reference to the type for the specified
/// typedef-name decl.
QualType getTypedefType(const TypedefNameDecl *Decl,
QualType Underlying = QualType(),
bool IsCHERICap = false) const;
QualType Underlying = QualType()) const;

QualType getRecordType(const RecordDecl *Decl) const;

Expand Down
4 changes: 0 additions & 4 deletions clang/include/clang/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -3181,10 +3181,6 @@ class TypeDecl : public NamedDecl {

/// Base class for declarations which introduce a typedef-name.
class TypedefNameDecl : public TypeDecl, public Redeclarable<TypedefNameDecl> {
/// CHERICapTypeForDecl - This indicates the Type object that represents the
/// memory capability version of this TypedefNameDecl. It is a cache
/// maintained by ASTContext::getTypedefType.
mutable const Type *CHERICapTypeForDecl = nullptr;
friend class ASTContext;

struct alignas(8) ModedTInfo {
Expand Down
34 changes: 4 additions & 30 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4701,42 +4701,16 @@ QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const {
/// getTypedefType - Return the unique reference to the type for the
/// specified typedef name decl.
QualType ASTContext::getTypedefType(const TypedefNameDecl *Decl,
QualType Underlying,
bool IsCHERICap) const {
if (IsCHERICap && Decl->CHERICapTypeForDecl)
return QualType(Decl->CHERICapTypeForDecl, 0);
if (!IsCHERICap && Decl->TypeForDecl)
QualType Underlying) const {
if (Decl->TypeForDecl)
return QualType(Decl->TypeForDecl, 0);

if (Underlying.isNull())
Underlying = Decl->getUnderlyingType();
QualType Canonical = getCanonicalType(Underlying);
if (IsCHERICap) {
if (const PointerType *PT = Canonical->getAs<PointerType>()) {
// Create a copy of the typedef whose name is prefixed by "__chericap_"
// and whose underlying type is the __capability qualified version of
// the pointer type
Canonical = getPointerType(PT->getPointeeType(), PIK_Capability);
TypeSourceInfo *TInfo = getTrivialTypeSourceInfo(Canonical, Decl->getBeginLoc());
DeclContext *DC = const_cast<DeclContext *>(Decl->getDeclContext());
std::string typedefName = "__chericap_" + Decl->getNameAsString();
TypedefDecl *NewDecl = TypedefDecl::Create(
const_cast<ASTContext &>(*this),
DC,
Decl->getBeginLoc(),
Decl->getLocation(),
&Idents.get(typedefName),
TInfo);
DC->addDecl(NewDecl);
Decl = NewDecl;
}
}
auto *newType = new (*this, TypeAlignment)
TypedefType(Type::Typedef, Decl, Underlying, Canonical);
if (IsCHERICap)
Decl->CHERICapTypeForDecl = newType;
else
Decl->TypeForDecl = newType;
TypedefType(Type::Typedef, Decl, Underlying, Canonical);
Decl->TypeForDecl = newType;
Types.push_back(newType);
return QualType(newType, 0);
}
Expand Down
105 changes: 50 additions & 55 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8236,63 +8236,61 @@ static void HandleCHERICapabilityQualifier(QualType &CurType,
// create a new instance of this type with a memory capability as the
// underlying type.
if (CurType->isPointerType() || CurType->isReferenceType()) {
// typedef'd types are special as they cache their capability
// counterparts; all other cases are shared with the declarator chunk
// case at the end of the function.
if (const TypedefType *TT = CurType->getAs<TypedefType>()) {
CurType = S.Context.getTypedefType(TT->getDecl(), QualType(), true);
return;
}
} else {
for (unsigned i = state.getCurrentChunkIndex(); i != 0; --i) {
DeclaratorChunk &chunk = declarator.getTypeObject(i-1);
switch (chunk.Kind) {
case DeclaratorChunk::Pointer: {
// Check for an ambiguous use where this is more than one pointer
// level, like __capability T **. We do this by checking that the next
// chunk isn't a pointer without the attribute.
if (i > 1) {
DeclaratorChunk &nextChunk = declarator.getTypeObject(i-2);
if (nextChunk.Kind == DeclaratorChunk::Pointer) {
auto Attr = nextChunk.getAttrs();
if (!Attr.hasAttribute(ParsedAttr::AT_CHERICapability)) {
S.Diag(nextChunk.Loc,
diag::err_cheri_capability_qualifier_ambiguous);
return;
}
}
// typedef'd types/typeof/decltype are special: a __capability qualifier
// before/after transforms the underlying type to the capability
// equivalent rather than pushing the capability qualifier to the
// outermost pointer type.
// So in `typedef int *intptr; __capability intptr *foo`, foo will be of
// type `int * __capability *` rather than `int **__capability`.
break;
}
for (unsigned i = state.getCurrentChunkIndex(); i != 0; --i) {
arichardson marked this conversation as resolved.
Show resolved Hide resolved
DeclaratorChunk &chunk = declarator.getTypeObject(i - 1);
switch (chunk.Kind) {
case DeclaratorChunk::Pointer: {
// Check for an ambiguous use where this is more than one pointer
// level, like __capability T **. We do this by checking that the next
// chunk isn't a pointer without the attribute.
if (i > 1) {
DeclaratorChunk &nextChunk = declarator.getTypeObject(i - 2);
if (nextChunk.Kind == DeclaratorChunk::Pointer) {
auto Attr = nextChunk.getAttrs();
if (!Attr.hasAttribute(ParsedAttr::AT_CHERICapability)) {
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_qualifier_location)
<< FixItHint::CreateRemoval(attr.getRange())
<< FixItHint::CreateInsertion(chunk.Loc.getLocWithOffset(1),
" " + Name + " ");

// Put this attribute in the right place after the next pointer
// chunk so we are called again with the parsed pointer type.
ParsedAttr *attrCopy = declarator.getAttributePool()
.create(const_cast<IdentifierInfo *>(attr.getAttrName()),
attr.getRange(),
const_cast<IdentifierInfo *>(attr.getScopeName()),
attr.getScopeLoc(), nullptr, 0,
ParsedAttr::AS_Keyword);
chunk.getAttrs().addAtEnd(attrCopy);
return;
}
case DeclaratorChunk::BlockPointer:
case DeclaratorChunk::Paren:
case DeclaratorChunk::Array:
case DeclaratorChunk::Function:
case DeclaratorChunk::Reference:
case DeclaratorChunk::Pipe:
continue;
case DeclaratorChunk::MemberPointer:
llvm_unreachable("Should this be handled?"); continue;

}

// Output a deprecated usage warning with a FixItHint
S.Diag(chunk.Loc, diag::warn_cheri_capability_qualifier_location)
<< FixItHint::CreateRemoval(attr.getRange())
<< FixItHint::CreateInsertion(chunk.Loc.getLocWithOffset(1),
" " + Name + " ");

// Put this attribute in the right place after the next pointer
// chunk so we are called again with the parsed pointer type.
ParsedAttr *attrCopy = declarator.getAttributePool().create(
const_cast<IdentifierInfo *>(attr.getAttrName()), attr.getRange(),
const_cast<IdentifierInfo *>(attr.getScopeName()),
attr.getScopeLoc(), nullptr, 0, ParsedAttr::AS_Keyword);
chunk.getAttrs().addAtEnd(attrCopy);
return;
}
case DeclaratorChunk::BlockPointer:
case DeclaratorChunk::Paren:
case DeclaratorChunk::Array:
case DeclaratorChunk::Function:
case DeclaratorChunk::Reference:
case DeclaratorChunk::Pipe:
continue;
case DeclaratorChunk::MemberPointer:
llvm_unreachable("Should this be handled?");
continue;
}
}

break;

case TAL_DeclChunk: {
Expand Down Expand Up @@ -8329,9 +8327,6 @@ static void HandleCHERICapabilityQualifier(QualType &CurType,
case TAL_DeclName:
llvm_unreachable(
"Keyword attribute should never be parsed after declaration's name");

default:
llvm_unreachable("Unknown type attribute location");
}

assert(S.Context.getTargetInfo().SupportsCapabilities());
Expand Down
3 changes: 1 addition & 2 deletions clang/test/Sema/cheri/cap-provenance-attr.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
/// Check that the attribute can be applied at any position
// RUN: %cheri_purecap_cc1 %s -fsyntax-only -Wall -verify -ast-dump -fcolor-diagnostics
// RUN: %cheri_purecap_cc1 %s -fsyntax-only -Wall -verify
/// Check that it also works in hybrid mode
// RUN: %cheri_cc1 %s -fsyntax-only -Wall -verify=expected,hybrid


typedef __uintcap_t uintptr_t;

typedef __attribute__((cheri_no_provenance)) __uintcap_t no_provenance_uintptr;
Expand Down
27 changes: 25 additions & 2 deletions clang/test/Sema/cheri/cheri-capability-qualifier-declspec.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,30 @@
// RUN: %cheri_cc1 -o - %s -fsyntax-only -verify
// RUN: %cheri_cc1 %s -fsyntax-only -verify
// expected-no-diagnostics

void * __capability test_typeof(void *p) {
void *__capability test_typeof(void *p) {
__typeof__(p) __capability c = (__cheri_tocap __typeof__(p) __capability)p;
_Static_assert(__builtin_types_compatible_p(typeof(c), void *__capability), "");
__capability __typeof__(p) c2 = (__cheri_tocap __capability __typeof__(p))p;
_Static_assert(__builtin_types_compatible_p(typeof(c2), void *__capability), "");
__capability __typeof__(p) *__capability c3 = (__cheri_tocap __capability __typeof__(p) *__capability)p;
_Static_assert(__builtin_types_compatible_p(typeof(c3), void *__capability *__capability), "");
return c;
}

static int *global_intptr = 0;
static __capability typeof(global_intptr) global_intcap = 0;
_Static_assert(__builtin_types_compatible_p(typeof(global_intptr), int *), "");
_Static_assert(__builtin_types_compatible_p(typeof(global_intcap), int *__capability), "");

/// Crash reproducer for https://github.com/CTSRD-CHERI/llvm-project/issues/710
// RUN: not --crash %cheri_cc1 %s -fsyntax-only -verify -DCRASH
// REQUIRES: asserts
#ifdef CRASH
struct s {
int i;
};
static struct s *global_sptr = 0;
static __capability typeof(global_sptr) global_scap = 0;
_Static_assert(__builtin_types_compatible_p(typeof(global_sptr), struct s *), "");
_Static_assert(__builtin_types_compatible_p(typeof(global_scap), struct s *__capability), "");
#endif
58 changes: 58 additions & 0 deletions clang/test/Sema/cheri/cheri-capability-qualifier-typedef.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// RUN: %cheri_cc1 %s -fsyntax-only -verify=expected,c
// RUN: %cheri_cc1 -xc++ %s -fsyntax-only -verify=expected,cxx
// RUN: %cheri_cc1 -xc++ -Dtypeof=decltype %s -fsyntax-only -verify=expected,cxx

#ifdef __cplusplus
#define CHECK_SAME(a, b) static_assert(__is_same(a *, b *), "")
#else
#define CHECK_SAME(a, b) _Static_assert(__builtin_types_compatible_p(a *, b *), "")
#endif

#define _CONCAT(a, b) a##b
#define CONCAT(a, b) _CONCAT(a, b)
#define CHECK_TYPE(ty, expected) \
typedef ty CONCAT(type_, __LINE__); \
CHECK_SAME(CONCAT(type_, __LINE__), expected); \
static ty CONCAT(var_, __LINE__); \
CHECK_SAME(typeof(CONCAT(var_, __LINE__)), expected); \
static CONCAT(type_, __LINE__) CONCAT(typedef_var_, __LINE__); \
CHECK_SAME(typeof(CONCAT(typedef_var_, __LINE__)), expected)

struct s;
typedef struct s s;
typedef s *sptr;
typedef s *__capability scap;
CHECK_TYPE(sptr, struct s *);
CHECK_TYPE(scap, struct s *__capability);

CHECK_TYPE(s *__capability, struct s *__capability);
CHECK_TYPE(__capability s *, struct s *__capability); // expected-warning 2 {{use of __capability before the pointer type is deprecated}}
CHECK_TYPE(s __capability *, struct s *__capability); // expected-warning 2 {{use of __capability before the pointer type is deprecated}}
CHECK_TYPE(sptr __capability, struct s *__capability);
// TODO: should __capability sptr also diagnose legacy usage?
CHECK_TYPE(__capability sptr, struct s *__capability);

// TODO: Should this warn about __capability being ignored?
CHECK_TYPE(__capability scap, struct s *__capability);
CHECK_TYPE(scap __capability, struct s *__capability);

/// Also check two levels of pointers
CHECK_TYPE(s *__capability *, struct s *__capability *);
CHECK_TYPE(scap *, struct s *__capability *);
CHECK_TYPE(__capability sptr *, struct s *__capability *);
CHECK_TYPE(sptr __capability *, struct s *__capability *);
CHECK_TYPE(__capability sptr *__capability, struct s *__capability *__capability);
CHECK_TYPE(sptr __capability *__capability, struct s *__capability *__capability);
// FIXME: this one is a bit odd, maybe should warn about ignored capability qualifier?
CHECK_TYPE(__capability scap *, struct s *__capability *);
CHECK_TYPE(scap __capability *, struct s *__capability *);

CHECK_TYPE(__capability s **, struct s *__capability *); // expected-error 2{{use of __capability is ambiguous}}
// c-error@-1 3{{static_assert failed due to requirement '__builtin_types_compatible_p(struct s ***, struct s * __capability **)'}}
// cxx-error@-2 3{{static_assert failed due to requirement '__is_same(s ***, s * __capability **)'}}
CHECK_TYPE(s __capability **, struct s *__capability *); // expected-error 2{{use of __capability is ambiguous}}
// c-error@-1 3{{static_assert failed due to requirement '__builtin_types_compatible_p(struct s ***, struct s * __capability **)'}}
// cxx-error@-2 3{{static_assert failed due to requirement '__is_same(s ***, s * __capability **)'}}
CHECK_TYPE(__capability s *__capability *, struct s *__capability *__capability); // expected-error 2 {{use of __capability is ambiguous}}
// c-error@-1 3{{static_assert failed due to requirement '__builtin_types_compatible_p(struct s * __capability **, struct s * __capability * __capability *)'}}
// cxx-error@-2 3{{static_assert failed due to requirement '__is_same(s * __capability **, s * __capability * __capability *)'}}
22 changes: 10 additions & 12 deletions clang/test/Sema/cheri/cheri-memcap-attr.c
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
// RUN: %cheri_cc1 -DDEPRECATED=1 -fsyntax-only -verify %s
// RUN: %cheri_cc1 -DDEPRECATED=1 -fsyntax-only -fdiagnostics-parseable-fixits -ast-dump %s 2>&1 | FileCheck -check-prefix=CHECK-DEPRECATED %s
// RUN: %cheri_cc1 -DAMBIGUOUS=1 -fsyntax-only -verify %s
// RUN: %cheri_cc1 -DNORMAL=1 -fsyntax-only -verify %s
// RUN: %cheri_cc1 -DNORMAL=1 -fsyntax-only -ast-dump %s | FileCheck -check-prefix=CHECK-NORMAL %s
// RUN: %cheri_cc1 -DNOT_POINTER=1 -fsyntax-only -verify %s
// RUN: %cheri_cc1 -DTYPEDEF=1 -fsyntax-only -verify %s
// RUN: %cheri_cc1 -DTYPEDEF=1 -fsyntax-only -ast-dump %s | FileCheck -check-prefix=CHECK-TYPEDEF %s
// RUN: %cheri_cc1 -DLIST=1 -fsyntax-only -ast-dump %s | FileCheck -check-prefix=CHECK-LIST %s
// RUN: %cheri_cc1 -DDEPRECATED=1 -fsyntax-only -verify %s
// RUN: %cheri_cc1 -DDEPRECATED=1 -fsyntax-only -fdiagnostics-parseable-fixits -ast-dump %s 2>&1 | FileCheck -check-prefix=CHECK-DEPRECATED %s
// RUN: %cheri_cc1 -DAMBIGUOUS=1 -fsyntax-only -verify %s
// RUN: %cheri_cc1 -DNORMAL=1 -fsyntax-only -verify -ast-dump %s | FileCheck -check-prefix=CHECK-NORMAL %s
// RUN: %cheri_cc1 -DNOT_POINTER=1 -fsyntax-only -verify %s
// RUN: %cheri_cc1 -DTYPEDEF=1 -fsyntax-only -verify -ast-dump %s | FileCheck -check-prefix=CHECK-TYPEDEF %s
// RUN: %cheri_cc1 -DLIST=1 -fsyntax-only -verify -ast-dump %s | FileCheck -check-prefix=CHECK-LIST %s

// Test expected compiler warnings/errors for the __capability qualifier

Expand Down Expand Up @@ -42,12 +40,12 @@ __capability int var1; // expected-error{{only applies to pointers}}
#ifdef TYPEDEF
// expected-no-diagnostics
typedef int* intptr;
__capability intptr x; // CHECK-TYPEDEF: x '__chericap_intptr':'int * __capability'
__capability intptr *y; // CHECK-TYPEDEF: y '__chericap_intptr *'
__capability intptr x; // CHECK-TYPEDEF: line:[[#@LINE]]:1, col:21> col:21 x 'int * __capability'
__capability intptr *y; // CHECK-TYPEDEF:line:[[#@LINE]]:1, col:22> col:22 y 'int * __capability *'
#endif

#ifdef LIST
__capability int *a, *b;
__capability int *a, *b; // expected-warning 2{{use of __capability before the pointer type is deprecated}}
// CHECK-LIST: a 'int * __capability'
// CHECK-LIST: b 'int * __capability'
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,14 @@

void * __capability test_decltype(void *p) {
decltype(p) __capability c = (__cheri_tocap decltype(p) __capability)p;
static_assert(__is_same(typeof(c) *, void *__capability *), "");
static_assert(__is_same(decltype(c) &__capability, void *__capability &__capability), "");
void *__capability &cref = c;
static_assert(__is_same(decltype(cref) __capability, void *__capability &__capability), "");
static_assert(__is_same(__capability decltype(cref), void *__capability &__capability), "");

using intref = int &;
static_assert(__is_same(intref __capability, int &__capability), "");
static_assert(__is_same(__capability intref, int &__capability), "");
return c;
}