llvm/clang/test/Sema/attr-read-only-placement.cpp

// RUN: %clang_cc1 -Wread-only-types %s -verify -fsyntax-only
// RUN: %clang_cc1 -std=c++2a -Wread-only-types %s -verify -fsyntax-only
// RUN: %clang_cc1 -std=c++17 -Wread-only-types %s -verify -fsyntax-only

struct __attribute__((enforce_read_only_placement)) A { // #A_DECL
};

A a1; // expected-warning {{object of type 'A' cannot be placed in read-only memory}}
      // expected-note@#A_DECL {{type was declared read-only here}}
const A a2[10]; // no-warning
A a3[20]; // expected-warning {{object of type 'A' cannot be placed in read-only memory}}
          // expected-note@#A_DECL {{type was declared read-only here}}



struct B;
struct __attribute__((enforce_read_only_placement)) B { //#B_DECL
};

B b1; // expected-warning {{object of type 'B' cannot be placed in read-only memory}}
      // expected-note@#B_DECL {{type was declared read-only here}}
const B b2; // no-warning
const B b3[4]; // no-warning
B b4[5]; // expected-warning {{object of type 'B' cannot be placed in read-only memory}}
         // expected-note@#B_DECL {{type was declared read-only here}}
B b5[5][5]; // expected-warning {{object of type 'B' cannot be placed in read-only memory}}
            // expected-note@#B_DECL {{type was declared read-only here}}
B b10[5][5][5]; // expected-warning {{object of type 'B' cannot be placed in read-only memory}}
                // expected-note@#B_DECL {{type was declared read-only here}}

void method1() {
    static const B b6;
    static B b7;// expected-warning {{object of type 'B' cannot be placed in read-only memory}}
                // expected-note@#B_DECL {{type was declared read-only here}}
    B b8; // no-warning
    const B b9; // no-warning
}

struct C;
struct __attribute__((enforce_read_only_placement)) C; // expected-note {{type was declared read-only here}}
struct C { // no-note. The note should be attached to the definition/declaration bearing the attribute
};

C c1; // expected-warning {{object of type 'C' cannot be placed in read-only memory}}

// Cases to be handled by the follow-up patches.

// Attaching and checking the attribute in reverse, where the attribute is attached after the
// type definition
struct D;
struct D { //expected-note{{previous definition is here}}
};
struct __attribute__((enforce_read_only_placement)) D; // #3
                // expected-warning@#3{{attribute declaration must precede definition}}

D d1; // We do not  emit a warning here, as there is another warning for declaring
      // a type after the definition


// Cases where the attribute must be explicitly attached to another type
// Case 1: Inheriting from a type that has the attribute
struct E : C { // FIXME: warn the user declarations of type `E`, that extends `C`, won't be
               // checked for read only placement because `E` is not marked as `C` is.
};

// Case 2: Declaring a field of the type that has the attribute
struct F {
    C c1; // FIXME: warn the user type `F` that wraps type `C` won't be checked for
          // read only placement
};

struct BaseWithoutAttribute {
    int a;
};

struct  __attribute__((enforce_read_only_placement)) J : BaseWithoutAttribute { // no-warning
};

struct __attribute__((enforce_read_only_placement)) BaseWithAttribute {
    int i;
};

struct __attribute__((enforce_read_only_placement)) Derived : BaseWithAttribute { // no-warning
    int j;
};

struct __attribute__((enforce_read_only_placement)) WrapperToAttributeInstance { // no-warning
    BaseWithAttribute b;
};

struct __attribute__((enforce_read_only_placement)) WrapperToNoAttributeInstance { // no-warning
    BaseWithoutAttribute b;
};

// Cases where the const qualification doesn't ensure read-only memory placement
// of an instance.

// Case 1: The type defines/inherits mutable data members
struct __attribute__((enforce_read_only_placement)) G {
    mutable int x; // FIXME: warn the user type `G` won't be placed in the read only program memory
};

struct __attribute__((enforce_read_only_placement)) H : public G { // FIXME: Warn the user type `H`
                                                // won't be placed in the read only program memory
};

struct __attribute__((enforce_read_only_placement)) K { // FIXME : Warn the user type `K` w on't be
                                                // placed in the read only program memory
    G g;
};


// Case 2: The type has a constructor that makes its fields modifiable
struct  __attribute__((enforce_read_only_placement)) L {
    int b;
    L(int val) { // FIXME: warn the user type `L` won't be placed in the read only program memory
      b = val;
    }
};

struct __attribute__((enforce_read_only_placement)) ConstInClassInitializers { // no-warning
  int b = 12;

  ConstInClassInitializers() = default;
};

int foo();
struct __attribute__((enforce_read_only_placement)) NonConstInClassInitializers {
  int b = foo(); // FIXME: warn the user type `NonConstInClassInitializers` won't be placed
                 // in the read only program memory

  NonConstInClassInitializers() = default;
};

#if (__cplusplus >= 202002L)
struct __attribute__((enforce_read_only_placement)) ConstevalCtor {
  int b;

  consteval ConstevalCtor(int B) : b(B) {} // no-warning
};
#endif

#if (__cplusplus >= 201103L)
struct __attribute__((enforce_read_only_placement)) ConstExprCtor { // no-warning
  int b;

  constexpr ConstExprCtor(int B) : b(B) {}
};

constexpr ConstExprCtor cec1(10); // no-warning

#endif

// Cases where an object is allocated on the heap or on the stack
C *c2 = new C; // FIXME: warn the user this instance of 'C' won't be placed in the read only program memory

void func1(C c); // FIXME: warn the user the instance of 'C' won't be placed in the read only program memory

void func2(const C c); // FIXME: warn the user the instance of 'C' won't be placed in the read
                       // only program memory

C func3(); // FIXME: warn the user the instance of 'C' won't be placed in the read only program memory

void func4() {
    C c; // FIXME: warn the user the instance of 'C' won't be placed in the read only program memory
}

#if (__cplusplus >= 202002L)
consteval void func4(C c); // no-warning
#endif