diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -450,6 +450,10 @@ It can be used to writing conditionally constexpr code that uses builtins. - The time profiler (using ``-ftime-trace`` option) now traces various constant evaluation events. +- Clang can now generate a PCH when using ``-fdelayed-template-parsing`` for + code with templates containing loop hint pragmas, OpenMP pragmas, and + ``#pragma unused``. + New Compiler Flags ------------------ diff --git a/clang/include/clang/Lex/Token.h b/clang/include/clang/Lex/Token.h --- a/clang/include/clang/Lex/Token.h +++ b/clang/include/clang/Lex/Token.h @@ -15,6 +15,7 @@ #include "clang/Basic/SourceLocation.h" #include "clang/Basic/TokenKinds.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include @@ -330,6 +331,12 @@ bool FoundElse; }; +// Extra information needed for annonation tokens. +struct PragmaLoopHintInfo { + Token PragmaName; + Token Option; + ArrayRef Toks; +}; } // end namespace clang #endif // LLVM_CLANG_LEX_TOKEN_H diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -41,7 +41,7 @@ /// Version 4 of AST files also requires that the version control branch and /// revision match exactly, since there is no backward compatibility of /// AST files at this time. -const unsigned VERSION_MAJOR = 23; +const unsigned VERSION_MAJOR = 24; /// AST file minor version number supported by this version of /// Clang. diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -1293,14 +1293,6 @@ return true; } -namespace { -struct PragmaLoopHintInfo { - Token PragmaName; - Token Option; - ArrayRef Toks; -}; -} // end anonymous namespace - static std::string PragmaLoopHintString(Token PragmaName, Token Option) { StringRef Str = PragmaName.getIdentifierInfo()->getName(); std::string ClangLoopStr("clang loop "); diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -1669,11 +1669,38 @@ Token Tok; Tok.startToken(); Tok.setLocation(ReadSourceLocation(F, Record, Idx)); - Tok.setLength(Record[Idx++]); - if (IdentifierInfo *II = getLocalIdentifier(F, Record[Idx++])) - Tok.setIdentifierInfo(II); Tok.setKind((tok::TokenKind)Record[Idx++]); Tok.setFlag((Token::TokenFlags)Record[Idx++]); + + if (Tok.isAnnotation()) { + Tok.setAnnotationEndLoc(ReadSourceLocation(F, Record, Idx)); + switch (Tok.getKind()) { + case tok::annot_pragma_loop_hint: { + auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo; + Info->PragmaName = ReadToken(F, Record, Idx); + Info->Option = ReadToken(F, Record, Idx); + unsigned NumTokens = Record[Idx++]; + SmallVector Toks; + Toks.reserve(NumTokens); + for (unsigned I = 0; I < NumTokens; ++I) + Toks.push_back(ReadToken(F, Record, Idx)); + Info->Toks = llvm::makeArrayRef(Toks).copy(PP.getPreprocessorAllocator()); + Tok.setAnnotationValue(static_cast(Info)); + break; + } + // Some annotation tokens do not use the PtrData field. + case tok::annot_pragma_openmp: + case tok::annot_pragma_openmp_end: + case tok::annot_pragma_unused: + break; + default: + llvm_unreachable("missing deserialization code for annotation token"); + } + } else { + Tok.setLength(Record[Idx++]); + if (IdentifierInfo *II = getLocalIdentifier(F, Record[Idx++])) + Tok.setIdentifierInfo(II); + } return Tok; } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -4372,15 +4372,37 @@ void ASTWriter::AddToken(const Token &Tok, RecordDataImpl &Record) { AddSourceLocation(Tok.getLocation(), Record); - Record.push_back(Tok.getLength()); - - // FIXME: When reading literal tokens, reconstruct the literal pointer - // if it is needed. - AddIdentifierRef(Tok.getIdentifierInfo(), Record); // FIXME: Should translate token kind to a stable encoding. Record.push_back(Tok.getKind()); // FIXME: Should translate token flags to a stable encoding. Record.push_back(Tok.getFlags()); + + if (Tok.isAnnotation()) { + AddSourceLocation(Tok.getAnnotationEndLoc(), Record); + switch (Tok.getKind()) { + case tok::annot_pragma_loop_hint: { + auto *Info = static_cast(Tok.getAnnotationValue()); + AddToken(Info->PragmaName, Record); + AddToken(Info->Option, Record); + Record.push_back(Info->Toks.size()); + for (const auto &T : Info->Toks) + AddToken(T, Record); + break; + } + // Some annotation tokens do not use the PtrData field. + case tok::annot_pragma_openmp: + case tok::annot_pragma_openmp_end: + case tok::annot_pragma_unused: + break; + default: + llvm_unreachable("missing serialization code for annotation token"); + } + } else { + Record.push_back(Tok.getLength()); + // FIXME: When reading literal tokens, reconstruct the literal pointer if it + // is needed. + AddIdentifierRef(Tok.getIdentifierInfo(), Record); + } } void ASTWriter::AddString(StringRef Str, RecordDataImpl &Record) { diff --git a/clang/test/PCH/delayed-template-with-pragma.cpp b/clang/test/PCH/delayed-template-with-pragma.cpp new file mode 100644 --- /dev/null +++ b/clang/test/PCH/delayed-template-with-pragma.cpp @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -fopenmp -emit-pch -o %t.pch %s +// RUN: %clang_cc1 -fopenmp -fdelayed-template-parsing -emit-pch -o %t.delayed.pch %s +// RUN: %clang_cc1 -DMAIN_FILE -fopenmp -include-pch %t.pch \ +// RUN: -emit-llvm -o - %s -fopenmp | FileCheck %s +// RUN: %clang_cc1 -DMAIN_FILE -fopenmp -fdelayed-template-parsing -verify \ +// RUN: -Wunused-variable -include-pch %t.delayed.pch \ +// RUN: -emit-llvm -o - %s | FileCheck %s + +#ifndef MAIN_FILE +template +void a(T t) { + #pragma clang loop unroll_count(4) + for(int i=0;i<8;++i) {} + #pragma omp simd + for(int i=0;i<8;++i) {} + { + int x, y, z, zz; + #pragma unused(x) + #pragma unused(y, z) + } +} +#else +// CHECK: !llvm.loop !3 +// CHECK: !llvm.loop !7 +// CHECK: !3 = distinct !{!3, !4, !5} +// CHECK: !4 = !{!"llvm.loop.mustprogress"} +// CHECK: !5 = !{!"llvm.loop.unroll.count", i32 4} +// CHECK: !7 = distinct !{!7, !8, !9} +// CHECK: !8 = !{!"llvm.loop.parallel_accesses", !6} +// CHECK: !9 = !{!"llvm.loop.vectorize.enable", i1 true} +// expected-warning@17 {{unused variable 'zz'}} +void foo() +{ + a(1); +} +#endif