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}}
|