diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 8e01ef6cbb399..286405850900a 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -2821,7 +2821,7 @@ Example output: The ``__builtin_dump_struct`` function is used to print the fields of a simple structure and their values for debugging purposes. The first argument of the -builtin should be a pointer to the struct to dump. The second argument ``f`` +builtin should be a pointer to a complete record type to dump. The second argument ``f`` should be some callable expression, and can be a function object or an overload set. The builtin calls ``f``, passing any further arguments ``args...`` followed by a ``printf``-compatible format string and the corresponding diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 683d0026bb345..41904f4db8ef3 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -794,6 +794,9 @@ Bug Fixes to C++ Support Fixes: (`#68769 `_) +- Clang now rejects incomplete types for ``__builtin_dump_struct``. Fixes: + (`#63506 `_) + - Fixed a crash for C++98/03 while checking an ill-formed ``_Static_assert`` expression. Fixes: (`#72025 `_) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 77c8334f3ca25..07ced5ffc3407 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -712,8 +712,13 @@ static ExprResult SemaBuiltinDumpStruct(Sema &S, CallExpr *TheCall) { << 1 << TheCall->getDirectCallee() << PtrArgType; return ExprError(); } - const RecordDecl *RD = PtrArgType->getPointeeType()->getAsRecordDecl(); - + QualType Pointee = PtrArgType->getPointeeType(); + const RecordDecl *RD = Pointee->getAsRecordDecl(); + // Try to instantiate the class template as appropriate; otherwise, access to + // its data() may lead to a crash. + if (S.RequireCompleteType(PtrArgResult.get()->getBeginLoc(), Pointee, + diag::err_incomplete_type)) + return ExprError(); // Second argument is a callable, but we can't fully validate it until we try // calling it. QualType FnArgType = TheCall->getArg(1)->getType(); diff --git a/clang/test/SemaCXX/builtin-dump-struct.cpp b/clang/test/SemaCXX/builtin-dump-struct.cpp index b3d2a2d808ce2..91ffa7c8c05bd 100644 --- a/clang/test/SemaCXX/builtin-dump-struct.cpp +++ b/clang/test/SemaCXX/builtin-dump-struct.cpp @@ -149,7 +149,15 @@ B { } )"[1]); +class Incomplete; // #incomplete-type + +template +class Class { + T value = {}; +}; + void errors(B b) { + ConstexprString cs; __builtin_dump_struct(); // expected-error {{too few arguments to function call, expected 2, have 0}} __builtin_dump_struct(1); // expected-error {{too few arguments to function call, expected 2, have 1}} __builtin_dump_struct(1, 2); // expected-error {{expected pointer to struct as 1st argument to '__builtin_dump_struct', found 'int'}} @@ -157,6 +165,10 @@ void errors(B b) { __builtin_dump_struct(&b, Format, 0); // expected-error {{no matching function for call to 'Format'}} // expected-note@-1 {{in call to printing function with arguments '(0, "%s", "B")' while dumping struct}} // expected-note@#Format {{no known conversion from 'int' to 'ConstexprString &' for 1st argument}} + __builtin_dump_struct((Incomplete *)nullptr, Format, cs); // expected-error {{incomplete type 'Incomplete' where a complete type is required}} + // expected-note@#incomplete-type {{forward declaration of 'Incomplete'}} + // Ensure the Class gets instantiated; otherwise crash happens. + __builtin_dump_struct((Class *)nullptr, Format, cs); } #endif