aboutsummaryrefslogtreecommitdiff
path: root/clang/test/SemaCXX/gnu-asm-constexpr.cpp
blob: 77466df12bdc195593d2cccc044adda2489332a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++26 -triple x86_64-gnu-linux
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++26 -triple x86_64-gnu-linux -fexperimental-new-constant-interpreter

template <bool Leak>
struct RAIIBase {
    constexpr RAIIBase(const char* in) {
        s = __builtin_strlen(in);
        d = new char[s + 1]; // expected-note 4{{allocation performed here was not deallocated}}
        for(int i = 0 ; i < s; i++)
            d[i] = in[i];
    }
    int s;
    char* d;
    constexpr unsigned long size() const {
        return s;
    }
    constexpr const char* data() const {
        return d;
    }
    constexpr ~RAIIBase() {
        if constexpr(!Leak)
            delete[] d;
    }
};

using RAII = RAIIBase<false>;
using RAIILeak = RAIIBase<true>;

void test_leaks(int i) {
    asm((RAII("nop")) : (RAII("+ir")) (i) : (RAII("g")) (i) : (RAII("memory")));
    asm((RAIILeak("nop"))); // expected-error {{the expression in this asm operand must be produced by a constant expression}}
    asm((RAII("nop"))
        : (RAIILeak("+ir")) (i) // expected-error {{the expression in this asm operand must be produced by a constant expression}}
        ::
    );
    asm((RAII("nop"))
        : (RAII("+ir")) (i)
        : (RAIILeak("g")) (i) // expected-error {{the expression in this asm operand must be produced by a constant expression}}
        :
    );
    asm((RAII("nop"))
        : (RAII("+ir")) (i)
        : (RAII("g")) (i)
        : (RAIILeak("memory")) // expected-error {{the expression in this asm operand must be produced by a constant expression}}
    );
}

struct NotAString{};
struct MessageInvalidSize {
    constexpr unsigned long size(int) const; // expected-note {{'size' declared here}}
    constexpr const char* data() const;
};
struct MessageInvalidData {
    constexpr unsigned long size() const;
    constexpr const char* data(int) const; // expected-note {{'data' declared here}}
};


struct WMessage {
    constexpr unsigned long long size() const {return 0;};
    constexpr const wchar_t* data() const {return L"";}
};

struct string_view {
  int S;
  const char* D;
  constexpr string_view() : S(0), D(0){}
  constexpr string_view(const char* Str) : S(__builtin_strlen(Str)), D(Str) {}
  constexpr string_view(int Size, const char* Str) : S(Size), D(Str) {}
  constexpr int size() const {
      return S;
  }
  constexpr const char* data() const {
      return D;
  }
};


void f() {
    asm(("")); // expected-error {{the expression in this asm operand must be a string literal or an object with 'data()' and 'size()' member functions}}
    asm((NotAString{})); // expected-error {{the string object in this asm operand is missing 'data()' and 'size()' member functions}}
    asm((MessageInvalidData{})); // expected-error {{the expression in this asm operand must have a 'data()' member function returning an object convertible to 'const char *'}} \
                                 // expected-error {{too few arguments to function call, expected 1, have 0}}
    asm((MessageInvalidSize{})); // expected-error {{the expression in this asm operand must have a 'size()' member function returning an object convertible to 'std::size_t'}} \
                                 // expected-error {{too few arguments to function call, expected 1, have 0}}

    asm((WMessage{})); // expected-error {{value of type 'const wchar_t *' is not implicitly convertible to 'const char *'}} \
                       // expected-error {{the expression in this asm operand must have a 'data()' member function returning an object convertible to 'const char *'}}
}

template <typename... U>
void test_packs() {
    asm((U{})); // expected-error {{expression contains unexpanded parameter pack 'U'}}
    asm("" : (U{})); // expected-error {{expression contains unexpanded parameter pack 'U'}}
    asm("" :: (U{})); // expected-error {{expression contains unexpanded parameter pack 'U'}}
    asm("" ::: (U{})); // expected-error {{expression contains unexpanded parameter pack 'U'}}
}

template <typename T>
void test_dependent1(int i) {
    asm((T{})); // #err-int
    asm("" : (T{"+g"})(i)); // #err-int2
    asm("" :: (T{"g"})(i)); // #err-int3
    asm("" ::: (T{"memory"})); // #err-int4
}

template void test_dependent1<int>(int);
// expected-note@-1 {{in instantiation of function template specialization}}
// expected-error@#err-int {{the expression in this asm operand must be a string literal or an object with 'data()' and 'size()' member functions}}
// expected-error@#err-int2 {{cannot initialize a value of type 'int' with an lvalue of type 'const char[3]'}}
// expected-error@#err-int3 {{cannot initialize a value of type 'int' with an lvalue of type 'const char[2]'}}
// expected-error@#err-int4 {{cannot initialize a value of type 'int' with an lvalue of type 'const char[7]'}}

template void test_dependent1<string_view>(int);


template <typename T>
void test_dependent2(int i) {
    asm("" : (T{"g"})(i)); // #err-invalid1
    asm("" :: (T{"+g"})(i)); // #err-invalid2
    asm("" ::: (T{"foo"})); // #err-invalid3
}
template void test_dependent2<string_view>(int);
// expected-note@-1 {{in instantiation of function template specialization}}
// expected-error@#err-invalid1 {{invalid output constraint 'g' in asm}}
// expected-error@#err-invalid2 {{invalid input constraint '+g' in asm}}
// expected-error@#err-invalid3 {{unknown register name 'foo' in asm}}