2012-12-21 03:22:21 +08:00
|
|
|
//===--- SemaAttr.cpp - Semantic Analysis for Attributes ------------------===//
|
2009-02-17 08:57:29 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2009-02-17 08:57:29 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2009-02-17 09:09:29 +08:00
|
|
|
// This file implements semantic analysis for non-trivial attributes and
|
|
|
|
// pragmas.
|
2009-02-17 08:57:29 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2013-05-08 21:44:39 +08:00
|
|
|
#include "clang/AST/ASTConsumer.h"
|
2010-08-19 07:23:40 +08:00
|
|
|
#include "clang/AST/Attr.h"
|
2009-02-17 08:57:29 +08:00
|
|
|
#include "clang/AST/Expr.h"
|
2010-05-27 08:35:16 +08:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
|
|
|
#include "clang/Lex/Preprocessor.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/Sema/Lookup.h"
|
2016-07-19 03:02:11 +08:00
|
|
|
#include "clang/Sema/SemaInternal.h"
|
2009-02-17 08:57:29 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
2009-02-17 09:09:29 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2010-05-27 08:04:40 +08:00
|
|
|
// Pragma 'pack' and 'options align'
|
2009-02-17 09:09:29 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2016-04-29 19:27:00 +08:00
|
|
|
Sema::PragmaStackSentinelRAII::PragmaStackSentinelRAII(Sema &S,
|
|
|
|
StringRef SlotLabel,
|
|
|
|
bool ShouldAct)
|
|
|
|
: S(S), SlotLabel(SlotLabel), ShouldAct(ShouldAct) {
|
|
|
|
if (ShouldAct) {
|
|
|
|
S.VtorDispStack.SentinelAction(PSK_Push, SlotLabel);
|
|
|
|
S.DataSegStack.SentinelAction(PSK_Push, SlotLabel);
|
|
|
|
S.BSSSegStack.SentinelAction(PSK_Push, SlotLabel);
|
|
|
|
S.ConstSegStack.SentinelAction(PSK_Push, SlotLabel);
|
|
|
|
S.CodeSegStack.SentinelAction(PSK_Push, SlotLabel);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Sema::PragmaStackSentinelRAII::~PragmaStackSentinelRAII() {
|
|
|
|
if (ShouldAct) {
|
|
|
|
S.VtorDispStack.SentinelAction(PSK_Pop, SlotLabel);
|
|
|
|
S.DataSegStack.SentinelAction(PSK_Pop, SlotLabel);
|
|
|
|
S.BSSSegStack.SentinelAction(PSK_Pop, SlotLabel);
|
|
|
|
S.ConstSegStack.SentinelAction(PSK_Pop, SlotLabel);
|
|
|
|
S.CodeSegStack.SentinelAction(PSK_Pop, SlotLabel);
|
|
|
|
}
|
|
|
|
}
|
2009-02-17 09:09:29 +08:00
|
|
|
|
2010-05-27 09:53:40 +08:00
|
|
|
void Sema::AddAlignmentAttributesForRecord(RecordDecl *RD) {
|
2016-04-30 02:17:40 +08:00
|
|
|
// If there is no pack value, we don't need any attributes.
|
|
|
|
if (!PackStack.CurrentValue)
|
2010-05-27 09:53:40 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Otherwise, check to see if we need a max field alignment attribute.
|
2016-04-30 02:17:40 +08:00
|
|
|
if (unsigned Alignment = PackStack.CurrentValue) {
|
|
|
|
if (Alignment == Sema::kMac68kAlignmentSentinel)
|
2014-01-16 21:03:14 +08:00
|
|
|
RD->addAttr(AlignMac68kAttr::CreateImplicit(Context));
|
2010-05-27 13:45:51 +08:00
|
|
|
else
|
2014-01-16 21:03:14 +08:00
|
|
|
RD->addAttr(MaxFieldAlignmentAttr::CreateImplicit(Context,
|
2010-08-19 07:23:40 +08:00
|
|
|
Alignment * 8));
|
2010-05-27 13:45:51 +08:00
|
|
|
}
|
2017-07-28 22:41:21 +08:00
|
|
|
if (PackIncludeStack.empty())
|
|
|
|
return;
|
|
|
|
// The #pragma pack affected a record in an included file, so Clang should
|
|
|
|
// warn when that pragma was written in a file that included the included
|
|
|
|
// file.
|
|
|
|
for (auto &PackedInclude : llvm::reverse(PackIncludeStack)) {
|
|
|
|
if (PackedInclude.CurrentPragmaLocation != PackStack.CurrentPragmaLocation)
|
|
|
|
break;
|
|
|
|
if (PackedInclude.HasNonDefaultValue)
|
|
|
|
PackedInclude.ShouldWarnOnInclude = true;
|
|
|
|
}
|
2009-02-17 09:09:29 +08:00
|
|
|
}
|
|
|
|
|
2011-04-27 01:54:40 +08:00
|
|
|
void Sema::AddMsStructLayoutForRecord(RecordDecl *RD) {
|
2014-02-13 07:50:26 +08:00
|
|
|
if (MSStructPragmaOn)
|
2015-02-03 03:30:52 +08:00
|
|
|
RD->addAttr(MSStructAttr::CreateImplicit(Context));
|
2014-02-13 07:50:26 +08:00
|
|
|
|
|
|
|
// FIXME: We should merge AddAlignmentAttributesForRecord with
|
|
|
|
// AddMsStructLayoutForRecord into AddPragmaAttributesForRecord, which takes
|
|
|
|
// all active pragmas and applies them as attributes to class definitions.
|
2019-11-23 06:55:49 +08:00
|
|
|
if (VtorDispStack.CurrentValue != getLangOpts().getVtorDispMode())
|
|
|
|
RD->addAttr(MSVtorDispAttr::CreateImplicit(
|
|
|
|
Context, unsigned(VtorDispStack.CurrentValue)));
|
2011-04-27 01:54:40 +08:00
|
|
|
}
|
|
|
|
|
gsl::Owner/gsl::Pointer: Add implicit annotations for some std types
Summary:
Hard code gsl::Owner/gsl::Pointer for std types. The paper mentions
some types explicitly. Generally, all containers and their iterators are
covered. For iterators, we cover both the case that they are defined
as an nested class or as an typedef/using. I have started to test this
implementation against some real standard library implementations, namely
libc++ 7.1.0, libc++ 8.0.1rc2, libstdc++ 4.6.4, libstdc++ 4.8.5,
libstdc++ 4.9.4, libstdc++ 5.4.0, libstdc++ 6.5.0, libstdc++ 7.3.0,
libstdc++ 8.3.0 and libstdc++ 9.1.0.
The tests are currently here
https://github.com/mgehre/llvm-project/blob/lifetime-ci/lifetime-attr-test.sh
https://github.com/mgehre/llvm-project/blob/lifetime-ci/lifetime-attr-test.cpp
I think due to their dependency on a standard library, they are not a good fit
for clang/test/. Where else could I put them?
Reviewers: gribozavr, xazax.hun
Subscribers: rnkovacs, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64448
llvm-svn: 368147
2019-08-07 18:45:36 +08:00
|
|
|
template <typename Attribute>
|
|
|
|
static void addGslOwnerPointerAttributeIfNotExisting(ASTContext &Context,
|
|
|
|
CXXRecordDecl *Record) {
|
2019-09-06 16:56:30 +08:00
|
|
|
if (Record->hasAttr<OwnerAttr>() || Record->hasAttr<PointerAttr>())
|
gsl::Owner/gsl::Pointer: Add implicit annotations for some std types
Summary:
Hard code gsl::Owner/gsl::Pointer for std types. The paper mentions
some types explicitly. Generally, all containers and their iterators are
covered. For iterators, we cover both the case that they are defined
as an nested class or as an typedef/using. I have started to test this
implementation against some real standard library implementations, namely
libc++ 7.1.0, libc++ 8.0.1rc2, libstdc++ 4.6.4, libstdc++ 4.8.5,
libstdc++ 4.9.4, libstdc++ 5.4.0, libstdc++ 6.5.0, libstdc++ 7.3.0,
libstdc++ 8.3.0 and libstdc++ 9.1.0.
The tests are currently here
https://github.com/mgehre/llvm-project/blob/lifetime-ci/lifetime-attr-test.sh
https://github.com/mgehre/llvm-project/blob/lifetime-ci/lifetime-attr-test.cpp
I think due to their dependency on a standard library, they are not a good fit
for clang/test/. Where else could I put them?
Reviewers: gribozavr, xazax.hun
Subscribers: rnkovacs, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64448
llvm-svn: 368147
2019-08-07 18:45:36 +08:00
|
|
|
return;
|
|
|
|
|
2019-09-06 16:56:30 +08:00
|
|
|
for (Decl *Redecl : Record->redecls())
|
|
|
|
Redecl->addAttr(Attribute::CreateImplicit(Context, /*DerefType=*/nullptr));
|
gsl::Owner/gsl::Pointer: Add implicit annotations for some std types
Summary:
Hard code gsl::Owner/gsl::Pointer for std types. The paper mentions
some types explicitly. Generally, all containers and their iterators are
covered. For iterators, we cover both the case that they are defined
as an nested class or as an typedef/using. I have started to test this
implementation against some real standard library implementations, namely
libc++ 7.1.0, libc++ 8.0.1rc2, libstdc++ 4.6.4, libstdc++ 4.8.5,
libstdc++ 4.9.4, libstdc++ 5.4.0, libstdc++ 6.5.0, libstdc++ 7.3.0,
libstdc++ 8.3.0 and libstdc++ 9.1.0.
The tests are currently here
https://github.com/mgehre/llvm-project/blob/lifetime-ci/lifetime-attr-test.sh
https://github.com/mgehre/llvm-project/blob/lifetime-ci/lifetime-attr-test.cpp
I think due to their dependency on a standard library, they are not a good fit
for clang/test/. Where else could I put them?
Reviewers: gribozavr, xazax.hun
Subscribers: rnkovacs, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64448
llvm-svn: 368147
2019-08-07 18:45:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Sema::inferGslPointerAttribute(NamedDecl *ND,
|
|
|
|
CXXRecordDecl *UnderlyingRecord) {
|
|
|
|
if (!UnderlyingRecord)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const auto *Parent = dyn_cast<CXXRecordDecl>(ND->getDeclContext());
|
|
|
|
if (!Parent)
|
|
|
|
return;
|
|
|
|
|
|
|
|
static llvm::StringSet<> Containers{
|
|
|
|
"array",
|
|
|
|
"basic_string",
|
|
|
|
"deque",
|
|
|
|
"forward_list",
|
|
|
|
"vector",
|
|
|
|
"list",
|
|
|
|
"map",
|
|
|
|
"multiset",
|
|
|
|
"multimap",
|
|
|
|
"priority_queue",
|
|
|
|
"queue",
|
|
|
|
"set",
|
|
|
|
"stack",
|
|
|
|
"unordered_set",
|
|
|
|
"unordered_map",
|
|
|
|
"unordered_multiset",
|
|
|
|
"unordered_multimap",
|
|
|
|
};
|
|
|
|
|
|
|
|
static llvm::StringSet<> Iterators{"iterator", "const_iterator",
|
|
|
|
"reverse_iterator",
|
|
|
|
"const_reverse_iterator"};
|
|
|
|
|
|
|
|
if (Parent->isInStdNamespace() && Iterators.count(ND->getName()) &&
|
|
|
|
Containers.count(Parent->getName()))
|
|
|
|
addGslOwnerPointerAttributeIfNotExisting<PointerAttr>(Context,
|
|
|
|
UnderlyingRecord);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Sema::inferGslPointerAttribute(TypedefNameDecl *TD) {
|
|
|
|
|
|
|
|
QualType Canonical = TD->getUnderlyingType().getCanonicalType();
|
|
|
|
|
|
|
|
CXXRecordDecl *RD = Canonical->getAsCXXRecordDecl();
|
|
|
|
if (!RD) {
|
|
|
|
if (auto *TST =
|
|
|
|
dyn_cast<TemplateSpecializationType>(Canonical.getTypePtr())) {
|
|
|
|
|
|
|
|
RD = dyn_cast_or_null<CXXRecordDecl>(
|
|
|
|
TST->getTemplateName().getAsTemplateDecl()->getTemplatedDecl());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inferGslPointerAttribute(TD, RD);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Sema::inferGslOwnerPointerAttribute(CXXRecordDecl *Record) {
|
|
|
|
static llvm::StringSet<> StdOwners{
|
|
|
|
"any",
|
|
|
|
"array",
|
|
|
|
"basic_regex",
|
|
|
|
"basic_string",
|
|
|
|
"deque",
|
|
|
|
"forward_list",
|
|
|
|
"vector",
|
|
|
|
"list",
|
|
|
|
"map",
|
|
|
|
"multiset",
|
|
|
|
"multimap",
|
|
|
|
"optional",
|
|
|
|
"priority_queue",
|
|
|
|
"queue",
|
|
|
|
"set",
|
|
|
|
"stack",
|
|
|
|
"unique_ptr",
|
|
|
|
"unordered_set",
|
|
|
|
"unordered_map",
|
|
|
|
"unordered_multiset",
|
|
|
|
"unordered_multimap",
|
|
|
|
"variant",
|
|
|
|
};
|
|
|
|
static llvm::StringSet<> StdPointers{
|
|
|
|
"basic_string_view",
|
|
|
|
"reference_wrapper",
|
|
|
|
"regex_iterator",
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!Record->getIdentifier())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Handle classes that directly appear in std namespace.
|
|
|
|
if (Record->isInStdNamespace()) {
|
2019-09-06 16:56:30 +08:00
|
|
|
if (Record->hasAttr<OwnerAttr>() || Record->hasAttr<PointerAttr>())
|
gsl::Owner/gsl::Pointer: Add implicit annotations for some std types
Summary:
Hard code gsl::Owner/gsl::Pointer for std types. The paper mentions
some types explicitly. Generally, all containers and their iterators are
covered. For iterators, we cover both the case that they are defined
as an nested class or as an typedef/using. I have started to test this
implementation against some real standard library implementations, namely
libc++ 7.1.0, libc++ 8.0.1rc2, libstdc++ 4.6.4, libstdc++ 4.8.5,
libstdc++ 4.9.4, libstdc++ 5.4.0, libstdc++ 6.5.0, libstdc++ 7.3.0,
libstdc++ 8.3.0 and libstdc++ 9.1.0.
The tests are currently here
https://github.com/mgehre/llvm-project/blob/lifetime-ci/lifetime-attr-test.sh
https://github.com/mgehre/llvm-project/blob/lifetime-ci/lifetime-attr-test.cpp
I think due to their dependency on a standard library, they are not a good fit
for clang/test/. Where else could I put them?
Reviewers: gribozavr, xazax.hun
Subscribers: rnkovacs, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64448
llvm-svn: 368147
2019-08-07 18:45:36 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (StdOwners.count(Record->getName()))
|
|
|
|
addGslOwnerPointerAttributeIfNotExisting<OwnerAttr>(Context, Record);
|
|
|
|
else if (StdPointers.count(Record->getName()))
|
|
|
|
addGslOwnerPointerAttributeIfNotExisting<PointerAttr>(Context, Record);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle nested classes that could be a gsl::Pointer.
|
|
|
|
inferGslPointerAttribute(Record, Record);
|
|
|
|
}
|
|
|
|
|
2010-05-27 08:04:40 +08:00
|
|
|
void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
|
2012-10-04 10:36:51 +08:00
|
|
|
SourceLocation PragmaLoc) {
|
2016-04-30 02:17:40 +08:00
|
|
|
PragmaMsStackAction Action = Sema::PSK_Reset;
|
2016-04-30 06:50:16 +08:00
|
|
|
unsigned Alignment = 0;
|
2010-05-27 08:04:40 +08:00
|
|
|
switch (Kind) {
|
2010-05-28 02:42:09 +08:00
|
|
|
// For all targets we support native and natural are the same.
|
|
|
|
//
|
|
|
|
// FIXME: This is not true on Darwin/PPC.
|
|
|
|
case POAK_Native:
|
2010-05-29 03:43:33 +08:00
|
|
|
case POAK_Power:
|
2010-05-29 04:08:00 +08:00
|
|
|
case POAK_Natural:
|
2016-04-30 02:17:40 +08:00
|
|
|
Action = Sema::PSK_Push_Set;
|
|
|
|
Alignment = 0;
|
2010-05-29 03:43:33 +08:00
|
|
|
break;
|
|
|
|
|
2010-05-28 02:42:17 +08:00
|
|
|
// Note that '#pragma options align=packed' is not equivalent to attribute
|
|
|
|
// packed, it has a different precedence relative to attribute aligned.
|
|
|
|
case POAK_Packed:
|
2016-04-30 02:17:40 +08:00
|
|
|
Action = Sema::PSK_Push_Set;
|
|
|
|
Alignment = 1;
|
2010-05-28 02:42:17 +08:00
|
|
|
break;
|
|
|
|
|
2010-05-27 08:35:16 +08:00
|
|
|
case POAK_Mac68k:
|
|
|
|
// Check if the target supports this.
|
2014-05-03 11:45:55 +08:00
|
|
|
if (!this->Context.getTargetInfo().hasAlignMac68kSupport()) {
|
2010-05-27 08:35:16 +08:00
|
|
|
Diag(PragmaLoc, diag::err_pragma_options_align_mac68k_target_unsupported);
|
|
|
|
return;
|
|
|
|
}
|
2016-04-30 02:17:40 +08:00
|
|
|
Action = Sema::PSK_Push_Set;
|
|
|
|
Alignment = Sema::kMac68kAlignmentSentinel;
|
2010-05-27 08:35:16 +08:00
|
|
|
break;
|
|
|
|
|
2012-10-04 10:36:51 +08:00
|
|
|
case POAK_Reset:
|
|
|
|
// Reset just pops the top of the stack, or resets the current alignment to
|
|
|
|
// default.
|
2016-04-30 02:17:40 +08:00
|
|
|
Action = Sema::PSK_Pop;
|
|
|
|
if (PackStack.Stack.empty()) {
|
|
|
|
if (PackStack.CurrentValue) {
|
|
|
|
Action = Sema::PSK_Reset;
|
|
|
|
} else {
|
|
|
|
Diag(PragmaLoc, diag::warn_pragma_options_align_reset_failed)
|
|
|
|
<< "stack empty";
|
|
|
|
return;
|
|
|
|
}
|
2012-10-04 10:36:51 +08:00
|
|
|
}
|
2010-05-27 08:04:40 +08:00
|
|
|
break;
|
|
|
|
}
|
2016-04-30 02:17:40 +08:00
|
|
|
|
|
|
|
PackStack.Act(PragmaLoc, Action, StringRef(), Alignment);
|
2010-05-27 08:04:40 +08:00
|
|
|
}
|
|
|
|
|
2017-06-05 18:11:57 +08:00
|
|
|
void Sema::ActOnPragmaClangSection(SourceLocation PragmaLoc, PragmaClangSectionAction Action,
|
|
|
|
PragmaClangSectionKind SecKind, StringRef SecName) {
|
|
|
|
PragmaClangSection *CSec;
|
2020-04-16 20:55:18 +08:00
|
|
|
int SectionFlags = ASTContext::PSF_Read;
|
2017-06-05 18:11:57 +08:00
|
|
|
switch (SecKind) {
|
|
|
|
case PragmaClangSectionKind::PCSK_BSS:
|
|
|
|
CSec = &PragmaClangBSSSection;
|
2020-04-16 20:55:18 +08:00
|
|
|
SectionFlags |= ASTContext::PSF_Write | ASTContext::PSF_ZeroInit;
|
2017-06-05 18:11:57 +08:00
|
|
|
break;
|
|
|
|
case PragmaClangSectionKind::PCSK_Data:
|
|
|
|
CSec = &PragmaClangDataSection;
|
2020-04-16 20:55:18 +08:00
|
|
|
SectionFlags |= ASTContext::PSF_Write;
|
2017-06-05 18:11:57 +08:00
|
|
|
break;
|
|
|
|
case PragmaClangSectionKind::PCSK_Rodata:
|
|
|
|
CSec = &PragmaClangRodataSection;
|
|
|
|
break;
|
2019-10-16 02:31:10 +08:00
|
|
|
case PragmaClangSectionKind::PCSK_Relro:
|
|
|
|
CSec = &PragmaClangRelroSection;
|
|
|
|
break;
|
2017-06-05 18:11:57 +08:00
|
|
|
case PragmaClangSectionKind::PCSK_Text:
|
|
|
|
CSec = &PragmaClangTextSection;
|
2020-04-16 20:55:18 +08:00
|
|
|
SectionFlags |= ASTContext::PSF_Execute;
|
2017-06-05 18:11:57 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
llvm_unreachable("invalid clang section kind");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Action == PragmaClangSectionAction::PCSA_Clear) {
|
|
|
|
CSec->Valid = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-04-16 20:55:18 +08:00
|
|
|
if (UnifySection(SecName, SectionFlags, PragmaLoc))
|
|
|
|
return;
|
|
|
|
|
2017-06-05 18:11:57 +08:00
|
|
|
CSec->Valid = true;
|
2020-01-29 03:23:46 +08:00
|
|
|
CSec->SectionName = std::string(SecName);
|
2017-06-05 18:11:57 +08:00
|
|
|
CSec->PragmaLocation = PragmaLoc;
|
|
|
|
}
|
|
|
|
|
2016-04-30 02:17:40 +08:00
|
|
|
void Sema::ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action,
|
|
|
|
StringRef SlotLabel, Expr *alignment) {
|
2009-02-17 08:57:29 +08:00
|
|
|
Expr *Alignment = static_cast<Expr *>(alignment);
|
|
|
|
|
|
|
|
// If specified then alignment must be a "small" power of two.
|
|
|
|
unsigned AlignmentVal = 0;
|
|
|
|
if (Alignment) {
|
2020-07-13 11:31:08 +08:00
|
|
|
Optional<llvm::APSInt> Val;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-07 04:45:54 +08:00
|
|
|
// pack(0) is like pack(), which just works out since that is what
|
|
|
|
// we use 0 for in PackAttr.
|
2020-07-13 11:31:08 +08:00
|
|
|
if (Alignment->isTypeDependent() || Alignment->isValueDependent() ||
|
|
|
|
!(Val = Alignment->getIntegerConstantExpr(Context)) ||
|
|
|
|
!(*Val == 0 || Val->isPowerOf2()) || Val->getZExtValue() > 16) {
|
2009-02-17 08:57:29 +08:00
|
|
|
Diag(PragmaLoc, diag::warn_pragma_pack_invalid_alignment);
|
|
|
|
return; // Ignore
|
|
|
|
}
|
|
|
|
|
2020-07-13 11:31:08 +08:00
|
|
|
AlignmentVal = (unsigned)Val->getZExtValue();
|
2009-02-17 08:57:29 +08:00
|
|
|
}
|
2016-04-30 02:17:40 +08:00
|
|
|
if (Action == Sema::PSK_Show) {
|
2009-02-17 08:57:29 +08:00
|
|
|
// Show the current alignment, making sure to show the right value
|
|
|
|
// for the default.
|
|
|
|
// FIXME: This should come from the target.
|
2016-04-30 02:17:40 +08:00
|
|
|
AlignmentVal = PackStack.CurrentValue;
|
2009-02-17 08:57:29 +08:00
|
|
|
if (AlignmentVal == 0)
|
|
|
|
AlignmentVal = 8;
|
2016-04-30 02:17:40 +08:00
|
|
|
if (AlignmentVal == Sema::kMac68kAlignmentSentinel)
|
2010-05-27 13:45:51 +08:00
|
|
|
Diag(PragmaLoc, diag::warn_pragma_pack_show) << "mac68k";
|
|
|
|
else
|
|
|
|
Diag(PragmaLoc, diag::warn_pragma_pack_show) << AlignmentVal;
|
2016-04-30 02:17:40 +08:00
|
|
|
}
|
|
|
|
// MSDN, C/C++ Preprocessor Reference > Pragma Directives > pack:
|
|
|
|
// "#pragma pack(pop, identifier, n) is undefined"
|
|
|
|
if (Action & Sema::PSK_Pop) {
|
|
|
|
if (Alignment && !SlotLabel.empty())
|
2018-04-06 23:14:32 +08:00
|
|
|
Diag(PragmaLoc, diag::warn_pragma_pack_pop_identifier_and_alignment);
|
2016-04-30 02:17:40 +08:00
|
|
|
if (PackStack.Stack.empty())
|
|
|
|
Diag(PragmaLoc, diag::warn_pragma_pop_failed) << "pack" << "stack empty";
|
2009-02-17 08:57:29 +08:00
|
|
|
}
|
2016-04-30 02:17:40 +08:00
|
|
|
|
|
|
|
PackStack.Act(PragmaLoc, Action, SlotLabel, AlignmentVal);
|
2009-02-17 08:57:29 +08:00
|
|
|
}
|
|
|
|
|
2017-07-28 22:41:21 +08:00
|
|
|
void Sema::DiagnoseNonDefaultPragmaPack(PragmaPackDiagnoseKind Kind,
|
|
|
|
SourceLocation IncludeLoc) {
|
|
|
|
if (Kind == PragmaPackDiagnoseKind::NonDefaultStateAtInclude) {
|
|
|
|
SourceLocation PrevLocation = PackStack.CurrentPragmaLocation;
|
|
|
|
// Warn about non-default alignment at #includes (without redundant
|
|
|
|
// warnings for the same directive in nested includes).
|
|
|
|
// The warning is delayed until the end of the file to avoid warnings
|
|
|
|
// for files that don't have any records that are affected by the modified
|
|
|
|
// alignment.
|
|
|
|
bool HasNonDefaultValue =
|
|
|
|
PackStack.hasValue() &&
|
|
|
|
(PackIncludeStack.empty() ||
|
|
|
|
PackIncludeStack.back().CurrentPragmaLocation != PrevLocation);
|
|
|
|
PackIncludeStack.push_back(
|
|
|
|
{PackStack.CurrentValue,
|
|
|
|
PackStack.hasValue() ? PrevLocation : SourceLocation(),
|
|
|
|
HasNonDefaultValue, /*ShouldWarnOnInclude*/ false});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(Kind == PragmaPackDiagnoseKind::ChangedStateAtExit && "invalid kind");
|
|
|
|
PackIncludeState PrevPackState = PackIncludeStack.pop_back_val();
|
|
|
|
if (PrevPackState.ShouldWarnOnInclude) {
|
|
|
|
// Emit the delayed non-default alignment at #include warning.
|
|
|
|
Diag(IncludeLoc, diag::warn_pragma_pack_non_default_at_include);
|
|
|
|
Diag(PrevPackState.CurrentPragmaLocation, diag::note_pragma_pack_here);
|
|
|
|
}
|
|
|
|
// Warn about modified alignment after #includes.
|
|
|
|
if (PrevPackState.CurrentValue != PackStack.CurrentValue) {
|
|
|
|
Diag(IncludeLoc, diag::warn_pragma_pack_modified_after_include);
|
|
|
|
Diag(PackStack.CurrentPragmaLocation, diag::note_pragma_pack_here);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Sema::DiagnoseUnterminatedPragmaPack() {
|
|
|
|
if (PackStack.Stack.empty())
|
|
|
|
return;
|
2017-07-31 21:37:50 +08:00
|
|
|
bool IsInnermost = true;
|
|
|
|
for (const auto &StackSlot : llvm::reverse(PackStack.Stack)) {
|
2017-07-28 22:41:21 +08:00
|
|
|
Diag(StackSlot.PragmaPushLocation, diag::warn_pragma_pack_no_pop_eof);
|
2017-07-31 21:37:50 +08:00
|
|
|
// The user might have already reset the alignment, so suggest replacing
|
|
|
|
// the reset with a pop.
|
|
|
|
if (IsInnermost && PackStack.CurrentValue == PackStack.DefaultValue) {
|
|
|
|
DiagnosticBuilder DB = Diag(PackStack.CurrentPragmaLocation,
|
|
|
|
diag::note_pragma_pack_pop_instead_reset);
|
|
|
|
SourceLocation FixItLoc = Lexer::findLocationAfterToken(
|
|
|
|
PackStack.CurrentPragmaLocation, tok::l_paren, SourceMgr, LangOpts,
|
|
|
|
/*SkipTrailing=*/false);
|
|
|
|
if (FixItLoc.isValid())
|
|
|
|
DB << FixItHint::CreateInsertion(FixItLoc, "pop");
|
|
|
|
}
|
|
|
|
IsInnermost = false;
|
|
|
|
}
|
2017-07-28 22:41:21 +08:00
|
|
|
}
|
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
void Sema::ActOnPragmaMSStruct(PragmaMSStructKind Kind) {
|
2011-04-26 02:49:15 +08:00
|
|
|
MSStructPragmaOn = (Kind == PMSST_ON);
|
|
|
|
}
|
|
|
|
|
2016-03-03 01:28:48 +08:00
|
|
|
void Sema::ActOnPragmaMSComment(SourceLocation CommentLoc,
|
|
|
|
PragmaMSCommentKind Kind, StringRef Arg) {
|
|
|
|
auto *PCD = PragmaCommentDecl::Create(
|
|
|
|
Context, Context.getTranslationUnitDecl(), CommentLoc, Kind, Arg);
|
|
|
|
Context.getTranslationUnitDecl()->addDecl(PCD);
|
|
|
|
Consumer.HandleTopLevelDecl(DeclGroupRef(PCD));
|
2013-05-08 21:44:39 +08:00
|
|
|
}
|
|
|
|
|
2016-03-03 03:28:54 +08:00
|
|
|
void Sema::ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name,
|
|
|
|
StringRef Value) {
|
|
|
|
auto *PDMD = PragmaDetectMismatchDecl::Create(
|
|
|
|
Context, Context.getTranslationUnitDecl(), Loc, Name, Value);
|
|
|
|
Context.getTranslationUnitDecl()->addDecl(PDMD);
|
|
|
|
Consumer.HandleTopLevelDecl(DeclGroupRef(PDMD));
|
2013-06-04 10:07:14 +08:00
|
|
|
}
|
|
|
|
|
2020-05-02 01:32:06 +08:00
|
|
|
void Sema::ActOnPragmaFloatControl(SourceLocation Loc,
|
|
|
|
PragmaMsStackAction Action,
|
|
|
|
PragmaFloatControlKind Value) {
|
2020-08-17 07:36:10 +08:00
|
|
|
FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
|
2020-05-02 01:32:06 +08:00
|
|
|
if ((Action == PSK_Push_Set || Action == PSK_Push || Action == PSK_Pop) &&
|
2020-05-08 23:05:34 +08:00
|
|
|
!(CurContext->isTranslationUnit()) && !CurContext->isNamespace()) {
|
|
|
|
// Push and pop can only occur at file or namespace scope.
|
2020-05-02 01:32:06 +08:00
|
|
|
Diag(Loc, diag::err_pragma_fc_pp_scope);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
switch (Value) {
|
|
|
|
default:
|
|
|
|
llvm_unreachable("invalid pragma float_control kind");
|
|
|
|
case PFC_Precise:
|
2020-06-27 00:23:45 +08:00
|
|
|
NewFPFeatures.setFPPreciseEnabled(true);
|
2020-08-17 07:36:10 +08:00
|
|
|
FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures);
|
2020-05-02 01:32:06 +08:00
|
|
|
break;
|
|
|
|
case PFC_NoPrecise:
|
2020-06-27 00:23:45 +08:00
|
|
|
if (CurFPFeatures.getFPExceptionMode() == LangOptions::FPE_Strict)
|
2020-05-02 01:32:06 +08:00
|
|
|
Diag(Loc, diag::err_pragma_fc_noprecise_requires_noexcept);
|
2020-06-27 00:23:45 +08:00
|
|
|
else if (CurFPFeatures.getAllowFEnvAccess())
|
2020-05-02 01:32:06 +08:00
|
|
|
Diag(Loc, diag::err_pragma_fc_noprecise_requires_nofenv);
|
|
|
|
else
|
2020-06-27 00:23:45 +08:00
|
|
|
NewFPFeatures.setFPPreciseEnabled(false);
|
2020-08-17 07:36:10 +08:00
|
|
|
FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures);
|
2020-05-02 01:32:06 +08:00
|
|
|
break;
|
|
|
|
case PFC_Except:
|
|
|
|
if (!isPreciseFPEnabled())
|
|
|
|
Diag(Loc, diag::err_pragma_fc_except_requires_precise);
|
|
|
|
else
|
2020-06-27 00:23:45 +08:00
|
|
|
NewFPFeatures.setFPExceptionModeOverride(LangOptions::FPE_Strict);
|
2020-08-17 07:36:10 +08:00
|
|
|
FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures);
|
2020-05-02 01:32:06 +08:00
|
|
|
break;
|
|
|
|
case PFC_NoExcept:
|
2020-06-27 00:23:45 +08:00
|
|
|
NewFPFeatures.setFPExceptionModeOverride(LangOptions::FPE_Ignore);
|
2020-08-17 07:36:10 +08:00
|
|
|
FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures);
|
2020-05-02 01:32:06 +08:00
|
|
|
break;
|
|
|
|
case PFC_Push:
|
2020-08-17 07:36:10 +08:00
|
|
|
FpPragmaStack.Act(Loc, Sema::PSK_Push_Set, StringRef(), NewFPFeatures);
|
2020-05-02 01:32:06 +08:00
|
|
|
break;
|
|
|
|
case PFC_Pop:
|
|
|
|
if (FpPragmaStack.Stack.empty()) {
|
|
|
|
Diag(Loc, diag::warn_pragma_pop_failed) << "float_control"
|
|
|
|
<< "stack empty";
|
|
|
|
return;
|
|
|
|
}
|
2020-08-17 07:36:10 +08:00
|
|
|
FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures);
|
|
|
|
NewFPFeatures = FpPragmaStack.CurrentValue;
|
2020-05-02 01:32:06 +08:00
|
|
|
break;
|
|
|
|
}
|
2020-08-17 07:36:10 +08:00
|
|
|
CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
|
2020-05-02 01:32:06 +08:00
|
|
|
}
|
|
|
|
|
2014-02-11 03:50:15 +08:00
|
|
|
void Sema::ActOnPragmaMSPointersToMembers(
|
2014-02-12 05:05:00 +08:00
|
|
|
LangOptions::PragmaMSPointersToMembersKind RepresentationMethod,
|
2014-02-11 03:50:15 +08:00
|
|
|
SourceLocation PragmaLoc) {
|
|
|
|
MSPointerToMemberRepresentationMethod = RepresentationMethod;
|
|
|
|
ImplicitMSInheritanceAttrLoc = PragmaLoc;
|
|
|
|
}
|
|
|
|
|
2016-04-29 19:27:00 +08:00
|
|
|
void Sema::ActOnPragmaMSVtorDisp(PragmaMsStackAction Action,
|
2014-02-13 07:50:26 +08:00
|
|
|
SourceLocation PragmaLoc,
|
2019-11-23 06:55:49 +08:00
|
|
|
MSVtorDispMode Mode) {
|
2016-04-29 19:27:00 +08:00
|
|
|
if (Action & PSK_Pop && VtorDispStack.Stack.empty())
|
|
|
|
Diag(PragmaLoc, diag::warn_pragma_pop_failed) << "vtordisp"
|
|
|
|
<< "stack empty";
|
|
|
|
VtorDispStack.Act(PragmaLoc, Action, StringRef(), Mode);
|
2014-02-13 07:50:26 +08:00
|
|
|
}
|
|
|
|
|
2014-08-31 00:55:52 +08:00
|
|
|
bool Sema::UnifySection(StringRef SectionName,
|
2014-04-09 06:30:47 +08:00
|
|
|
int SectionFlags,
|
|
|
|
DeclaratorDecl *Decl) {
|
2020-04-22 00:25:18 +08:00
|
|
|
SourceLocation PragmaLocation;
|
|
|
|
if (auto A = Decl->getAttr<SectionAttr>())
|
|
|
|
if (A->isImplicit())
|
|
|
|
PragmaLocation = A->getLocation();
|
|
|
|
auto SectionIt = Context.SectionInfos.find(SectionName);
|
|
|
|
if (SectionIt == Context.SectionInfos.end()) {
|
2014-10-17 04:52:46 +08:00
|
|
|
Context.SectionInfos[SectionName] =
|
2020-04-22 00:25:18 +08:00
|
|
|
ASTContext::SectionInfo(Decl, PragmaLocation, SectionFlags);
|
2014-04-09 06:30:47 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// A pre-declared section takes precedence w/o diagnostic.
|
2020-04-22 00:25:18 +08:00
|
|
|
const auto &Section = SectionIt->second;
|
|
|
|
if (Section.SectionFlags == SectionFlags ||
|
|
|
|
((SectionFlags & ASTContext::PSF_Implicit) &&
|
|
|
|
!(Section.SectionFlags & ASTContext::PSF_Implicit)))
|
2014-04-09 06:30:47 +08:00
|
|
|
return false;
|
2020-04-22 00:25:18 +08:00
|
|
|
Diag(Decl->getLocation(), diag::err_section_conflict) << Decl << Section;
|
|
|
|
if (Section.Decl)
|
|
|
|
Diag(Section.Decl->getLocation(), diag::note_declared_at)
|
|
|
|
<< Section.Decl->getName();
|
|
|
|
if (PragmaLocation.isValid())
|
|
|
|
Diag(PragmaLocation, diag::note_pragma_entered_here);
|
|
|
|
if (Section.PragmaSectionLocation.isValid())
|
|
|
|
Diag(Section.PragmaSectionLocation, diag::note_pragma_entered_here);
|
2014-09-23 03:46:39 +08:00
|
|
|
return true;
|
2014-04-09 06:30:47 +08:00
|
|
|
}
|
|
|
|
|
2014-08-31 00:55:52 +08:00
|
|
|
bool Sema::UnifySection(StringRef SectionName,
|
2014-04-09 06:30:47 +08:00
|
|
|
int SectionFlags,
|
|
|
|
SourceLocation PragmaSectionLocation) {
|
2020-04-22 00:25:18 +08:00
|
|
|
auto SectionIt = Context.SectionInfos.find(SectionName);
|
|
|
|
if (SectionIt != Context.SectionInfos.end()) {
|
|
|
|
const auto &Section = SectionIt->second;
|
|
|
|
if (Section.SectionFlags == SectionFlags)
|
2014-04-09 06:30:47 +08:00
|
|
|
return false;
|
2020-04-22 00:25:18 +08:00
|
|
|
if (!(Section.SectionFlags & ASTContext::PSF_Implicit)) {
|
2014-04-09 06:30:47 +08:00
|
|
|
Diag(PragmaSectionLocation, diag::err_section_conflict)
|
2020-04-22 00:25:18 +08:00
|
|
|
<< "this" << Section;
|
|
|
|
if (Section.Decl)
|
|
|
|
Diag(Section.Decl->getLocation(), diag::note_declared_at)
|
|
|
|
<< Section.Decl->getName();
|
|
|
|
if (Section.PragmaSectionLocation.isValid())
|
|
|
|
Diag(Section.PragmaSectionLocation, diag::note_pragma_entered_here);
|
2014-04-09 06:30:47 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2014-10-17 04:52:46 +08:00
|
|
|
Context.SectionInfos[SectionName] =
|
|
|
|
ASTContext::SectionInfo(nullptr, PragmaSectionLocation, SectionFlags);
|
2014-04-09 06:30:47 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Called on well formed \#pragma bss_seg().
|
2014-04-09 06:30:47 +08:00
|
|
|
void Sema::ActOnPragmaMSSeg(SourceLocation PragmaLocation,
|
|
|
|
PragmaMsStackAction Action,
|
|
|
|
llvm::StringRef StackSlotLabel,
|
|
|
|
StringLiteral *SegmentName,
|
|
|
|
llvm::StringRef PragmaName) {
|
|
|
|
PragmaStack<StringLiteral *> *Stack =
|
|
|
|
llvm::StringSwitch<PragmaStack<StringLiteral *> *>(PragmaName)
|
|
|
|
.Case("data_seg", &DataSegStack)
|
|
|
|
.Case("bss_seg", &BSSSegStack)
|
|
|
|
.Case("const_seg", &ConstSegStack)
|
|
|
|
.Case("code_seg", &CodeSegStack);
|
|
|
|
if (Action & PSK_Pop && Stack->Stack.empty())
|
|
|
|
Diag(PragmaLocation, diag::warn_pragma_pop_failed) << PragmaName
|
|
|
|
<< "stack empty";
|
2019-07-09 08:02:23 +08:00
|
|
|
if (SegmentName) {
|
|
|
|
if (!checkSectionName(SegmentName->getBeginLoc(), SegmentName->getString()))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (SegmentName->getString() == ".drectve" &&
|
|
|
|
Context.getTargetInfo().getCXXABI().isMicrosoft())
|
|
|
|
Diag(PragmaLocation, diag::warn_attribute_section_drectve) << PragmaName;
|
|
|
|
}
|
|
|
|
|
2014-04-09 06:30:47 +08:00
|
|
|
Stack->Act(PragmaLocation, Action, StackSlotLabel, SegmentName);
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Called on well formed \#pragma bss_seg().
|
2014-04-09 06:30:47 +08:00
|
|
|
void Sema::ActOnPragmaMSSection(SourceLocation PragmaLocation,
|
|
|
|
int SectionFlags, StringLiteral *SegmentName) {
|
|
|
|
UnifySection(SegmentName->getString(), SectionFlags, PragmaLocation);
|
|
|
|
}
|
|
|
|
|
2014-07-22 08:53:05 +08:00
|
|
|
void Sema::ActOnPragmaMSInitSeg(SourceLocation PragmaLocation,
|
|
|
|
StringLiteral *SegmentName) {
|
|
|
|
// There's no stack to maintain, so we just have a current section. When we
|
|
|
|
// see the default section, reset our current section back to null so we stop
|
|
|
|
// tacking on unnecessary attributes.
|
|
|
|
CurInitSeg = SegmentName->getString() == ".CRT$XCU" ? nullptr : SegmentName;
|
|
|
|
CurInitSegLoc = PragmaLocation;
|
|
|
|
}
|
|
|
|
|
2011-01-18 02:58:44 +08:00
|
|
|
void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
|
|
|
|
SourceLocation PragmaLoc) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-01-18 02:58:44 +08:00
|
|
|
IdentifierInfo *Name = IdTok.getIdentifierInfo();
|
|
|
|
LookupResult Lookup(*this, Name, IdTok.getLocation(), LookupOrdinaryName);
|
2014-05-26 14:22:03 +08:00
|
|
|
LookupParsedName(Lookup, curScope, nullptr, true);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-01-18 02:58:44 +08:00
|
|
|
if (Lookup.empty()) {
|
|
|
|
Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var)
|
|
|
|
<< Name << SourceRange(IdTok.getLocation());
|
|
|
|
return;
|
|
|
|
}
|
2010-10-23 07:37:08 +08:00
|
|
|
|
2011-01-18 02:58:44 +08:00
|
|
|
VarDecl *VD = Lookup.getAsSingle<VarDecl>();
|
2011-01-28 02:16:48 +08:00
|
|
|
if (!VD) {
|
|
|
|
Diag(PragmaLoc, diag::warn_pragma_unused_expected_var_arg)
|
2011-01-18 02:58:44 +08:00
|
|
|
<< Name << SourceRange(IdTok.getLocation());
|
|
|
|
return;
|
2009-03-24 06:28:25 +08:00
|
|
|
}
|
2011-01-18 02:58:44 +08:00
|
|
|
|
|
|
|
// Warn if this was used before being marked unused.
|
|
|
|
if (VD->isUsed())
|
|
|
|
Diag(PragmaLoc, diag::warn_used_but_marked_unused) << Name;
|
|
|
|
|
2019-09-14 01:39:31 +08:00
|
|
|
VD->addAttr(UnusedAttr::CreateImplicit(Context, IdTok.getLocation(),
|
|
|
|
AttributeCommonInfo::AS_Pragma,
|
|
|
|
UnusedAttr::GNU_unused));
|
2009-03-24 06:28:25 +08:00
|
|
|
}
|
2010-08-05 14:57:20 +08:00
|
|
|
|
2011-09-30 13:12:12 +08:00
|
|
|
void Sema::AddCFAuditedAttribute(Decl *D) {
|
2019-09-14 01:39:31 +08:00
|
|
|
IdentifierInfo *Ident;
|
|
|
|
SourceLocation Loc;
|
|
|
|
std::tie(Ident, Loc) = PP.getPragmaARCCFCodeAuditedInfo();
|
2011-09-30 13:12:12 +08:00
|
|
|
if (!Loc.isValid()) return;
|
|
|
|
|
|
|
|
// Don't add a redundant or conflicting attribute.
|
|
|
|
if (D->hasAttr<CFAuditedTransferAttr>() ||
|
|
|
|
D->hasAttr<CFUnknownTransferAttr>())
|
|
|
|
return;
|
|
|
|
|
2019-09-14 01:39:31 +08:00
|
|
|
AttributeCommonInfo Info(Ident, SourceRange(Loc),
|
|
|
|
AttributeCommonInfo::AS_Pragma);
|
|
|
|
D->addAttr(CFAuditedTransferAttr::CreateImplicit(Context, Info));
|
2011-09-30 13:12:12 +08:00
|
|
|
}
|
|
|
|
|
2017-04-18 22:33:39 +08:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
Optional<attr::SubjectMatchRule>
|
|
|
|
getParentAttrMatcherRule(attr::SubjectMatchRule Rule) {
|
|
|
|
using namespace attr;
|
|
|
|
switch (Rule) {
|
|
|
|
default:
|
|
|
|
return None;
|
|
|
|
#define ATTR_MATCH_RULE(Value, Spelling, IsAbstract)
|
|
|
|
#define ATTR_MATCH_SUB_RULE(Value, Spelling, IsAbstract, Parent, IsNegated) \
|
|
|
|
case Value: \
|
|
|
|
return Parent;
|
|
|
|
#include "clang/Basic/AttrSubMatchRulesList.inc"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isNegatedAttrMatcherSubRule(attr::SubjectMatchRule Rule) {
|
|
|
|
using namespace attr;
|
|
|
|
switch (Rule) {
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
#define ATTR_MATCH_RULE(Value, Spelling, IsAbstract)
|
|
|
|
#define ATTR_MATCH_SUB_RULE(Value, Spelling, IsAbstract, Parent, IsNegated) \
|
|
|
|
case Value: \
|
|
|
|
return IsNegated;
|
|
|
|
#include "clang/Basic/AttrSubMatchRulesList.inc"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CharSourceRange replacementRangeForListElement(const Sema &S,
|
|
|
|
SourceRange Range) {
|
|
|
|
// Make sure that the ',' is removed as well.
|
|
|
|
SourceLocation AfterCommaLoc = Lexer::findLocationAfterToken(
|
|
|
|
Range.getEnd(), tok::comma, S.getSourceManager(), S.getLangOpts(),
|
|
|
|
/*SkipTrailingWhitespaceAndNewLine=*/false);
|
|
|
|
if (AfterCommaLoc.isValid())
|
|
|
|
return CharSourceRange::getCharRange(Range.getBegin(), AfterCommaLoc);
|
|
|
|
else
|
|
|
|
return CharSourceRange::getTokenRange(Range);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string
|
|
|
|
attrMatcherRuleListToString(ArrayRef<attr::SubjectMatchRule> Rules) {
|
|
|
|
std::string Result;
|
|
|
|
llvm::raw_string_ostream OS(Result);
|
|
|
|
for (const auto &I : llvm::enumerate(Rules)) {
|
|
|
|
if (I.index())
|
|
|
|
OS << (I.index() == Rules.size() - 1 ? ", and " : ", ");
|
|
|
|
OS << "'" << attr::getSubjectMatchRuleSpelling(I.value()) << "'";
|
|
|
|
}
|
|
|
|
return OS.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
2018-10-30 01:38:42 +08:00
|
|
|
void Sema::ActOnPragmaAttributeAttribute(
|
|
|
|
ParsedAttr &Attribute, SourceLocation PragmaLoc,
|
|
|
|
attr::ParsedSubjectMatchRuleSet Rules) {
|
2019-01-25 03:14:39 +08:00
|
|
|
Attribute.setIsPragmaClangAttribute();
|
2017-04-18 22:33:39 +08:00
|
|
|
SmallVector<attr::SubjectMatchRule, 4> SubjectMatchRules;
|
|
|
|
// Gather the subject match rules that are supported by the attribute.
|
|
|
|
SmallVector<std::pair<attr::SubjectMatchRule, bool>, 4>
|
|
|
|
StrictSubjectMatchRuleSet;
|
|
|
|
Attribute.getMatchRules(LangOpts, StrictSubjectMatchRuleSet);
|
|
|
|
|
|
|
|
// Figure out which subject matching rules are valid.
|
|
|
|
if (StrictSubjectMatchRuleSet.empty()) {
|
|
|
|
// Check for contradicting match rules. Contradicting match rules are
|
|
|
|
// either:
|
|
|
|
// - a top-level rule and one of its sub-rules. E.g. variable and
|
|
|
|
// variable(is_parameter).
|
|
|
|
// - a sub-rule and a sibling that's negated. E.g.
|
|
|
|
// variable(is_thread_local) and variable(unless(is_parameter))
|
2017-04-19 04:54:23 +08:00
|
|
|
llvm::SmallDenseMap<int, std::pair<int, SourceRange>, 2>
|
2017-04-18 22:33:39 +08:00
|
|
|
RulesToFirstSpecifiedNegatedSubRule;
|
|
|
|
for (const auto &Rule : Rules) {
|
2017-04-19 04:54:23 +08:00
|
|
|
attr::SubjectMatchRule MatchRule = attr::SubjectMatchRule(Rule.first);
|
2017-04-18 22:33:39 +08:00
|
|
|
Optional<attr::SubjectMatchRule> ParentRule =
|
2017-04-19 04:54:23 +08:00
|
|
|
getParentAttrMatcherRule(MatchRule);
|
2017-04-18 22:33:39 +08:00
|
|
|
if (!ParentRule)
|
|
|
|
continue;
|
|
|
|
auto It = Rules.find(*ParentRule);
|
|
|
|
if (It != Rules.end()) {
|
|
|
|
// A sub-rule contradicts a parent rule.
|
|
|
|
Diag(Rule.second.getBegin(),
|
|
|
|
diag::err_pragma_attribute_matcher_subrule_contradicts_rule)
|
2017-04-19 04:54:23 +08:00
|
|
|
<< attr::getSubjectMatchRuleSpelling(MatchRule)
|
2017-04-18 22:33:39 +08:00
|
|
|
<< attr::getSubjectMatchRuleSpelling(*ParentRule) << It->second
|
|
|
|
<< FixItHint::CreateRemoval(
|
|
|
|
replacementRangeForListElement(*this, Rule.second));
|
|
|
|
// Keep going without removing this rule as it won't change the set of
|
|
|
|
// declarations that receive the attribute.
|
|
|
|
continue;
|
|
|
|
}
|
2017-04-19 04:54:23 +08:00
|
|
|
if (isNegatedAttrMatcherSubRule(MatchRule))
|
2017-04-18 22:33:39 +08:00
|
|
|
RulesToFirstSpecifiedNegatedSubRule.insert(
|
|
|
|
std::make_pair(*ParentRule, Rule));
|
|
|
|
}
|
|
|
|
bool IgnoreNegatedSubRules = false;
|
|
|
|
for (const auto &Rule : Rules) {
|
2017-04-19 04:54:23 +08:00
|
|
|
attr::SubjectMatchRule MatchRule = attr::SubjectMatchRule(Rule.first);
|
2017-04-18 22:33:39 +08:00
|
|
|
Optional<attr::SubjectMatchRule> ParentRule =
|
2017-04-19 04:54:23 +08:00
|
|
|
getParentAttrMatcherRule(MatchRule);
|
2017-04-18 22:33:39 +08:00
|
|
|
if (!ParentRule)
|
|
|
|
continue;
|
|
|
|
auto It = RulesToFirstSpecifiedNegatedSubRule.find(*ParentRule);
|
|
|
|
if (It != RulesToFirstSpecifiedNegatedSubRule.end() &&
|
|
|
|
It->second != Rule) {
|
|
|
|
// Negated sub-rule contradicts another sub-rule.
|
|
|
|
Diag(
|
|
|
|
It->second.second.getBegin(),
|
|
|
|
diag::
|
|
|
|
err_pragma_attribute_matcher_negated_subrule_contradicts_subrule)
|
2017-04-19 04:54:23 +08:00
|
|
|
<< attr::getSubjectMatchRuleSpelling(
|
|
|
|
attr::SubjectMatchRule(It->second.first))
|
|
|
|
<< attr::getSubjectMatchRuleSpelling(MatchRule) << Rule.second
|
2017-04-18 22:33:39 +08:00
|
|
|
<< FixItHint::CreateRemoval(
|
|
|
|
replacementRangeForListElement(*this, It->second.second));
|
|
|
|
// Keep going but ignore all of the negated sub-rules.
|
|
|
|
IgnoreNegatedSubRules = true;
|
|
|
|
RulesToFirstSpecifiedNegatedSubRule.erase(It);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!IgnoreNegatedSubRules) {
|
|
|
|
for (const auto &Rule : Rules)
|
2017-04-19 04:54:23 +08:00
|
|
|
SubjectMatchRules.push_back(attr::SubjectMatchRule(Rule.first));
|
2017-04-18 22:33:39 +08:00
|
|
|
} else {
|
|
|
|
for (const auto &Rule : Rules) {
|
2017-04-19 04:54:23 +08:00
|
|
|
if (!isNegatedAttrMatcherSubRule(attr::SubjectMatchRule(Rule.first)))
|
|
|
|
SubjectMatchRules.push_back(attr::SubjectMatchRule(Rule.first));
|
2017-04-18 22:33:39 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Rules.clear();
|
|
|
|
} else {
|
|
|
|
for (const auto &Rule : StrictSubjectMatchRuleSet) {
|
|
|
|
if (Rules.erase(Rule.first)) {
|
|
|
|
// Add the rule to the set of attribute receivers only if it's supported
|
|
|
|
// in the current language mode.
|
|
|
|
if (Rule.second)
|
|
|
|
SubjectMatchRules.push_back(Rule.first);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Rules.empty()) {
|
|
|
|
auto Diagnostic =
|
|
|
|
Diag(PragmaLoc, diag::err_pragma_attribute_invalid_matchers)
|
2019-09-14 01:39:31 +08:00
|
|
|
<< Attribute;
|
2017-04-18 22:33:39 +08:00
|
|
|
SmallVector<attr::SubjectMatchRule, 2> ExtraRules;
|
|
|
|
for (const auto &Rule : Rules) {
|
2017-04-19 04:54:23 +08:00
|
|
|
ExtraRules.push_back(attr::SubjectMatchRule(Rule.first));
|
2017-04-18 22:33:39 +08:00
|
|
|
Diagnostic << FixItHint::CreateRemoval(
|
|
|
|
replacementRangeForListElement(*this, Rule.second));
|
|
|
|
}
|
|
|
|
Diagnostic << attrMatcherRuleListToString(ExtraRules);
|
|
|
|
}
|
|
|
|
|
2018-10-30 01:38:42 +08:00
|
|
|
if (PragmaAttributeStack.empty()) {
|
|
|
|
Diag(PragmaLoc, diag::err_pragma_attr_attr_no_push);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
PragmaAttributeStack.back().Entries.push_back(
|
2017-04-18 22:33:39 +08:00
|
|
|
{PragmaLoc, &Attribute, std::move(SubjectMatchRules), /*IsUsed=*/false});
|
|
|
|
}
|
|
|
|
|
2018-12-21 06:32:04 +08:00
|
|
|
void Sema::ActOnPragmaAttributeEmptyPush(SourceLocation PragmaLoc,
|
|
|
|
const IdentifierInfo *Namespace) {
|
2018-10-30 01:38:42 +08:00
|
|
|
PragmaAttributeStack.emplace_back();
|
|
|
|
PragmaAttributeStack.back().Loc = PragmaLoc;
|
2018-12-21 06:32:04 +08:00
|
|
|
PragmaAttributeStack.back().Namespace = Namespace;
|
2018-10-30 01:38:42 +08:00
|
|
|
}
|
|
|
|
|
2018-12-21 06:32:04 +08:00
|
|
|
void Sema::ActOnPragmaAttributePop(SourceLocation PragmaLoc,
|
|
|
|
const IdentifierInfo *Namespace) {
|
2017-04-18 22:33:39 +08:00
|
|
|
if (PragmaAttributeStack.empty()) {
|
2018-12-21 06:32:04 +08:00
|
|
|
Diag(PragmaLoc, diag::err_pragma_attribute_stack_mismatch) << 1;
|
2017-04-18 22:33:39 +08:00
|
|
|
return;
|
|
|
|
}
|
2018-10-30 01:38:42 +08:00
|
|
|
|
2018-12-21 06:32:04 +08:00
|
|
|
// Dig back through the stack trying to find the most recently pushed group
|
|
|
|
// that in Namespace. Note that this works fine if no namespace is present,
|
|
|
|
// think of push/pops without namespaces as having an implicit "nullptr"
|
|
|
|
// namespace.
|
|
|
|
for (size_t Index = PragmaAttributeStack.size(); Index;) {
|
|
|
|
--Index;
|
|
|
|
if (PragmaAttributeStack[Index].Namespace == Namespace) {
|
|
|
|
for (const PragmaAttributeEntry &Entry :
|
|
|
|
PragmaAttributeStack[Index].Entries) {
|
|
|
|
if (!Entry.IsUsed) {
|
|
|
|
assert(Entry.Attribute && "Expected an attribute");
|
|
|
|
Diag(Entry.Attribute->getLoc(), diag::warn_pragma_attribute_unused)
|
|
|
|
<< *Entry.Attribute;
|
|
|
|
Diag(PragmaLoc, diag::note_pragma_attribute_region_ends_here);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PragmaAttributeStack.erase(PragmaAttributeStack.begin() + Index);
|
|
|
|
return;
|
2018-10-30 01:38:42 +08:00
|
|
|
}
|
2017-04-18 22:33:39 +08:00
|
|
|
}
|
2018-10-30 01:38:42 +08:00
|
|
|
|
2018-12-21 06:32:04 +08:00
|
|
|
if (Namespace)
|
|
|
|
Diag(PragmaLoc, diag::err_pragma_attribute_stack_mismatch)
|
|
|
|
<< 0 << Namespace->getName();
|
|
|
|
else
|
|
|
|
Diag(PragmaLoc, diag::err_pragma_attribute_stack_mismatch) << 1;
|
2017-04-18 22:33:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Sema::AddPragmaAttributes(Scope *S, Decl *D) {
|
|
|
|
if (PragmaAttributeStack.empty())
|
|
|
|
return;
|
2018-10-30 01:38:42 +08:00
|
|
|
for (auto &Group : PragmaAttributeStack) {
|
|
|
|
for (auto &Entry : Group.Entries) {
|
|
|
|
ParsedAttr *Attribute = Entry.Attribute;
|
|
|
|
assert(Attribute && "Expected an attribute");
|
2019-01-25 03:14:39 +08:00
|
|
|
assert(Attribute->isPragmaClangAttribute() &&
|
|
|
|
"expected #pragma clang attribute");
|
2018-10-30 01:38:42 +08:00
|
|
|
|
|
|
|
// Ensure that the attribute can be applied to the given declaration.
|
|
|
|
bool Applies = false;
|
|
|
|
for (const auto &Rule : Entry.MatchRules) {
|
|
|
|
if (Attribute->appliesToDecl(D, Rule)) {
|
|
|
|
Applies = true;
|
|
|
|
break;
|
|
|
|
}
|
2017-04-18 22:33:39 +08:00
|
|
|
}
|
2018-10-30 01:38:42 +08:00
|
|
|
if (!Applies)
|
|
|
|
continue;
|
|
|
|
Entry.IsUsed = true;
|
|
|
|
PragmaAttributeCurrentTargetDecl = D;
|
|
|
|
ParsedAttributesView Attrs;
|
|
|
|
Attrs.addAtEnd(Attribute);
|
|
|
|
ProcessDeclAttributeList(S, D, Attrs);
|
|
|
|
PragmaAttributeCurrentTargetDecl = nullptr;
|
2017-04-18 22:33:39 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Sema::PrintPragmaAttributeInstantiationPoint() {
|
|
|
|
assert(PragmaAttributeCurrentTargetDecl && "Expected an active declaration");
|
2018-08-10 05:08:08 +08:00
|
|
|
Diags.Report(PragmaAttributeCurrentTargetDecl->getBeginLoc(),
|
2017-04-18 22:33:39 +08:00
|
|
|
diag::note_pragma_attribute_applied_decl_here);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Sema::DiagnoseUnterminatedPragmaAttribute() {
|
|
|
|
if (PragmaAttributeStack.empty())
|
|
|
|
return;
|
|
|
|
Diag(PragmaAttributeStack.back().Loc, diag::err_pragma_attribute_no_pop_eof);
|
|
|
|
}
|
|
|
|
|
2014-05-23 20:13:25 +08:00
|
|
|
void Sema::ActOnPragmaOptimize(bool On, SourceLocation PragmaLoc) {
|
|
|
|
if(On)
|
|
|
|
OptimizeOffPragmaLocation = SourceLocation();
|
|
|
|
else
|
|
|
|
OptimizeOffPragmaLocation = PragmaLoc;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Sema::AddRangeBasedOptnone(FunctionDecl *FD) {
|
|
|
|
// In the future, check other pragmas if they're implemented (e.g. pragma
|
|
|
|
// optimize 0 will probably map to this functionality too).
|
|
|
|
if(OptimizeOffPragmaLocation.isValid())
|
|
|
|
AddOptnoneAttributeIfNoConflicts(FD, OptimizeOffPragmaLocation);
|
|
|
|
}
|
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
void Sema::AddOptnoneAttributeIfNoConflicts(FunctionDecl *FD,
|
2014-05-23 20:13:25 +08:00
|
|
|
SourceLocation Loc) {
|
|
|
|
// Don't add a conflicting attribute. No diagnostic is needed.
|
|
|
|
if (FD->hasAttr<MinSizeAttr>() || FD->hasAttr<AlwaysInlineAttr>())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Add attributes only if required. Optnone requires noinline as well, but if
|
|
|
|
// either is already present then don't bother adding them.
|
|
|
|
if (!FD->hasAttr<OptimizeNoneAttr>())
|
|
|
|
FD->addAttr(OptimizeNoneAttr::CreateImplicit(Context, Loc));
|
|
|
|
if (!FD->hasAttr<NoInlineAttr>())
|
|
|
|
FD->addAttr(NoInlineAttr::CreateImplicit(Context, Loc));
|
|
|
|
}
|
|
|
|
|
2010-12-10 10:59:44 +08:00
|
|
|
typedef std::vector<std::pair<unsigned, SourceLocation> > VisStack;
|
2014-03-02 11:20:16 +08:00
|
|
|
enum : unsigned { NoVisibility = ~0U };
|
2010-08-05 14:57:20 +08:00
|
|
|
|
|
|
|
void Sema::AddPushedVisibilityAttribute(Decl *D) {
|
|
|
|
if (!VisContext)
|
|
|
|
return;
|
|
|
|
|
2012-12-25 15:31:49 +08:00
|
|
|
NamedDecl *ND = dyn_cast<NamedDecl>(D);
|
2013-02-20 09:54:26 +08:00
|
|
|
if (ND && ND->getExplicitVisibility(NamedDecl::VisibilityForValue))
|
2010-08-05 14:57:20 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
VisStack *Stack = static_cast<VisStack*>(VisContext);
|
2010-12-10 10:59:44 +08:00
|
|
|
unsigned rawType = Stack->back().first;
|
|
|
|
if (rawType == NoVisibility) return;
|
|
|
|
|
|
|
|
VisibilityAttr::VisibilityType type
|
|
|
|
= (VisibilityAttr::VisibilityType) rawType;
|
2010-08-19 07:23:40 +08:00
|
|
|
SourceLocation loc = Stack->back().second;
|
2010-08-05 14:57:20 +08:00
|
|
|
|
2014-01-16 21:03:14 +08:00
|
|
|
D->addAttr(VisibilityAttr::CreateImplicit(Context, type, loc));
|
2010-08-05 14:57:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// FreeVisContext - Deallocate and null out VisContext.
|
|
|
|
void Sema::FreeVisContext() {
|
|
|
|
delete static_cast<VisStack*>(VisContext);
|
2014-05-26 14:22:03 +08:00
|
|
|
VisContext = nullptr;
|
2010-08-05 14:57:20 +08:00
|
|
|
}
|
|
|
|
|
2010-12-10 10:59:44 +08:00
|
|
|
static void PushPragmaVisibility(Sema &S, unsigned type, SourceLocation loc) {
|
2010-08-26 17:15:37 +08:00
|
|
|
// Put visibility on stack.
|
|
|
|
if (!S.VisContext)
|
|
|
|
S.VisContext = new VisStack;
|
|
|
|
|
|
|
|
VisStack *Stack = static_cast<VisStack*>(S.VisContext);
|
|
|
|
Stack->push_back(std::make_pair(type, loc));
|
|
|
|
}
|
|
|
|
|
2012-01-21 13:43:40 +08:00
|
|
|
void Sema::ActOnPragmaVisibility(const IdentifierInfo* VisType,
|
2010-08-05 14:57:20 +08:00
|
|
|
SourceLocation PragmaLoc) {
|
2012-01-21 13:43:40 +08:00
|
|
|
if (VisType) {
|
2010-08-05 14:57:20 +08:00
|
|
|
// Compute visibility to use.
|
2013-09-12 03:47:58 +08:00
|
|
|
VisibilityAttr::VisibilityType T;
|
|
|
|
if (!VisibilityAttr::ConvertStrToVisibilityType(VisType->getName(), T)) {
|
|
|
|
Diag(PragmaLoc, diag::warn_attribute_unknown_visibility) << VisType;
|
2010-08-05 14:57:20 +08:00
|
|
|
return;
|
|
|
|
}
|
2013-09-12 03:47:58 +08:00
|
|
|
PushPragmaVisibility(*this, T, PragmaLoc);
|
2010-08-05 14:57:20 +08:00
|
|
|
} else {
|
2012-02-02 07:24:59 +08:00
|
|
|
PopPragmaVisibility(false, PragmaLoc);
|
2010-08-05 14:57:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-27 00:23:45 +08:00
|
|
|
void Sema::ActOnPragmaFPContract(SourceLocation Loc,
|
|
|
|
LangOptions::FPModeKind FPC) {
|
2020-08-17 07:36:10 +08:00
|
|
|
FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
|
2017-04-05 05:18:36 +08:00
|
|
|
switch (FPC) {
|
2020-05-05 01:48:12 +08:00
|
|
|
case LangOptions::FPM_On:
|
2020-06-27 00:23:45 +08:00
|
|
|
NewFPFeatures.setAllowFPContractWithinStatement();
|
2011-02-14 09:42:35 +08:00
|
|
|
break;
|
2020-05-05 01:48:12 +08:00
|
|
|
case LangOptions::FPM_Fast:
|
2020-06-27 00:23:45 +08:00
|
|
|
NewFPFeatures.setAllowFPContractAcrossStatement();
|
2011-02-14 09:42:35 +08:00
|
|
|
break;
|
2020-05-05 01:48:12 +08:00
|
|
|
case LangOptions::FPM_Off:
|
2020-06-27 00:23:45 +08:00
|
|
|
NewFPFeatures.setDisallowFPContract();
|
2011-02-14 09:42:35 +08:00
|
|
|
break;
|
|
|
|
}
|
2020-08-17 07:36:10 +08:00
|
|
|
FpPragmaStack.Act(Loc, Sema::PSK_Set, StringRef(), NewFPFeatures);
|
2020-06-27 00:23:45 +08:00
|
|
|
CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
|
2011-02-14 09:42:35 +08:00
|
|
|
}
|
|
|
|
|
2020-06-27 00:23:45 +08:00
|
|
|
void Sema::ActOnPragmaFPReassociate(SourceLocation Loc, bool IsEnabled) {
|
2020-08-17 07:36:10 +08:00
|
|
|
FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
|
2020-06-27 00:23:45 +08:00
|
|
|
NewFPFeatures.setAllowFPReassociateOverride(IsEnabled);
|
2020-08-17 07:36:10 +08:00
|
|
|
FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures);
|
|
|
|
CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
|
2020-05-05 01:48:12 +08:00
|
|
|
}
|
|
|
|
|
2020-06-27 00:23:45 +08:00
|
|
|
void Sema::setRoundingMode(SourceLocation Loc, llvm::RoundingMode FPR) {
|
2020-08-24 15:02:26 +08:00
|
|
|
// C2x: 7.6.2p3 If the FE_DYNAMIC mode is specified and FENV_ACCESS is "off",
|
|
|
|
// the translator may assume that the default rounding mode is in effect.
|
|
|
|
if (FPR == llvm::RoundingMode::Dynamic && !CurFPFeatures.getAllowFEnvAccess())
|
|
|
|
FPR = llvm::RoundingMode::NearestTiesToEven;
|
|
|
|
|
2020-08-17 07:36:10 +08:00
|
|
|
FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
|
2020-06-27 00:23:45 +08:00
|
|
|
NewFPFeatures.setRoundingModeOverride(FPR);
|
2020-08-17 07:36:10 +08:00
|
|
|
FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures);
|
|
|
|
CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
|
2019-08-08 00:31:26 +08:00
|
|
|
}
|
|
|
|
|
2020-06-27 00:23:45 +08:00
|
|
|
void Sema::setExceptionMode(SourceLocation Loc,
|
|
|
|
LangOptions::FPExceptionModeKind FPE) {
|
2020-08-17 07:36:10 +08:00
|
|
|
FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
|
2020-06-27 00:23:45 +08:00
|
|
|
NewFPFeatures.setFPExceptionModeOverride(FPE);
|
2020-08-17 07:36:10 +08:00
|
|
|
FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures);
|
|
|
|
CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
|
2019-08-08 00:31:26 +08:00
|
|
|
}
|
|
|
|
|
2020-05-05 01:48:12 +08:00
|
|
|
void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled) {
|
2020-08-17 07:36:10 +08:00
|
|
|
FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
|
2020-05-05 01:48:12 +08:00
|
|
|
if (IsEnabled) {
|
2020-05-02 01:32:06 +08:00
|
|
|
// Verify Microsoft restriction:
|
|
|
|
// You can't enable fenv_access unless precise semantics are enabled.
|
|
|
|
// Precise semantics can be enabled either by the float_control
|
|
|
|
// pragma, or by using the /fp:precise or /fp:strict compiler options
|
|
|
|
if (!isPreciseFPEnabled())
|
|
|
|
Diag(Loc, diag::err_pragma_fenv_requires_precise);
|
2020-06-27 00:23:45 +08:00
|
|
|
NewFPFeatures.setAllowFEnvAccessOverride(true);
|
2020-05-05 01:48:12 +08:00
|
|
|
} else
|
2020-06-27 00:23:45 +08:00
|
|
|
NewFPFeatures.setAllowFEnvAccessOverride(false);
|
2020-08-17 07:36:10 +08:00
|
|
|
FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures);
|
|
|
|
CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
|
2018-08-15 01:06:56 +08:00
|
|
|
}
|
|
|
|
|
2012-02-02 07:24:59 +08:00
|
|
|
void Sema::PushNamespaceVisibilityAttr(const VisibilityAttr *Attr,
|
|
|
|
SourceLocation Loc) {
|
2010-12-10 10:59:44 +08:00
|
|
|
// Visibility calculations will consider the namespace's visibility.
|
|
|
|
// Here we just want to note that we're in a visibility context
|
|
|
|
// which overrides any enclosing #pragma context, but doesn't itself
|
|
|
|
// contribute visibility.
|
2012-02-02 07:24:59 +08:00
|
|
|
PushPragmaVisibility(*this, NoVisibility, Loc);
|
2010-08-05 14:57:20 +08:00
|
|
|
}
|
|
|
|
|
2012-02-02 07:24:59 +08:00
|
|
|
void Sema::PopPragmaVisibility(bool IsNamespaceEnd, SourceLocation EndLoc) {
|
|
|
|
if (!VisContext) {
|
|
|
|
Diag(EndLoc, diag::err_pragma_pop_visibility_mismatch);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pop visibility from stack
|
|
|
|
VisStack *Stack = static_cast<VisStack*>(VisContext);
|
2010-08-05 14:57:20 +08:00
|
|
|
|
2012-02-02 07:24:59 +08:00
|
|
|
const std::pair<unsigned, SourceLocation> *Back = &Stack->back();
|
|
|
|
bool StartsWithPragma = Back->first != NoVisibility;
|
|
|
|
if (StartsWithPragma && IsNamespaceEnd) {
|
|
|
|
Diag(Back->second, diag::err_pragma_push_visibility_mismatch);
|
|
|
|
Diag(EndLoc, diag::note_surrounding_namespace_ends_here);
|
|
|
|
|
|
|
|
// For better error recovery, eat all pushes inside the namespace.
|
|
|
|
do {
|
|
|
|
Stack->pop_back();
|
|
|
|
Back = &Stack->back();
|
|
|
|
StartsWithPragma = Back->first != NoVisibility;
|
|
|
|
} while (StartsWithPragma);
|
|
|
|
} else if (!StartsWithPragma && !IsNamespaceEnd) {
|
|
|
|
Diag(EndLoc, diag::err_pragma_pop_visibility_mismatch);
|
|
|
|
Diag(Back->second, diag::note_surrounding_namespace_starts_here);
|
|
|
|
return;
|
2010-08-05 14:57:20 +08:00
|
|
|
}
|
2012-02-02 07:24:59 +08:00
|
|
|
|
|
|
|
Stack->pop_back();
|
|
|
|
// To simplify the implementation, never keep around an empty stack.
|
|
|
|
if (Stack->empty())
|
|
|
|
FreeVisContext();
|
2010-08-05 14:57:20 +08:00
|
|
|
}
|