cor3ntin updated this revision to Diff 535356.
cor3ntin added a comment.
revert accidental changes to cmake
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D105759/new/
https://reviews.llvm.org/D105759
Files:
clang-tools-extra/test/clang-tidy/checkers/modernize/unary-static-assert.cpp
clang/include/clang/AST/Expr.h
clang/include/clang/Basic/DiagnosticCommonKinds.td
clang/include/clang/Basic/DiagnosticLexKinds.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Lex/LiteralSupport.h
clang/include/clang/Parse/Parser.h
clang/include/clang/Sema/ParsedAttr.h
clang/include/clang/Sema/Sema.h
clang/lib/AST/Expr.cpp
clang/lib/Lex/LiteralSupport.cpp
clang/lib/Lex/PPMacroExpansion.cpp
clang/lib/Lex/Pragma.cpp
clang/lib/Parse/ParseDecl.cpp
clang/lib/Parse/ParseDeclCXX.cpp
clang/lib/Parse/ParseExpr.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaExprCXX.cpp
clang/lib/Sema/SemaInit.cpp
clang/test/CXX/dcl.dcl/dcl.link/p2.cpp
clang/test/CXX/dcl.dcl/p4-0x.cpp
clang/test/FixIt/fixit-static-assert.cpp
clang/test/Parser/MicrosoftExtensions.cpp
clang/test/Parser/c2x-attributes.c
clang/test/Parser/cxx-attributes.cpp
clang/test/Parser/cxx0x-attributes.cpp
clang/test/Sema/MicrosoftExtensions.c
clang/test/Sema/annotate-type.c
clang/test/Sema/annotate.c
clang/test/Sema/attr-assume.c
clang/test/Sema/attr-btf_tag.c
clang/test/Sema/attr-btf_type_tag.c
clang/test/Sema/attr-capabilities.c
clang/test/Sema/attr-enforce-tcb-errors.cpp
clang/test/Sema/attr-enforce-tcb-errors.m
clang/test/Sema/attr-error.c
clang/test/Sema/attr-handles.cpp
clang/test/Sema/attr-section.c
clang/test/Sema/attr-tls_model.c
clang/test/Sema/attr-unavailable-message.c
clang/test/Sema/attr-warning.c
clang/test/Sema/diagnose_if.c
clang/test/Sema/enable_if.c
clang/test/SemaCXX/attr-deprecated-replacement-error.cpp
clang/test/SemaCXX/attr-no-sanitize.cpp
clang/test/SemaCXX/attr-section.cpp
clang/test/SemaCXX/attr-weakref.cpp
clang/test/SemaCXX/static-assert.cpp
clang/test/SemaCXX/suppress.cpp
clang/test/SemaObjC/attr-swift_bridge.m
clang/test/SemaObjC/objc-asm-attribute-neg-test.m
clang/test/SemaObjC/validate-attr-swift_attr.m
clang/test/SemaTemplate/attributes.cpp
clang/utils/TableGen/ClangAttrEmitter.cpp
Index: clang/utils/TableGen/ClangAttrEmitter.cpp
===================================================================
--- clang/utils/TableGen/ClangAttrEmitter.cpp
+++ clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -2297,6 +2297,22 @@
.Default(false);
}
+static bool isStringLiteralArgument(const Record *Arg) {
+ return !Arg->getSuperClasses().empty() &&
+ llvm::StringSwitch<bool>(
+ Arg->getSuperClasses().back().first->getName())
+ .Case("StringArgument", true)
+ .Default(false);
+}
+
+static bool isVariadicStringLiteralArgument(const Record *Arg) {
+ return !Arg->getSuperClasses().empty() &&
+ llvm::StringSwitch<bool>(
+ Arg->getSuperClasses().back().first->getName())
+ .Case("VariadicStringArgument", true)
+ .Default(false);
+}
+
static void emitClangAttrVariadicIdentifierArgList(RecordKeeper &Records,
raw_ostream &OS) {
OS << "#if defined(CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST)\n";
@@ -2317,6 +2333,34 @@
OS << "#endif // CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST\n\n";
}
+// Emits the list of arguments that shoulkd be parsed as unevaluated string
+// literals for each attributes
+static void emitClangAttrUnevaluatedStringLiteralList(RecordKeeper &Records,
+ raw_ostream &OS) {
+ OS << "#if defined(CLANG_ATTR_STRING_LITERAL_ARG_LIST)\n";
+ std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
+ for (const auto *Attr : Attrs) {
+ std::vector<Record *> Args = Attr->getValueAsListOfDefs("Args");
+ uint32_t Bits = 0;
+ for (uint32_t N = 0; N < Args.size(); N++) {
+ Bits |= (isStringLiteralArgument(Args[N]) << N);
+ // If we have a variadic string argument, set all the remaining bits to 1
+ if (isVariadicStringLiteralArgument(Args[N])) {
+ for (; N < sizeof(uint32_t); N++)
+ Bits |= (1 << N);
+ break;
+ }
+ }
+ if (!Bits)
+ continue;
+ // All these spellings have at least one string literal has argument.
+ forEachUniqueSpelling(*Attr, [&](const FlattenedSpelling &S) {
+ OS << ".Case(\"" << S.name() << "\", " << Bits << ")\n";
+ });
+ }
+ OS << "#endif // CLANG_ATTR_STRING_LITERAL_ARG_LIST\n\n";
+}
+
// Emits the first-argument-is-identifier property for attributes.
static void emitClangAttrIdentifierArgList(RecordKeeper &Records, raw_ostream &OS) {
OS << "#if defined(CLANG_ATTR_IDENTIFIER_ARG_LIST)\n";
@@ -4615,6 +4659,7 @@
emitSourceFileHeader("Parser-related llvm::StringSwitch cases", OS);
emitClangAttrArgContextList(Records, OS);
emitClangAttrIdentifierArgList(Records, OS);
+ emitClangAttrUnevaluatedStringLiteralList(Records, OS);
emitClangAttrVariadicIdentifierArgList(Records, OS);
emitClangAttrThisIsaIdentifierArgList(Records, OS);
emitClangAttrAcceptsExprPack(Records, OS);
Index: clang/test/SemaTemplate/attributes.cpp
===================================================================
--- clang/test/SemaTemplate/attributes.cpp
+++ clang/test/SemaTemplate/attributes.cpp
@@ -25,7 +25,7 @@
{
__attribute__((aligned(Align))) char storage[Size];
};
-
+
template<typename T>
class C {
public:
@@ -95,11 +95,11 @@
template <int... Is> [[clang::annotate("ANNOTATE_BAZ", Is...)]] void HasPackAnnotations();
void UsePackAnnotations() { HasPackAnnotations<1, 2, 3>(); }
-template <int... Is> [[clang::annotate(Is...)]] void HasOnlyPackAnnotation() {} // expected-error {{'annotate' attribute takes at least 1 argument}} expected-error {{'annotate' attribute requires a string}}
+template <int... Is> [[clang::annotate(Is...)]] void HasOnlyPackAnnotation() {} // expected-error {{expected string literal as argument of 'annotate' attribute}}
void UseOnlyPackAnnotations() {
- HasOnlyPackAnnotation<>(); // expected-note {{in instantiation of function template specialization 'attribute_annotate::HasOnlyPackAnnotation<>' requested here}}
- HasOnlyPackAnnotation<1>(); // expected-note {{in instantiation of function template specialization 'attribute_annotate::HasOnlyPackAnnotation<1>' requested here}}
+ HasOnlyPackAnnotation<>();
+ HasOnlyPackAnnotation<1>();
}
// CHECK: ClassTemplateDecl {{.*}} AnnotatedPackTemplateStruct
@@ -276,40 +276,21 @@
// CHECK-NEXT: value: Int 6
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 6
// CHECK-NEXT: CXXRecordDecl {{.*}} implicit struct AnnotatedPackTemplateStruct
-// CHECK-NEXT: ClassTemplatePartialSpecializationDecl {{.*}} struct AnnotatedPackTemplateStruct definition
-// CHECK-NEXT: DefinitionData
-// CHECK-NEXT: DefaultConstructor
-// CHECK-NEXT: CopyConstructor
-// CHECK-NEXT: MoveConstructor
-// CHECK-NEXT: CopyAssignment
-// CHECK-NEXT: MoveAssignment
-// CHECK-NEXT: Destructor
-// CHECK-NEXT: TemplateArgument{{.*}} type 'char'
-// CHECK-NEXT: BuiltinType {{.*}} 'char'
-// CHECK-NEXT: TemplateArgument{{.*}} pack
-// CHECK-NEXT: TemplateArgument{{.*}} expr
-// CHECK-NEXT: PackExpansionExpr {{.*}} 'int'
-// CHECK-NEXT: DeclRefExpr {{.*}} 'int' NonTypeTemplateParm {{.*}} 'Is' 'int'
-// CHECK-NEXT: NonTypeTemplateParmDecl {{.*}} referenced 'int' depth 0 index 0 ... Is
-// CHECK-NEXT: AnnotateAttr {{.*}} ""
-// CHECK-NEXT: PackExpansionExpr {{.*}} '<dependent type>'
-// CHECK-NEXT: DeclRefExpr {{.*}} 'int' NonTypeTemplateParm {{.*}} 'Is' 'int'
-// CHECK-NEXT: CXXRecordDecl {{.*}} implicit struct AnnotatedPackTemplateStruct
template <typename T, int... Is> struct [[clang::annotate("ANNOTATE_FOZ", Is...)]] AnnotatedPackTemplateStruct{};
template <int... Is> struct [[clang::annotate("ANNOTATE_BOO", Is...)]] AnnotatedPackTemplateStruct<int, Is...>{};
template <int... Is> struct [[clang::annotate("ANNOTATE_FOZ", 4, 5, 6)]] AnnotatedPackTemplateStruct<float, Is...>{};
-template <int... Is> struct [[clang::annotate(Is...)]] AnnotatedPackTemplateStruct<char, Is...>{}; // expected-error {{'annotate' attribute requires a string}} expected-error {{'annotate' attribute takes at least 1 argument}}
+template <int... Is> struct [[clang::annotate(Is...)]] AnnotatedPackTemplateStruct<char, Is...>{}; // expected-error {{expected string literal as argument of 'annotate' attribute}}
void UseAnnotatedPackTemplateStructSpecializations() {
AnnotatedPackTemplateStruct<int, 1, 2, 3> Instance1{};
AnnotatedPackTemplateStruct<float, 3, 2, 1> Instance2{};
AnnotatedPackTemplateStruct<bool, 7, 8, 9> Instance3{};
- AnnotatedPackTemplateStruct<char, 1, 2, 3> Instance4{}; // expected-note {{in instantiation of template class 'attribute_annotate::AnnotatedPackTemplateStruct<char, 1, 2, 3>' requested here}}
- AnnotatedPackTemplateStruct<char> Instance5{}; // expected-note {{in instantiation of template class 'attribute_annotate::AnnotatedPackTemplateStruct<char>' requested here}}
+ AnnotatedPackTemplateStruct<char, 1, 2, 3> Instance4{};
+ AnnotatedPackTemplateStruct<char> Instance5{};
}
// CHECK: ClassTemplateDecl {{.*}} InvalidAnnotatedPackTemplateStruct
// CHECK-NEXT: TemplateTypeParmDecl {{.*}} typename depth 0 index 0 T
-// CHECK-NEXT: NonTypeTemplateParmDecl {{.*}} referenced 'int' depth 0 index 1 ... Is
+// CHECK-NEXT: NonTypeTemplateParmDecl {{.*}} 'int' depth 0 index 1 ... Is
// CHECK-NEXT: CXXRecordDecl {{.*}} struct InvalidAnnotatedPackTemplateStruct definition
// CHECK-NEXT: DefinitionData
// CHECK-NEXT: DefaultConstructor
@@ -318,9 +299,6 @@
// CHECK-NEXT: CopyAssignment
// CHECK-NEXT: MoveAssignment
// CHECK-NEXT: Destructor
-// CHECK-NEXT: AnnotateAttr {{.*}} ""
-// CHECK-NEXT: PackExpansionExpr {{.*}} '<dependent type>'
-// CHECK-NEXT: DeclRefExpr {{.*}} 'int' NonTypeTemplateParm {{.*}} 'Is' 'int'
// CHECK-NEXT: CXXRecordDecl {{.*}} implicit struct InvalidAnnotatedPackTemplateStruct
// CHECK-NEXT: ClassTemplateSpecialization {{.*}} 'InvalidAnnotatedPackTemplateStruct'
// CHECK-NEXT: ClassTemplateSpecializationDecl {{.*}} struct InvalidAnnotatedPackTemplateStruct definition
@@ -446,7 +424,7 @@
// CHECK-NEXT: TemplateArgument{{.*}} integral 6
// CHECK-NEXT: TemplateArgument{{.*}} integral 7
// CHECK-NEXT: CXXRecordDecl {{.*}} implicit struct InvalidAnnotatedPackTemplateStruct
-template <typename T, int... Is> struct [[clang::annotate(Is...)]] InvalidAnnotatedPackTemplateStruct{}; // expected-error {{'annotate' attribute requires a string}} expected-error {{'annotate' attribute takes at least 1 argument}}
+template <typename T, int... Is> struct InvalidAnnotatedPackTemplateStruct{};
template <int... Is> struct [[clang::annotate("ANNOTATE_BIR", Is...)]] InvalidAnnotatedPackTemplateStruct<int, Is...>{};
template <int... Is> struct InvalidAnnotatedPackTemplateStruct<float, Is...> {};
template <> struct InvalidAnnotatedPackTemplateStruct<char, 5, 6, 7> {};
@@ -454,8 +432,8 @@
InvalidAnnotatedPackTemplateStruct<int, 1, 2, 3> Instance1{};
InvalidAnnotatedPackTemplateStruct<float, 3, 2, 1> Instance2{};
InvalidAnnotatedPackTemplateStruct<char, 5, 6, 7> Instance3{};
- InvalidAnnotatedPackTemplateStruct<bool, 7, 8, 9> Instance4{}; // expected-note {{in instantiation of template class 'attribute_annotate::InvalidAnnotatedPackTemplateStruct<bool, 7, 8, 9>' requested here}}
- InvalidAnnotatedPackTemplateStruct<bool> Instance5{}; // expected-note {{in instantiation of template class 'attribute_annotate::InvalidAnnotatedPackTemplateStruct<bool>' requested here}}
+ InvalidAnnotatedPackTemplateStruct<bool, 7, 8, 9> Instance4{};
+ InvalidAnnotatedPackTemplateStruct<bool> Instance5{};
}
// CHECK: FunctionTemplateDecl {{.*}} RedeclaredAnnotatedFunc
Index: clang/test/SemaObjC/validate-attr-swift_attr.m
===================================================================
--- clang/test/SemaObjC/validate-attr-swift_attr.m
+++ clang/test/SemaObjC/validate-attr-swift_attr.m
@@ -5,7 +5,7 @@
@interface I
@end
-// expected-error@+1 {{'swift_attr' attribute requires a string}}
+// expected-error@+1 {{expected string literal as argument of 'swift_attr' attribute}}
__attribute__((swift_attr(1)))
@interface J
@end
Index: clang/test/SemaObjC/objc-asm-attribute-neg-test.m
===================================================================
--- clang/test/SemaObjC/objc-asm-attribute-neg-test.m
+++ clang/test/SemaObjC/objc-asm-attribute-neg-test.m
@@ -5,7 +5,7 @@
@interface BInterface
@end
-__attribute__((objc_runtime_name(123))) // expected-error {{'objc_runtime_name' attribute requires a string}}
+__attribute__((objc_runtime_name(123))) // expected-error {{expected string literal as argument of 'objc_runtime_name' attribute}}
@protocol BProtocol1
@end
@@ -14,7 +14,7 @@
@end
__attribute__((objc_runtime_name("MySecretNamespace.Message")))
-@interface Message <Protocol> {
+@interface Message <Protocol> {
__attribute__((objc_runtime_name("MySecretNamespace.Message"))) // expected-error {{'objc_runtime_name' attribute only applies to Objective-C interfaces and Objective-C protocols}}
id MyIVAR;
}
Index: clang/test/SemaObjC/attr-swift_bridge.m
===================================================================
--- clang/test/SemaObjC/attr-swift_bridge.m
+++ clang/test/SemaObjC/attr-swift_bridge.m
@@ -5,7 +5,7 @@
@interface I
@end
-// expected-error@+1 {{'__swift_bridge__' attribute requires a string}}
+// expected-error@+1 {{expected string literal as argument of '__swift_bridge__' attribute}}
__attribute__((__swift_bridge__(1)))
@interface J
@end
Index: clang/test/SemaCXX/suppress.cpp
===================================================================
--- clang/test/SemaCXX/suppress.cpp
+++ clang/test/SemaCXX/suppress.cpp
@@ -16,7 +16,7 @@
[[gsl::suppress]] int x; // expected-error {{'suppress' attribute takes at least 1 argument}}
[[gsl::suppress()]] int y; // expected-error {{'suppress' attribute takes at least 1 argument}}
int [[gsl::suppress("r")]] z; // expected-error {{'suppress' attribute cannot be applied to types}}
- [[gsl::suppress(f_)]] float f; // expected-error {{'suppress' attribute requires a string}}
+ [[gsl::suppress(f_)]] float f; // expected-error {{expected string literal as argument of 'suppress' attribut}}
}
union [[gsl::suppress("type.1")]] U {
Index: clang/test/SemaCXX/static-assert.cpp
===================================================================
--- clang/test/SemaCXX/static-assert.cpp
+++ clang/test/SemaCXX/static-assert.cpp
@@ -29,13 +29,23 @@
S<char> s1; // expected-note {{in instantiation of template class 'S<char>' requested here}}
S<int> s2;
-static_assert(false, L"\xFFFFFFFF"); // expected-error {{static assertion failed: L"\xFFFFFFFF"}}
-static_assert(false, u"\U000317FF"); // expected-error {{static assertion failed: u"\U000317FF"}}
-
-static_assert(false, u8"Ω"); // expected-error {{static assertion failed: u8"\316\251"}}
-static_assert(false, L"\u1234"); // expected-error {{static assertion failed: L"\x1234"}}
-static_assert(false, L"\x1ff" "0\x123" "fx\xfffff" "goop"); // expected-error {{static assertion failed: L"\x1FF""0\x123""fx\xFFFFFgoop"}}
-
+static_assert(false, L"\xFFFFFFFF"); // expected-error {{an unevaluated string literal cannot have an encoding prefix}} \
+ // expected-error {{invalid escape sequence '\xFFFFFFFF' in an unevaluated string literal}}
+static_assert(false, u"\U000317FF"); // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
+// FIXME: render this as u8"\u03A9"
+static_assert(false, u8"Ω"); // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
+static_assert(false, L"\u1234"); // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
+static_assert(false, L"\x1ff" // expected-error {{an unevaluated string literal cannot have an encoding prefix}} \
+ // expected-error {{invalid escape sequence '\x1ff' in an unevaluated string literal}}
+ "0\x123" // expected-error {{invalid escape sequence '\x123' in an unevaluated string literal}}
+ "fx\xfffff" // expected-error {{invalid escape sequence '\xfffff' in an unevaluated string literal}}
+ "goop");
+
+static_assert(false, "\'\"\?\\\a\b\f\n\r\t\v"); // expected-error {{'"?\<U+0007><U+0008>}}
+static_assert(true, "\xFF"); // expected-error {{invalid escape sequence '\xFF' in an unevaluated string literal}}
+static_assert(true, "\123"); // expected-error {{invalid escape sequence '\123' in an unevaluated string literal}}
+static_assert(true, "\pOh no, a Pascal string!"); // expected-warning {{unknown escape sequence '\p'}} \
+ // expected-error {{invalid escape sequence '\p' in an unevaluated string literal}}
static_assert(false, R"(a
\tb
c
Index: clang/test/SemaCXX/attr-weakref.cpp
===================================================================
--- clang/test/SemaCXX/attr-weakref.cpp
+++ clang/test/SemaCXX/attr-weakref.cpp
@@ -33,6 +33,6 @@
static int a10();
int a10() __attribute__((weakref ("foo")));
-static int v __attribute__((weakref(a1), alias("foo"))); // expected-error {{'weakref' attribute requires a string}}
+static int v __attribute__((weakref(a1), alias("foo"))); // expected-error {{expected string literal as argument of 'weakref' attribute}}
__attribute__((weakref ("foo"))) auto a11 = 1; // expected-error {{weakref declaration must have internal linkage}}
Index: clang/test/SemaCXX/attr-section.cpp
===================================================================
--- clang/test/SemaCXX/attr-section.cpp
+++ clang/test/SemaCXX/attr-section.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -verify -fsyntax-only -triple x86_64-linux-gnu %s
int x __attribute__((section(
- 42))); // expected-error {{'section' attribute requires a string}}
+ 42))); // expected-error {{expected string literal as argument of 'section' attribute}}
// PR6007
Index: clang/test/SemaCXX/attr-no-sanitize.cpp
===================================================================
--- clang/test/SemaCXX/attr-no-sanitize.cpp
+++ clang/test/SemaCXX/attr-no-sanitize.cpp
@@ -4,7 +4,7 @@
int f1() __attribute__((no_sanitize)); // expected-error{{'no_sanitize' attribute takes at least 1 argument}}
-int f2() __attribute__((no_sanitize(1))); // expected-error{{'no_sanitize' attribute requires a string}}
+int f2() __attribute__((no_sanitize(1))); // expected-error{{expected string literal as argument of 'no_sanitize' attribute}}
__attribute__((no_sanitize("all"))) int global; // expected-warning{{'no_sanitize' attribute argument 'all' not supported on a global variable}}
__attribute__((no_sanitize("unknown"))) int global2; // expected-warning{{unknown sanitizer 'unknown' ignored}}
Index: clang/test/SemaCXX/attr-deprecated-replacement-error.cpp
===================================================================
--- clang/test/SemaCXX/attr-deprecated-replacement-error.cpp
+++ clang/test/SemaCXX/attr-deprecated-replacement-error.cpp
@@ -5,13 +5,13 @@
#endif
int a1 [[deprecated("warning", "fixit")]]; // expected-error{{'deprecated' attribute takes no more than 1 argument}}
-int a2 [[deprecated("warning", 1)]]; // expected-error{{'deprecated' attribute takes no more than 1 argument}}
+int a2 [[deprecated("warning", 1)]]; // expected-error{{expected string literal as argument of 'deprecated' attribute}}
int b1 [[gnu::deprecated("warning", "fixit")]]; // expected-error{{'deprecated' attribute takes no more than 1 argument}}
-int b2 [[gnu::deprecated("warning", 1)]]; // expected-error{{'deprecated' attribute takes no more than 1 argument}}
+int b2 [[gnu::deprecated("warning", 1)]]; // expected-error{{expected string literal as argument of 'deprecated' attribute}}
__declspec(deprecated("warning", "fixit")) int c1; // expected-error{{'deprecated' attribute takes no more than 1 argument}}
-__declspec(deprecated("warning", 1)) int c2; // expected-error{{'deprecated' attribute takes no more than 1 argument}}
+__declspec(deprecated("warning", 1)) int c2; // expected-error{{expected string literal as argument of 'deprecated' attribute}}
int d1 __attribute__((deprecated("warning", "fixit")));
-int d2 __attribute__((deprecated("warning", 1))); // expected-error{{'deprecated' attribute requires a string}}
+int d2 __attribute__((deprecated("warning", 1))); // expected-error{{expected string literal as argument of 'deprecated' attribute}}
Index: clang/test/Sema/enable_if.c
===================================================================
--- clang/test/Sema/enable_if.c
+++ clang/test/Sema/enable_if.c
@@ -105,7 +105,7 @@
int n __attribute__((enable_if(1, "always chosen"))); // expected-warning{{'enable_if' attribute only applies to functions}}
-void f(int n) __attribute__((enable_if("chosen when 'n' is zero", n == 0))); // expected-error{{'enable_if' attribute requires a string}}
+void f(int n) __attribute__((enable_if("chosen when 'n' is zero", n == 0))); // expected-error{{expected string literal as argument of 'enable_if' attribute}}
void f(int n) __attribute__((enable_if())); // expected-error{{'enable_if' attribute requires exactly 2 arguments}}
Index: clang/test/Sema/diagnose_if.c
===================================================================
--- clang/test/Sema/diagnose_if.c
+++ clang/test/Sema/diagnose_if.c
@@ -6,7 +6,7 @@
void failure2(void) _diagnose_if(0); // expected-error{{exactly 3 arguments}}
void failure3(void) _diagnose_if(0, ""); // expected-error{{exactly 3 arguments}}
void failure4(void) _diagnose_if(0, "", "error", 1); // expected-error{{exactly 3 arguments}}
-void failure5(void) _diagnose_if(0, 0, "error"); // expected-error{{requires a string}}
+void failure5(void) _diagnose_if(0, 0, "error"); // expected-error{{expected string literal as argument of 'diagnose_if' attribute}}
void failure6(void) _diagnose_if(0, "", "invalid"); // expected-error{{invalid diagnostic type for 'diagnose_if'; use "error" or "warning" instead}}
void failure7(void) _diagnose_if(0, "", "ERROR"); // expected-error{{invalid diagnostic type}}
void failure8(int a) _diagnose_if(a, "", ""); // expected-error{{invalid diagnostic type}}
Index: clang/test/Sema/attr-warning.c
===================================================================
--- clang/test/Sema/attr-warning.c
+++ clang/test/Sema/attr-warning.c
@@ -15,7 +15,7 @@
__attribute__((warning("bad2"))); // expected-error {{'warning' attribute cannot be applied to a statement}}
}
-__attribute__((warning(3))) // expected-error {{'warning' attribute requires a string}}
+__attribute__((warning(3))) // expected-error {{expected string literal as argument of 'warning' attribute}}
int
bad3(void);
Index: clang/test/Sema/attr-unavailable-message.c
===================================================================
--- clang/test/Sema/attr-unavailable-message.c
+++ clang/test/Sema/attr-unavailable-message.c
@@ -8,7 +8,7 @@
void bar(void) __attribute__((__unavailable__)); // expected-note {{explicitly marked unavailable}}
-int quux(void) __attribute__((__unavailable__(12))); // expected-error {{'__unavailable__' attribute requires a string}}
+int quux(void) __attribute__((__unavailable__(12))); // expected-error {{expected string literal as argument of '__unavailable__' attribute}}
#define ACCEPTABLE "Use something else"
int quux2(void) __attribute__((__unavailable__(ACCEPTABLE)));
Index: clang/test/Sema/attr-tls_model.c
===================================================================
--- clang/test/Sema/attr-tls_model.c
+++ clang/test/Sema/attr-tls_model.c
@@ -10,5 +10,5 @@
static __thread int y __attribute((tls_model("global-dynamic"))); // no-warning
static __thread int y __attribute((tls_model("local", "dynamic"))); // expected-error {{'tls_model' attribute takes one argument}}
-static __thread int y __attribute((tls_model(123))); // expected-error {{'tls_model' attribute requires a string}}
+static __thread int y __attribute((tls_model(123))); // expected-error {{expected string literal as argument of 'tls_model' attribute}}
static __thread int y __attribute((tls_model("foobar"))); // expected-error {{tls_model must be "global-dynamic", "local-dynamic", "initial-exec" or "local-exec"}}
Index: clang/test/Sema/attr-section.c
===================================================================
--- clang/test/Sema/attr-section.c
+++ clang/test/Sema/attr-section.c
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -verify -fsyntax-only -triple x86_64-apple-darwin9 %s
int x __attribute__((section(
- 42))); // expected-error {{'section' attribute requires a string}}
+ 42))); // expected-error {{expected string literal as argument of 'section' attribute}}
// rdar://4341926
Index: clang/test/Sema/attr-handles.cpp
===================================================================
--- clang/test/Sema/attr-handles.cpp
+++ clang/test/Sema/attr-handles.cpp
@@ -6,7 +6,7 @@
auto lambda = [](int handle [[clang::use_handle("Fuchsia")]]){};
void g(int a __attribute__((acquire_handle("Fuchsia")))); // expected-error {{attribute only applies to output parameters}}
void h(int *a __attribute__((acquire_handle))); // expected-error {{'acquire_handle' attribute takes one argument}}
-void h(int *a __attribute__((acquire_handle(1)))); // expected-error {{attribute requires a string}}
+void h(int *a __attribute__((acquire_handle(1)))); // expected-error {{expected string literal as argument of 'acquire_handle' attribute}}
void h(int *a __attribute__((acquire_handle("RandomString", "AndAnother")))); // expected-error {{'acquire_handle' attribute takes one argument}}
__attribute__((release_handle("Fuchsia"))) int i(); // expected-warning {{'release_handle' attribute only applies to parameters}}
__attribute__((use_handle("Fuchsia"))) int j(); // expected-warning {{'use_handle' attribute only applies to parameters}}
Index: clang/test/Sema/attr-error.c
===================================================================
--- clang/test/Sema/attr-error.c
+++ clang/test/Sema/attr-error.c
@@ -15,7 +15,7 @@
__attribute__((error("bad2"))); // expected-error {{'error' attribute cannot be applied to a statement}}
}
-__attribute__((error(3))) // expected-error {{'error' attribute requires a string}}
+__attribute__((error(3))) // expected-error {{expected string literal as argument of 'error' attribute}}
int
bad3(void);
Index: clang/test/Sema/attr-enforce-tcb-errors.m
===================================================================
--- clang/test/Sema/attr-enforce-tcb-errors.m
+++ clang/test/Sema/attr-enforce-tcb-errors.m
@@ -20,13 +20,13 @@
- (void)tooManyArguments __attribute__((enforce_tcb("test", 12))); // expected-error{{'enforce_tcb' attribute takes one argument}}
-- (void)wrongArgumentType __attribute__((enforce_tcb(12))); // expected-error{{'enforce_tcb' attribute requires a string}}
+- (void)wrongArgumentType __attribute__((enforce_tcb(12))); // expected-error{{expected string literal as argument of 'enforce_tcb' attribute}}
- (void)noArgumentsLeaf __attribute__((enforce_tcb_leaf)); // expected-error{{'enforce_tcb_leaf' attribute takes one argument}}
- (void)tooManyArgumentsLeaf __attribute__((enforce_tcb_leaf("test", 12))); // expected-error{{'enforce_tcb_leaf' attribute takes one argument}}
-- (void)wrongArgumentTypeLeaf __attribute__((enforce_tcb_leaf(12))); // expected-error{{'enforce_tcb_leaf' attribute requires a string}}
+- (void)wrongArgumentTypeLeaf __attribute__((enforce_tcb_leaf(12))); // expected-error{{expected string literal as argument of 'enforce_tcb_leaf' attribute}}
@end
@implementation AClass
Index: clang/test/Sema/attr-enforce-tcb-errors.cpp
===================================================================
--- clang/test/Sema/attr-enforce-tcb-errors.cpp
+++ clang/test/Sema/attr-enforce-tcb-errors.cpp
@@ -6,14 +6,14 @@
void too_many_arguments() __attribute__((enforce_tcb("test", 12))); // expected-error{{'enforce_tcb' attribute takes one argument}}
-void wrong_argument_type() __attribute__((enforce_tcb(12))); // expected-error{{'enforce_tcb' attribute requires a string}}
+void wrong_argument_type() __attribute__((enforce_tcb(12))); // expected-error{{expected string literal as argument of 'enforce_tcb' attribute}}
[[clang::enforce_tcb_leaf("oops")]] int wrong_subject_type_leaf; // expected-warning{{'enforce_tcb_leaf' attribute only applies to functions}}
void no_arguments_leaf() __attribute__((enforce_tcb_leaf)); // expected-error{{'enforce_tcb_leaf' attribute takes one argument}}
void too_many_arguments_leaf() __attribute__((enforce_tcb_leaf("test", 12))); // expected-error{{'enforce_tcb_leaf' attribute takes one argument}}
-void wrong_argument_type_leaf() __attribute__((enforce_tcb_leaf(12))); // expected-error{{'enforce_tcb_leaf' attribute requires a string}}
+void wrong_argument_type_leaf() __attribute__((enforce_tcb_leaf(12))); // expected-error{{expected string literal as argument of 'enforce_tcb_leaf' attribute}}
void foo();
Index: clang/test/Sema/attr-capabilities.c
===================================================================
--- clang/test/Sema/attr-capabilities.c
+++ clang/test/Sema/attr-capabilities.c
@@ -17,8 +17,8 @@
int Test4 __attribute__((try_acquire_capability("test4"))); // expected-error {{'try_acquire_capability' attribute only applies to functions}}
int Test5 __attribute__((release_capability("test5"))); // expected-warning {{'release_capability' attribute only applies to functions}}
-struct __attribute__((capability(12))) Test3 {}; // expected-error {{'capability' attribute requires a string}}
-struct __attribute__((shared_capability(Test2))) Test4 {}; // expected-error {{'shared_capability' attribute requires a string}}
+struct __attribute__((capability(12))) Test3 {}; // expected-error {{expected string literal as argument of 'capability' attribute}}
+struct __attribute__((shared_capability(Test2))) Test4 {}; // expected-error {{expected string literal as argument of 'shared_capability' attribute}}
struct __attribute__((capability)) Test5 {}; // expected-error {{'capability' attribute takes one argument}}
struct __attribute__((shared_capability("test1", 12))) Test6 {}; // expected-error {{'shared_capability' attribute takes one argument}}
Index: clang/test/Sema/attr-btf_type_tag.c
===================================================================
--- clang/test/Sema/attr-btf_type_tag.c
+++ clang/test/Sema/attr-btf_type_tag.c
@@ -8,7 +8,7 @@
#define __tag6 __attribute__((btf_type_tag("tag6")))
int __attribute__((btf_type_tag("tag1", "tag2"))) *invalid1; // expected-error {{'btf_type_tag' attribute takes one argument}}
-int __attribute__((btf_type_tag(2))) *invalid2; // expected-error {{'btf_type_tag' attribute requires a string}}
+int __attribute__((btf_type_tag(2))) *invalid2; // expected-error {{expected string literal as argument of 'btf_type_tag' attribute}}
int * __tag1 __tag2 * __tag3 __tag4 * __tag5 __tag6 *g;
Index: clang/test/Sema/attr-btf_tag.c
===================================================================
--- clang/test/Sema/attr-btf_tag.c
+++ clang/test/Sema/attr-btf_tag.c
@@ -21,7 +21,7 @@
int g1 __tag1;
int g2 __tag_no_arg; // expected-error {{'btf_decl_tag' attribute takes one argument}}
int g3 __tag_2_arg; // expected-error {{'btf_decl_tag' attribute takes one argument}}
-int i1 __invalid; // expected-error {{'btf_decl_tag' attribute requires a string}}
+int i1 __invalid; // expected-error {{expected string literal as argument of 'btf_decl_tag' attribute}}
enum e1 {
E1
Index: clang/test/Sema/attr-assume.c
===================================================================
--- clang/test/Sema/attr-assume.c
+++ clang/test/Sema/attr-assume.c
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
-void f1(void) __attribute__((assume(3))); // expected-error {{'assume' attribute requires a string}}
-void f2(void) __attribute__((assume(int))); // expected-error {{expected expression}}
-void f3(void) __attribute__((assume(for))); // expected-error {{expected expression}}
+void f1(void) __attribute__((assume(3))); // expected-error {{expected string literal as argument of 'assume' attribute}}
+void f2(void) __attribute__((assume(int))); // expected-error {{expected string literal as argument of 'assume' attribute}}
+void f3(void) __attribute__((assume(for))); // expected-error {{expected string literal as argument of 'assume' attribute}}
void f4(void) __attribute__((assume("QQQQ"))); // expected-warning {{unknown assumption string 'QQQQ'; attribute is potentially ignored}}
void f5(void) __attribute__((assume("omp_no_openmp")));
void f6(void) __attribute__((assume("omp_noopenmp"))); // expected-warning {{unknown assumption string 'omp_noopenmp' may be misspelled; attribute is potentially ignored, did you mean 'omp_no_openmp'?}}
@@ -10,5 +10,5 @@
void f8(void) __attribute__((assume("omp_no_openmp1"))); // expected-warning {{unknown assumption string 'omp_no_openmp1' may be misspelled; attribute is potentially ignored, did you mean 'omp_no_openmp'?}}
void f9(void) __attribute__((assume("omp_no_openmp", "omp_no_openmp"))); // expected-error {{'assume' attribute takes one argument}}
-int g1 __attribute__((assume(0))); // expected-warning {{'assume' attribute only applies to functions and Objective-C methods}}
+int g1 __attribute__((assume(0))); // expected-error {{expected string literal as argument of 'assume' attribute}}
int g2 __attribute__((assume("omp_no_openmp"))); // expected-warning {{'assume' attribute only applies to functions and Objective-C methods}}
Index: clang/test/Sema/annotate.c
===================================================================
--- clang/test/Sema/annotate.c
+++ clang/test/Sema/annotate.c
@@ -3,8 +3,8 @@
void __attribute__((annotate("foo"))) foo(float *a) {
__attribute__((annotate("bar"))) int x;
[[clang::annotate("bar")]] int x2;
- __attribute__((annotate(1))) int y; // expected-error {{'annotate' attribute requires a string}}
- [[clang::annotate(1)]] int y2; // expected-error {{'annotate' attribute requires a string}}
+ __attribute__((annotate(1))) int y; // expected-error {{expected string literal as argument of 'annotate' attribute}}
+ [[clang::annotate(1)]] int y2; // expected-error {{expected string literal as argument of 'annotate' attribute}}
__attribute__((annotate("bar", 1))) int z;
[[clang::annotate("bar", 1)]] int z2;
Index: clang/test/Sema/annotate-type.c
===================================================================
--- clang/test/Sema/annotate-type.c
+++ clang/test/Sema/annotate-type.c
@@ -20,10 +20,10 @@
[[clang::annotate_type("bar")]] int *z1; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
int *z2 [[clang::annotate_type("bar")]]; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
[[clang::annotate_type("bar")]]; // expected-error {{'annotate_type' attribute cannot be applied to a statement}}
- int *[[clang::annotate_type(1)]] z3; // expected-error {{'annotate_type' attribute requires a string}}
+ int *[[clang::annotate_type(1)]] z3; // expected-error {{expected string literal as argument of 'annotate_type' attribute}}
int *[[clang::annotate_type()]] z4; // expected-error {{'annotate_type' attribute takes at least 1 argument}}
int *[[clang::annotate_type]] z5; // expected-error {{'annotate_type' attribute takes at least 1 argument}}
- int *[[clang::annotate_type(some_function())]] z6; // expected-error {{'annotate_type' attribute requires a string}}
+ int *[[clang::annotate_type(some_function())]] z6; // expected-error {{expected string literal as argument of 'annotate_type' attribute}}
int *[[clang::annotate_type("bar", some_function())]] z7; // expected-error {{'annotate_type' attribute requires parameter 1 to be a constant expression}} expected-note{{subexpression not valid in a constant expression}}
int *[[clang::annotate_type("bar", z7)]] z8; // expected-error {{'annotate_type' attribute requires parameter 1 to be a constant expression}} expected-note{{subexpression not valid in a constant expression}}
int *[[clang::annotate_type("bar", int)]] z9; // expected-error {{expected expression}}
Index: clang/test/Sema/MicrosoftExtensions.c
===================================================================
--- clang/test/Sema/MicrosoftExtensions.c
+++ clang/test/Sema/MicrosoftExtensions.c
@@ -123,7 +123,7 @@
#define MY_TEXT "This is also deprecated"
__declspec(deprecated(MY_TEXT)) void Dfunc1( void ) {} // expected-note {{'Dfunc1' has been explicitly marked deprecated here}}
-struct __declspec(deprecated(123)) DS2 {}; // expected-error {{'deprecated' attribute requires a string}}
+struct __declspec(deprecated(123)) DS2 {}; // expected-error {{expected string literal as argument of 'deprecated' attribute}}
void test( void ) {
e1 = one; // expected-warning {{'e1' is deprecated: This is deprecated}}
Index: clang/test/Parser/cxx0x-attributes.cpp
===================================================================
--- clang/test/Parser/cxx0x-attributes.cpp
+++ clang/test/Parser/cxx0x-attributes.cpp
@@ -94,7 +94,7 @@
[[]] [[]] alignas(16) [[]]{}; // expected-error {{an attribute list cannot appear here}}
// The diagnostics here don't matter much, this just shouldn't crash:
-class C final [[deprecated(l]] {}); // expected-error {{use of undeclared identifier}} expected-error {{expected ']'}} expected-error {{an attribute list cannot appear here}} expected-error {{expected unqualified-id}}
+class C final [[deprecated(l]] {}); //expected-error {{expected string literal as argument of 'deprecated' attribute}} expected-error {{an attribute list cannot appear here}} expected-error {{expected unqualified-id}}
class D final alignas ([l) {}]{}); // expected-error {{expected ',' or ']' in lambda capture list}} expected-error {{an attribute list cannot appear here}}
[[]] struct with_init_declarators {} init_declarator;
@@ -266,7 +266,7 @@
template <int... Is> void variadic_nttp() {
void bar [[noreturn...]] (); // expected-error {{attribute 'noreturn' cannot be used as an attribute pack}}
- void baz [[clang::no_sanitize(Is...)]] (); // expected-error {{attribute 'no_sanitize' does not support argument pack expansion}}
+ void baz [[clang::no_sanitize(Is...)]] (); // expected-error {{expected string literal as argument of 'no_sanitize' attribute}}
void bor [[clang::annotate("A", "V" ...)]] (); // expected-error {{pack expansion does not contain any unexpanded parameter packs}}
void bir [[clang::annotate("B", {1, 2, 3, 4})]] (); // expected-error {{'annotate' attribute requires parameter 1 to be a constant expression}} expected-note {{subexpression not valid in a constant expression}}
void boo [[unknown::foo(Is...)]] (); // expected-warning {{unknown attribute 'foo' ignored}}
@@ -445,3 +445,8 @@
) {
}
};
+
+namespace P2361 {
+[[deprecated(L"abc")]] void a(); // expected-error{{an unevaluated string literal cannot have an encoding prefix}}
+[[nodiscard("\123")]] int b(); // expected-error{{invalid escape sequence '\123' in an unevaluated string literal}}
+}
Index: clang/test/Parser/cxx-attributes.cpp
===================================================================
--- clang/test/Parser/cxx-attributes.cpp
+++ clang/test/Parser/cxx-attributes.cpp
@@ -41,7 +41,7 @@
pi = &i[0];
}
-[[deprecated([""])]] int WrongArgs; // expected-error {{expected variable name or 'this' in lambda capture list}}
+[[deprecated([""])]] int WrongArgs; // expected-error {{expected string literal as argument of 'deprecated' attribute}}
[[,,,,,]] int Commas1; // ok
[[,, maybe_unused]] int Commas2; // ok
[[maybe_unused,,,]] int Commas3; // ok
Index: clang/test/Parser/c2x-attributes.c
===================================================================
--- clang/test/Parser/c2x-attributes.c
+++ clang/test/Parser/c2x-attributes.c
@@ -16,7 +16,7 @@
// FIXME: this diagnostic can be improved.
enum E3 [[]] { Seven }; // expected-error {{expected identifier or '('}}
-[[deprecated([""])]] int WrongArgs; // expected-error {{expected expression}}
+[[deprecated([""])]] int WrongArgs; // expected-error {{expected string literal as argument of 'deprecated' attribute}}
[[,,,,,]] int Commas1; // ok
[[,, maybe_unused]] int Commas2; // ok
[[maybe_unused,,,]] int Commas3; // ok
Index: clang/test/Parser/MicrosoftExtensions.cpp
===================================================================
--- clang/test/Parser/MicrosoftExtensions.cpp
+++ clang/test/Parser/MicrosoftExtensions.cpp
@@ -44,8 +44,8 @@
unsigned char Data4[8];
} GUID;
-struct __declspec(uuid(L"00000000-0000-0000-1234-000000000047")) uuid_attr_bad1 { };// expected-error {{'uuid' attribute requires a string}}
-struct __declspec(uuid(3)) uuid_attr_bad2 { };// expected-error {{'uuid' attribute requires a string}}
+struct __declspec(uuid(L"00000000-0000-0000-1234-000000000047")) uuid_attr_bad1 { };// expected-error {{an unevaluated string literal cannot have an encoding prefix}}
+struct __declspec(uuid(3)) uuid_attr_bad2 { };// expected-error {{expected string literal as argument of 'uuid' attribute}}
struct __declspec(uuid("0000000-0000-0000-1234-0000500000047")) uuid_attr_bad3 { };// expected-error {{uuid attribute contains a malformed GUID}}
struct __declspec(uuid("0000000-0000-0000-Z234-000000000047")) uuid_attr_bad4 { };// expected-error {{uuid attribute contains a malformed GUID}}
struct __declspec(uuid("000000000000-0000-1234-000000000047")) uuid_attr_bad5 { };// expected-error {{uuid attribute contains a malformed GUID}}
Index: clang/test/FixIt/fixit-static-assert.cpp
===================================================================
--- clang/test/FixIt/fixit-static-assert.cpp
+++ clang/test/FixIt/fixit-static-assert.cpp
@@ -11,8 +11,6 @@
// String literal prefixes are good.
static_assert(true && R"(RawString)");
// CHECK-DAG: {[[@LINE-1]]:20-[[@LINE-1]]:22}:","
-static_assert(true && L"RawString");
-// CHECK-DAG: {[[@LINE-1]]:20-[[@LINE-1]]:22}:","
static_assert(true);
// CHECK-DAG: {[[@LINE-1]]:19-[[@LINE-1]]:19}:", \"\""
Index: clang/test/CXX/dcl.dcl/p4-0x.cpp
===================================================================
--- clang/test/CXX/dcl.dcl/p4-0x.cpp
+++ clang/test/CXX/dcl.dcl/p4-0x.cpp
@@ -18,4 +18,7 @@
static_assert(T(), "");
static_assert(U(), ""); // expected-error {{ambiguous}}
-static_assert(false, L"\x14hi" "!" R"x(")x"); // expected-error {{static assertion failed: L"\024hi!\""}}
+static_assert(false, L"\x14hi" // expected-error {{an unevaluated string literal cannot have an encoding prefix}} \
+ // expected-error {{invalid escape sequence '\x14' in an unevaluated string literal}}
+ "!"
+ R"x(")x");
Index: clang/test/CXX/dcl.dcl/dcl.link/p2.cpp
===================================================================
--- clang/test/CXX/dcl.dcl/dcl.link/p2.cpp
+++ clang/test/CXX/dcl.dcl/dcl.link/p2.cpp
@@ -8,7 +8,7 @@
extern "C" plusplus {
}
-extern u8"C" {} // expected-error {{string literal in language linkage specifier cannot have an encoding-prefix}}
-extern L"C" {} // expected-error {{string literal in language linkage specifier cannot have an encoding-prefix}}
-extern u"C++" {} // expected-error {{string literal in language linkage specifier cannot have an encoding-prefix}}
-extern U"C" {} // expected-error {{string literal in language linkage specifier cannot have an encoding-prefix}}
+extern u8"C" {} // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
+extern L"C" {} // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
+extern u"C++" {} // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
+extern U"C" {} // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
Index: clang/lib/Sema/SemaInit.cpp
===================================================================
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -140,6 +140,9 @@
if (IsWideCharCompatible(ElemTy, Context))
return SIF_IncompatWideStringIntoWideChar;
return SIF_Other;
+ case StringLiteral::Unevaluated:
+ assert(false && "Unevaluated string literal in initialization");
+ break;
}
llvm_unreachable("missed a StringLiteral kind?");
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -4086,6 +4086,9 @@
case StringLiteral::Wide:
return Context.typesAreCompatible(Context.getWideCharType(),
QualType(ToPointeeType, 0));
+ case StringLiteral::Unevaluated:
+ assert(false && "Unevaluated string literal in expression");
+ break;
}
}
}
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -1911,6 +1911,30 @@
return S.BuildLiteralOperatorCall(R, OpNameInfo, Args, LitEndLoc);
}
+ExprResult Sema::ActOnUnevaluatedStringLiteral(ArrayRef<Token> StringToks) {
+ StringLiteralParser Literal(StringToks, PP,
+ StringLiteralEvalMethod::Unevaluated);
+ if (Literal.hadError)
+ return ExprError();
+
+ SmallVector<SourceLocation, 4> StringTokLocs;
+ for (const Token &Tok : StringToks)
+ StringTokLocs.push_back(Tok.getLocation());
+
+ StringLiteral *Lit = StringLiteral::Create(
+ Context, Literal.GetString(), StringLiteral::Unevaluated, false, {},
+ &StringTokLocs[0], StringTokLocs.size());
+
+ if (!Literal.getUDSuffix().empty()) {
+ SourceLocation UDSuffixLoc =
+ getUDSuffixLoc(*this, StringTokLocs[Literal.getUDSuffixToken()],
+ Literal.getUDSuffixOffset());
+ return ExprError(Diag(UDSuffixLoc, diag::err_invalid_string_udl));
+ }
+
+ return Lit;
+}
+
/// ActOnStringLiteral - The specified tokens were lexed as pasted string
/// fragments (e.g. "foo" "bar" L"baz"). The result string has to handle string
/// concatenation ([C99 5.1.1.2, translation phase #6]), so it may come from
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -16467,11 +16467,7 @@
Expr *LangStr,
SourceLocation LBraceLoc) {
StringLiteral *Lit = cast<StringLiteral>(LangStr);
- if (!Lit->isOrdinary()) {
- Diag(LangStr->getExprLoc(), diag::err_language_linkage_spec_not_ascii)
- << LangStr->getSourceRange();
- return nullptr;
- }
+ assert(Lit->isUnevaluated() && "Unexpected string literal kind");
StringRef Lang = Lit->getString();
LinkageSpecDecl::LanguageIDs Language;
@@ -16936,10 +16932,7 @@
llvm::raw_svector_ostream Msg(MsgBuffer);
if (AssertMessage) {
const auto *MsgStr = cast<StringLiteral>(AssertMessage);
- if (MsgStr->isOrdinary())
- Msg << MsgStr->getString();
- else
- MsgStr->printPretty(Msg, nullptr, getPrintingPolicy());
+ Msg << MsgStr->getString();
}
Expr *InnerCond = nullptr;
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -349,7 +349,7 @@
if (ArgLocation)
*ArgLocation = E->getBeginLoc();
- if (!Literal || !Literal->isOrdinary()) {
+ if (!Literal || (!Literal->isUnevaluated() && !Literal->isOrdinary())) {
Diag(E->getBeginLoc(), diag::err_attribute_argument_type)
<< CI << AANT_ArgumentString;
return false;
@@ -381,6 +381,16 @@
// Now check for an actual string literal.
Expr *ArgExpr = AL.getArgAsExpr(ArgNum);
+ const auto *Literal = dyn_cast<StringLiteral>(ArgExpr->IgnoreParenCasts());
+ if (ArgLocation)
+ *ArgLocation = ArgExpr->getBeginLoc();
+
+ if (!Literal || (!Literal->isUnevaluated() && !Literal->isOrdinary())) {
+ Diag(ArgExpr->getBeginLoc(), diag::err_attribute_argument_type)
+ << AL << AANT_ArgumentString;
+ return false;
+ }
+ Str = Literal->getString();
return checkStringLiteralArgumentAttr(AL, ArgExpr, Str, ArgLocation);
}
@@ -865,7 +875,8 @@
if (!AL.checkAtLeastNumArgs(S, 1))
return false;
- if (!isIntOrBool(AL.getArgAsExpr(0))) {
+ Expr *First = AL.getArgAsExpr(0);
+ if (!isIntOrBool(First)) {
S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
<< AL << 1 << AANT_ArgumentIntOrBool;
return false;
Index: clang/lib/Parse/ParseExpr.cpp
===================================================================
--- clang/lib/Parse/ParseExpr.cpp
+++ clang/lib/Parse/ParseExpr.cpp
@@ -3256,6 +3256,17 @@
/// string-literal
/// \verbatim
ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral) {
+ return ParseStringLiteralExpression(AllowUserDefinedLiteral,
+ /*Unevaluated=*/false);
+}
+
+ExprResult Parser::ParseUnevaluatedStringLiteralExpression() {
+ return ParseStringLiteralExpression(/*AllowUserDefinedLiteral=*/false,
+ /*Unevaluated=*/true);
+}
+
+ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral,
+ bool Unevaluated) {
assert(isTokenStringLiteral() && "Not a string literal!");
// String concat. Note that keywords like __func__ and __FUNCTION__ are not
@@ -3267,6 +3278,11 @@
ConsumeStringToken();
} while (isTokenStringLiteral());
+ if (Unevaluated) {
+ assert(!AllowUserDefinedLiteral && "UDL are always evaluated");
+ return Actions.ActOnUnevaluatedStringLiteral(StringToks);
+ }
+
// Pass the set of string tokens, ready for concatenation, to the actions.
return Actions.ActOnStringLiteral(StringToks,
AllowUserDefinedLiteral ? getCurScope()
@@ -3478,9 +3494,9 @@
if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
Expr = ParseBraceInitializer();
- } else
+ } else {
Expr = ParseAssignmentExpression();
-
+ }
if (EarlyTypoCorrection)
Expr = Actions.CorrectDelayedTyposInExpr(Expr);
Index: clang/lib/Parse/ParseDeclCXX.cpp
===================================================================
--- clang/lib/Parse/ParseDeclCXX.cpp
+++ clang/lib/Parse/ParseDeclCXX.cpp
@@ -350,7 +350,7 @@
///
Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context) {
assert(isTokenStringLiteral() && "Not a string literal!");
- ExprResult Lang = ParseStringLiteralExpression(false);
+ ExprResult Lang = ParseUnevaluatedStringLiteralExpression();
ParseScope LinkageScope(this, Scope::DeclScope);
Decl *LinkageSpec =
@@ -1023,7 +1023,7 @@
return nullptr;
}
- AssertMessage = ParseStringLiteralExpression();
+ AssertMessage = ParseUnevaluatedStringLiteralExpression();
if (AssertMessage.isInvalid()) {
SkipMalformedDecl();
return nullptr;
Index: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -288,6 +288,16 @@
#undef CLANG_ATTR_IDENTIFIER_ARG_LIST
}
+/// Determine whether the given attribute has an identifier argument.
+static ParsedAttributeArgumentsProperties
+attributeStringLiteralListArg(const IdentifierInfo &II) {
+#define CLANG_ATTR_STRING_LITERAL_ARG_LIST
+ return llvm::StringSwitch<uint32_t>(normalizeAttrName(II.getName()))
+#include "clang/Parse/AttrParserStringSwitches.inc"
+ .Default(0);
+#undef CLANG_ATTR_STRING_LITERAL_ARG_LIST
+}
+
/// Determine whether the given attribute has a variadic identifier argument.
static bool attributeHasVariadicIdentifierArg(const IdentifierInfo &II) {
#define CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST
@@ -371,6 +381,79 @@
ScopeName, ScopeLoc, nullptr, 0, Form);
}
+ExprResult
+Parser::ParseUnevaluatedStringInAttribute(const IdentifierInfo &AttrName) {
+ if (Tok.is(tok::l_paren)) {
+ BalancedDelimiterTracker Paren(*this, tok::l_paren);
+ Paren.consumeOpen();
+ ExprResult Res = ParseUnevaluatedStringInAttribute(AttrName);
+ Paren.consumeClose();
+ return Res;
+ }
+ if (!isTokenStringLiteral()) {
+ Diag(Tok.getLocation(), diag::err_expected_string_literal)
+ << /*in attribute...*/ 4 << AttrName.getName();
+ return ExprError();
+ }
+ return ParseUnevaluatedStringLiteralExpression();
+}
+
+bool Parser::ParseAttributeArgumentList(
+ const IdentifierInfo &AttrName, SmallVectorImpl<Expr *> &Exprs,
+ ParsedAttributeArgumentsProperties ArgsProperties) {
+ bool SawError = false;
+ unsigned Arg = 0;
+ while (true) {
+ ExprResult Expr;
+ if (ArgsProperties.isStringLiteralArg(Arg)) {
+ Expr = ParseUnevaluatedStringInAttribute(AttrName);
+ } else if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
+ Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
+ Expr = ParseBraceInitializer();
+ } else {
+ Expr = ParseAssignmentExpression();
+ }
+ Expr = Actions.CorrectDelayedTyposInExpr(Expr);
+
+ if (Tok.is(tok::ellipsis))
+ Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken());
+ else if (Tok.is(tok::code_completion)) {
+ // There's nothing to suggest in here as we parsed a full expression.
+ // Instead fail and propogate the error since caller might have something
+ // the suggest, e.g. signature help in function call. Note that this is
+ // performed before pushing the \p Expr, so that signature help can report
+ // current argument correctly.
+ SawError = true;
+ cutOffParsing();
+ break;
+ }
+ if (Expr.isInvalid()) {
+ SawError = true;
+ break;
+ SkipUntil(tok::comma, tok::r_paren, StopBeforeMatch);
+ } else {
+ Exprs.push_back(Expr.get());
+ }
+ if (Tok.isNot(tok::comma))
+ break;
+ // Move to the next argument, remember where the comma was.
+ Token Comma = Tok;
+ ConsumeToken();
+ checkPotentialAngleBracketDelimiter(Comma);
+ Arg++;
+ }
+ if (SawError) {
+ // Ensure typos get diagnosed when errors were encountered while parsing the
+ // expression list.
+ for (auto &E : Exprs) {
+ ExprResult Expr = Actions.CorrectDelayedTyposInExpr(E);
+ if (Expr.isUsable())
+ E = Expr.get();
+ }
+ }
+ return SawError;
+}
+
unsigned Parser::ParseAttributeArgsCommon(
IdentifierInfo *AttrName, SourceLocation AttrNameLoc,
ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName,
@@ -463,9 +546,9 @@
: Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprVector ParsedExprs;
- if (ParseExpressionList(ParsedExprs, llvm::function_ref<void()>(),
- /*FailImmediatelyOnInvalidExpr=*/true,
- /*EarlyTypoCorrection=*/true)) {
+ ParsedAttributeArgumentsProperties ArgProperties =
+ attributeStringLiteralListArg(*AttrName);
+ if (ParseAttributeArgumentList(*AttrName, ParsedExprs, ArgProperties)) {
SkipUntil(tok::r_paren, StopAtSemi);
return 0;
}
Index: clang/lib/Lex/Pragma.cpp
===================================================================
--- clang/lib/Lex/Pragma.cpp
+++ clang/lib/Lex/Pragma.cpp
@@ -1088,7 +1088,8 @@
if (DiagName.is(tok::eod))
PP.getDiagnostics().dump();
else if (DiagName.is(tok::string_literal) && !DiagName.hasUDSuffix()) {
- StringLiteralParser Literal(DiagName, PP);
+ StringLiteralParser Literal(DiagName, PP,
+ StringLiteralEvalMethod::Unevaluated);
if (Literal.hadError)
return;
PP.getDiagnostics().dump(Literal.GetString());
Index: clang/lib/Lex/PPMacroExpansion.cpp
===================================================================
--- clang/lib/Lex/PPMacroExpansion.cpp
+++ clang/lib/Lex/PPMacroExpansion.cpp
@@ -1869,7 +1869,8 @@
if (!Tok.isAnnotation() && Tok.getIdentifierInfo())
Tok.setKind(tok::identifier);
else if (Tok.is(tok::string_literal) && !Tok.hasUDSuffix()) {
- StringLiteralParser Literal(Tok, *this);
+ StringLiteralParser Literal(Tok, *this,
+ StringLiteralEvalMethod::Unevaluated);
if (Literal.hadError)
return;
Index: clang/lib/Lex/LiteralSupport.cpp
===================================================================
--- clang/lib/Lex/LiteralSupport.cpp
+++ clang/lib/Lex/LiteralSupport.cpp
@@ -87,6 +87,24 @@
MakeCharSourceRange(Features, TokLoc, TokBegin, TokRangeBegin, TokRangeEnd);
}
+static bool IsEscapeValidInUnevaluatedStringLiteral(char Escape) {
+ switch (Escape) {
+ case '\'':
+ case '"':
+ case '?':
+ case '\\':
+ case 'a':
+ case 'b':
+ case 'f':
+ case 'n':
+ case 'r':
+ case 't':
+ case 'v':
+ return true;
+ }
+ return false;
+}
+
/// ProcessCharEscape - Parse a standard C escape sequence, which can occur in
/// either a character or a string literal.
static unsigned ProcessCharEscape(const char *ThisTokBegin,
@@ -94,7 +112,8 @@
const char *ThisTokEnd, bool &HadError,
FullSourceLoc Loc, unsigned CharWidth,
DiagnosticsEngine *Diags,
- const LangOptions &Features) {
+ const LangOptions &Features,
+ StringLiteralEvalMethod EvalMethod) {
const char *EscapeBegin = ThisTokBuf;
bool Delimited = false;
bool EndDelimiterFound = false;
@@ -105,6 +124,7 @@
// We know that this character can't be off the end of the buffer, because
// that would have been \", which would not have been the end of string.
unsigned ResultChar = *ThisTokBuf++;
+ char Escape = ResultChar;
switch (ResultChar) {
// These map to themselves.
case '\\': case '\'': case '"': case '?': break;
@@ -318,6 +338,12 @@
}
}
+ if (EvalMethod == StringLiteralEvalMethod::Unevaluated &&
+ !IsEscapeValidInUnevaluatedStringLiteral(Escape)) {
+ Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
+ diag::err_unevaluated_string_invalid_escape_sequence)
+ << StringRef(EscapeBegin, ThisTokBuf - EscapeBegin);
+ }
return ResultChar;
}
@@ -1727,9 +1753,10 @@
}
unsigned CharWidth = getCharWidth(Kind, PP.getTargetInfo());
uint64_t result =
- ProcessCharEscape(TokBegin, begin, end, HadError,
- FullSourceLoc(Loc,PP.getSourceManager()),
- CharWidth, &PP.getDiagnostics(), PP.getLangOpts());
+ ProcessCharEscape(TokBegin, begin, end, HadError,
+ FullSourceLoc(Loc, PP.getSourceManager()), CharWidth,
+ &PP.getDiagnostics(), PP.getLangOpts(),
+ StringLiteralEvalMethod::Evaluated);
*buffer_begin++ = result;
}
@@ -1837,13 +1864,14 @@
/// hex-digit hex-digit hex-digit hex-digit
/// \endverbatim
///
-StringLiteralParser::
-StringLiteralParser(ArrayRef<Token> StringToks,
- Preprocessor &PP)
- : SM(PP.getSourceManager()), Features(PP.getLangOpts()),
- Target(PP.getTargetInfo()), Diags(&PP.getDiagnostics()),
- MaxTokenLength(0), SizeBound(0), CharByteWidth(0), Kind(tok::unknown),
- ResultPtr(ResultBuf.data()), hadError(false), Pascal(false) {
+StringLiteralParser::StringLiteralParser(ArrayRef<Token> StringToks,
+ Preprocessor &PP,
+ StringLiteralEvalMethod EvalMethod)
+ : SM(PP.getSourceManager()), Features(PP.getLangOpts()),
+ Target(PP.getTargetInfo()), Diags(&PP.getDiagnostics()),
+ MaxTokenLength(0), SizeBound(0), CharByteWidth(0), Kind(tok::unknown),
+ ResultPtr(ResultBuf.data()), EvalMethod(EvalMethod), hadError(false),
+ Pascal(false) {
init(StringToks);
}
@@ -1860,12 +1888,12 @@
assert(!StringToks.empty() && "expected at least one token");
MaxTokenLength = StringToks[0].getLength();
assert(StringToks[0].getLength() >= 2 && "literal token is invalid!");
- SizeBound = StringToks[0].getLength()-2; // -2 for "".
- Kind = StringToks[0].getKind();
-
+ SizeBound = StringToks[0].getLength() - 2; // -2 for "".
hadError = false;
- // Implement Translation Phase #6: concatenation of string literals
+ // Determines the kind of string from the prefix
+ Kind = tok::string_literal;
+
/// (C99 5.1.1.2p1). The common case is only one string fragment.
for (const Token &Tok : StringToks) {
if (Tok.getLength() < 2)
@@ -1882,7 +1910,11 @@
// Remember if we see any wide or utf-8/16/32 strings.
// Also check for illegal concatenations.
- if (Tok.isNot(Kind) && Tok.isNot(tok::string_literal)) {
+ if (isUnevaluated() && Tok.getKind() != tok::string_literal) {
+ if (Diags)
+ Diags->Report(Tok.getLocation(), diag::err_unevaluated_string_prefix);
+ hadError = true;
+ } else if (Tok.isNot(Kind) && Tok.isNot(tok::string_literal)) {
if (isOrdinary()) {
Kind = Tok.getKind();
} else {
@@ -1965,13 +1997,18 @@
// result of a concatenation involving at least one user-defined-string-
// literal, all the participating user-defined-string-literals shall
// have the same ud-suffix.
- if (UDSuffixBuf != UDSuffix) {
+ bool UnevaluatedStringHasUDL = isUnevaluated() && !UDSuffix.empty();
+ if (UDSuffixBuf != UDSuffix || UnevaluatedStringHasUDL) {
if (Diags) {
SourceLocation TokLoc = StringToks[i].getLocation();
- Diags->Report(TokLoc, diag::err_string_concat_mixed_suffix)
- << UDSuffixBuf << UDSuffix
- << SourceRange(UDSuffixTokLoc, UDSuffixTokLoc)
- << SourceRange(TokLoc, TokLoc);
+ if (UnevaluatedStringHasUDL) {
+ Diags->Report(TokLoc, diag::err_unevaluated_string_udl)
+ << SourceRange(TokLoc, TokLoc);
+ } else {
+ Diags->Report(TokLoc, diag::err_string_concat_mixed_suffix)
+ << UDSuffixBuf << UDSuffix
+ << SourceRange(UDSuffixTokLoc, UDSuffixTokLoc);
+ }
}
hadError = true;
}
@@ -2043,8 +2080,9 @@
++ThisTokBuf; // skip "
// Check if this is a pascal string
- if (Features.PascalStrings && ThisTokBuf + 1 != ThisTokEnd &&
- ThisTokBuf[0] == '\\' && ThisTokBuf[1] == 'p') {
+ if (!isUnevaluated() && Features.PascalStrings &&
+ ThisTokBuf + 1 != ThisTokEnd && ThisTokBuf[0] == '\\' &&
+ ThisTokBuf[1] == 'p') {
// If the \p sequence is found in the first token, we have a pascal string
// Otherwise, if we already have a pascal string, ignore the first \p
@@ -2080,9 +2118,9 @@
}
// Otherwise, this is a non-UCN escape character. Process it.
unsigned ResultChar =
- ProcessCharEscape(ThisTokBegin, ThisTokBuf, ThisTokEnd, hadError,
- FullSourceLoc(StringToks[i].getLocation(), SM),
- CharByteWidth*8, Diags, Features);
+ ProcessCharEscape(ThisTokBegin, ThisTokBuf, ThisTokEnd, hadError,
+ FullSourceLoc(StringToks[i].getLocation(), SM),
+ CharByteWidth * 8, Diags, Features, EvalMethod);
if (CharByteWidth == 4) {
// FIXME: Make the type of the result buffer correct instead of
@@ -2104,6 +2142,8 @@
}
}
+ assert((!Pascal || !isUnevaluated()) &&
+ "Pascal string in unevaluated context");
if (Pascal) {
if (CharByteWidth == 4) {
// FIXME: Make the type of the result buffer correct instead of
@@ -2277,8 +2317,8 @@
ByteNo -= Len;
} else {
ProcessCharEscape(SpellingStart, SpellingPtr, SpellingEnd, HadError,
- FullSourceLoc(Tok.getLocation(), SM),
- CharByteWidth*8, Diags, Features);
+ FullSourceLoc(Tok.getLocation(), SM), CharByteWidth * 8,
+ Diags, Features, StringLiteralEvalMethod::Evaluated);
--ByteNo;
}
assert(!HadError && "This method isn't valid on erroneous strings");
Index: clang/lib/AST/Expr.cpp
===================================================================
--- clang/lib/AST/Expr.cpp
+++ clang/lib/AST/Expr.cpp
@@ -1136,6 +1136,8 @@
case UTF32:
CharByteWidth = Target.getChar32Width();
break;
+ case Unevaluated:
+ return sizeof(char); // Host;
}
assert((CharByteWidth & 7) == 0 && "Assumes character size is byte multiple");
CharByteWidth /= 8;
@@ -1149,35 +1151,45 @@
const SourceLocation *Loc,
unsigned NumConcatenated)
: Expr(StringLiteralClass, Ty, VK_LValue, OK_Ordinary) {
- assert(Ctx.getAsConstantArrayType(Ty) &&
- "StringLiteral must be of constant array type!");
- unsigned CharByteWidth = mapCharByteWidth(Ctx.getTargetInfo(), Kind);
- unsigned ByteLength = Str.size();
- assert((ByteLength % CharByteWidth == 0) &&
- "The size of the data must be a multiple of CharByteWidth!");
-
- // Avoid the expensive division. The compiler should be able to figure it
- // out by itself. However as of clang 7, even with the appropriate
- // llvm_unreachable added just here, it is not able to do so.
- unsigned Length;
- switch (CharByteWidth) {
- case 1:
- Length = ByteLength;
- break;
- case 2:
- Length = ByteLength / 2;
- break;
- case 4:
- Length = ByteLength / 4;
- break;
- default:
- llvm_unreachable("Unsupported character width!");
- }
+
+ unsigned Length = Str.size();
StringLiteralBits.Kind = Kind;
- StringLiteralBits.CharByteWidth = CharByteWidth;
- StringLiteralBits.IsPascal = Pascal;
StringLiteralBits.NumConcatenated = NumConcatenated;
+
+ if (Kind != StringKind::Unevaluated) {
+ assert(Ctx.getAsConstantArrayType(Ty) &&
+ "StringLiteral must be of constant array type!");
+ unsigned CharByteWidth = mapCharByteWidth(Ctx.getTargetInfo(), Kind);
+ unsigned ByteLength = Str.size();
+ assert((ByteLength % CharByteWidth == 0) &&
+ "The size of the data must be a multiple of CharByteWidth!");
+
+ // Avoid the expensive division. The compiler should be able to figure it
+ // out by itself. However as of clang 7, even with the appropriate
+ // llvm_unreachable added just here, it is not able to do so.
+ switch (CharByteWidth) {
+ case 1:
+ Length = ByteLength;
+ break;
+ case 2:
+ Length = ByteLength / 2;
+ break;
+ case 4:
+ Length = ByteLength / 4;
+ break;
+ default:
+ llvm_unreachable("Unsupported character width!");
+ }
+
+ StringLiteralBits.CharByteWidth = CharByteWidth;
+ StringLiteralBits.IsPascal = Pascal;
+ } else {
+ assert(!Pascal && "Can't make an unevaluated Pascal string");
+ StringLiteralBits.CharByteWidth = 1;
+ StringLiteralBits.IsPascal = false;
+ }
+
*getTrailingObjects<unsigned>() = Length;
// Initialize the trailing array of SourceLocation.
@@ -1186,7 +1198,7 @@
NumConcatenated * sizeof(SourceLocation));
// Initialize the trailing array of char holding the string data.
- std::memcpy(getTrailingObjects<char>(), Str.data(), ByteLength);
+ std::memcpy(getTrailingObjects<char>(), Str.data(), Str.size());
setDependence(ExprDependence::None);
}
@@ -1223,6 +1235,7 @@
void StringLiteral::outputString(raw_ostream &OS) const {
switch (getKind()) {
+ case Unevaluated:
case Ordinary:
break; // no prefix.
case Wide: OS << 'L'; break;
@@ -1333,7 +1346,8 @@
const TargetInfo &Target, unsigned *StartToken,
unsigned *StartTokenByteOffset) const {
assert((getKind() == StringLiteral::Ordinary ||
- getKind() == StringLiteral::UTF8) &&
+ getKind() == StringLiteral::UTF8 ||
+ getKind() == StringLiteral::Unevaluated) &&
"Only narrow string literals are currently supported");
// Loop over all of the tokens in this string until we find the one that
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -5695,6 +5695,8 @@
ExprResult ActOnStringLiteral(ArrayRef<Token> StringToks,
Scope *UDLScope = nullptr);
+ ExprResult ActOnUnevaluatedStringLiteral(ArrayRef<Token> StringToks);
+
/// ControllingExprOrType is either an opaque pointer coming out of a
/// ParsedType or an Expr *. FIXME: it'd be better to split this interface
/// into two so we don't take a void *, but that's awkward because one of
Index: clang/include/clang/Sema/ParsedAttr.h
===================================================================
--- clang/include/clang/Sema/ParsedAttr.h
+++ clang/include/clang/Sema/ParsedAttr.h
@@ -24,6 +24,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/VersionTuple.h"
+#include <bitset>
#include <cassert>
#include <cstddef>
#include <cstring>
@@ -911,6 +912,20 @@
VecTy AttrList;
};
+struct ParsedAttributeArgumentsProperties {
+ ParsedAttributeArgumentsProperties(uint32_t StringLiteralBits)
+ : StringLiterals(StringLiteralBits) {}
+ bool isStringLiteralArg(unsigned I) const {
+ // If the last bit is set, assume we have a variadic parameter
+ if (I >= StringLiterals.size())
+ return StringLiterals.test(StringLiterals.size() - 1);
+ return StringLiterals.test(I);
+ }
+
+private:
+ std::bitset<32> StringLiterals;
+};
+
/// ParsedAttributes - A collection of parsed attributes. Currently
/// we don't differentiate between the various attribute syntaxes,
/// which is basically silly.
Index: clang/include/clang/Parse/Parser.h
===================================================================
--- clang/include/clang/Parse/Parser.h
+++ clang/include/clang/Parse/Parser.h
@@ -1788,8 +1788,12 @@
bool IsUnevaluated);
ExprResult ParseStringLiteralExpression(bool AllowUserDefinedLiteral = false);
+ ExprResult ParseUnevaluatedStringLiteralExpression();
private:
+ ExprResult ParseStringLiteralExpression(bool AllowUserDefinedLiteral,
+ bool Unevaluated);
+
ExprResult ParseExpressionWithLeadingAt(SourceLocation AtLoc);
ExprResult ParseExpressionWithLeadingExtension(SourceLocation ExtLoc);
@@ -2790,6 +2794,13 @@
/// clang accepts as an extension.
void DiagnoseCXX11AttributeExtension(ParsedAttributes &Attrs);
+ ExprResult ParseUnevaluatedStringInAttribute(const IdentifierInfo &AttrName);
+
+ bool
+ ParseAttributeArgumentList(const clang::IdentifierInfo &AttrName,
+ SmallVectorImpl<Expr *> &Exprs,
+ ParsedAttributeArgumentsProperties ArgsProperties);
+
/// Parses syntax-generic attribute arguments for attributes which are
/// known to the implementation, and adds them to the given ParsedAttributes
/// list with the given attribute syntax. Returns the number of arguments
Index: clang/include/clang/Lex/LiteralSupport.h
===================================================================
--- clang/include/clang/Lex/LiteralSupport.h
+++ clang/include/clang/Lex/LiteralSupport.h
@@ -212,6 +212,11 @@
}
};
+enum class StringLiteralEvalMethod {
+ Evaluated,
+ Unevaluated,
+};
+
/// StringLiteralParser - This decodes string escape characters and performs
/// wide string analysis and Translation Phase #6 (concatenation of string
/// literals) (C99 5.1.1.2p1).
@@ -230,20 +235,23 @@
SmallString<32> UDSuffixBuf;
unsigned UDSuffixToken;
unsigned UDSuffixOffset;
+ StringLiteralEvalMethod EvalMethod;
+
public:
- StringLiteralParser(ArrayRef<Token> StringToks,
- Preprocessor &PP);
- StringLiteralParser(ArrayRef<Token> StringToks,
- const SourceManager &sm, const LangOptions &features,
- const TargetInfo &target,
+ StringLiteralParser(ArrayRef<Token> StringToks, Preprocessor &PP,
+ StringLiteralEvalMethod StringMethod =
+ StringLiteralEvalMethod::Evaluated);
+ StringLiteralParser(ArrayRef<Token> StringToks, const SourceManager &sm,
+ const LangOptions &features, const TargetInfo &target,
DiagnosticsEngine *diags = nullptr)
- : SM(sm), Features(features), Target(target), Diags(diags),
- MaxTokenLength(0), SizeBound(0), CharByteWidth(0), Kind(tok::unknown),
- ResultPtr(ResultBuf.data()), hadError(false), Pascal(false) {
+ : SM(sm), Features(features), Target(target), Diags(diags),
+ MaxTokenLength(0), SizeBound(0), CharByteWidth(0), Kind(tok::unknown),
+ ResultPtr(ResultBuf.data()),
+ EvalMethod(StringLiteralEvalMethod::Evaluated), hadError(false),
+ Pascal(false) {
init(StringToks);
}
-
bool hadError;
bool Pascal;
@@ -269,6 +277,9 @@
bool isUTF16() const { return Kind == tok::utf16_string_literal; }
bool isUTF32() const { return Kind == tok::utf32_string_literal; }
bool isPascal() const { return Pascal; }
+ bool isUnevaluated() const {
+ return EvalMethod == StringLiteralEvalMethod::Unevaluated;
+ }
StringRef getUDSuffix() const { return UDSuffixBuf; }
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -433,9 +433,6 @@
"ISO C requires a named parameter before '...'">;
def err_declarator_need_ident : Error<"declarator requires an identifier">;
def err_language_linkage_spec_unknown : Error<"unknown linkage language">;
-def err_language_linkage_spec_not_ascii : Error<
- "string literal in language linkage specifier cannot have an "
- "encoding-prefix">;
def ext_use_out_of_scope_declaration : ExtWarn<
"use of out-of-scope declaration of %0%select{| whose type is not "
"compatible with that of an implicit declaration}1">,
Index: clang/include/clang/Basic/DiagnosticLexKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticLexKinds.td
+++ clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -276,6 +276,13 @@
"identifier">, InGroup<ReservedUserDefinedLiteral>;
def err_unsupported_string_concat : Error<
"unsupported non-standard concatenation of string literals">;
+
+def err_unevaluated_string_prefix : Error<
+ "an unevaluated string literal cannot have an encoding prefix">;
+def err_unevaluated_string_udl : Error<
+ "an unevaluated string literal cannot be a user-defined literal">;
+def err_unevaluated_string_invalid_escape_sequence : Error<
+ "invalid escape sequence '%0' in an unevaluated string literal">;
def err_string_concat_mixed_suffix : Error<
"differing user-defined suffixes ('%0' and '%1') in string literal "
"concatenation">;
Index: clang/include/clang/Basic/DiagnosticCommonKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -56,7 +56,9 @@
"%select{in %1|for diagnostic message in static_assert|"
"for optional message in 'availability' attribute|"
"for %select{language name|source container name|USR}1 in "
- "'external_source_symbol' attribute}0">;
+ "'external_source_symbol' attribute|"
+ "as argument of '%1' attribute}0">;
+
def err_invalid_string_udl : Error<
"string literal with user-defined suffix cannot be used here">;
def err_invalid_character_udl : Error<
Index: clang/include/clang/AST/Expr.h
===================================================================
--- clang/include/clang/AST/Expr.h
+++ clang/include/clang/AST/Expr.h
@@ -1804,7 +1804,7 @@
/// * An array of getByteLength() char used to store the string data.
public:
- enum StringKind { Ordinary, Wide, UTF8, UTF16, UTF32 };
+ enum StringKind { Ordinary, Wide, UTF8, UTF16, UTF32, Unevaluated };
private:
unsigned numTrailingObjects(OverloadToken<unsigned>) const { return 1; }
@@ -1866,7 +1866,7 @@
unsigned CharByteWidth);
StringRef getString() const {
- assert(getCharByteWidth() == 1 &&
+ assert((isUnevaluated() || getCharByteWidth() == 1) &&
"This function is used in places that assume strings use char");
return StringRef(getStrDataAsChar(), getByteLength());
}
@@ -1906,6 +1906,7 @@
bool isUTF8() const { return getKind() == UTF8; }
bool isUTF16() const { return getKind() == UTF16; }
bool isUTF32() const { return getKind() == UTF32; }
+ bool isUnevaluated() const { return getKind() == Unevaluated; }
bool isPascal() const { return StringLiteralBits.IsPascal; }
bool containsNonAscii() const {
Index: clang-tools-extra/test/clang-tidy/checkers/modernize/unary-static-assert.cpp
===================================================================
--- clang-tools-extra/test/clang-tidy/checkers/modernize/unary-static-assert.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize/unary-static-assert.cpp
@@ -7,9 +7,6 @@
static_assert(sizeof(a) <= 10, "");
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use unary 'static_assert' when the string literal is an empty string [modernize-unary-static-assert]
// CHECK-FIXES: {{^}} static_assert(sizeof(a) <= 10 );{{$}}
- static_assert(sizeof(a) <= 12, L"");
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use unary 'static_assert' when
- // CHECK-FIXES: {{^}} static_assert(sizeof(a) <= 12 );{{$}}
FOO
// CHECK-FIXES: {{^}} FOO{{$}}
static_assert(sizeof(a) <= 17, MSG);
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits