summaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaAttr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/SemaAttr.cpp')
-rw-r--r--clang/lib/Sema/SemaAttr.cpp426
1 files changed, 426 insertions, 0 deletions
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
new file mode 100644
index 0000000..e935fc7
--- /dev/null
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -0,0 +1,426 @@
+//===--- SemaAttr.cpp - Semantic Analysis for Attributes ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for non-trivial attributes and
+// pragmas.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/Expr.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/Preprocessor.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Pragma 'pack' and 'options align'
+//===----------------------------------------------------------------------===//
+
+namespace {
+ struct PackStackEntry {
+ // We just use a sentinel to represent when the stack is set to mac68k
+ // alignment.
+ static const unsigned kMac68kAlignmentSentinel = ~0U;
+
+ unsigned Alignment;
+ IdentifierInfo *Name;
+ };
+
+ /// PragmaPackStack - Simple class to wrap the stack used by #pragma
+ /// pack.
+ class PragmaPackStack {
+ typedef std::vector<PackStackEntry> stack_ty;
+
+ /// Alignment - The current user specified alignment.
+ unsigned Alignment;
+
+ /// Stack - Entries in the #pragma pack stack, consisting of saved
+ /// alignments and optional names.
+ stack_ty Stack;
+
+ public:
+ PragmaPackStack() : Alignment(0) {}
+
+ void setAlignment(unsigned A) { Alignment = A; }
+ unsigned getAlignment() { return Alignment; }
+
+ /// push - Push the current alignment onto the stack, optionally
+ /// using the given \arg Name for the record, if non-zero.
+ void push(IdentifierInfo *Name) {
+ PackStackEntry PSE = { Alignment, Name };
+ Stack.push_back(PSE);
+ }
+
+ /// pop - Pop a record from the stack and restore the current
+ /// alignment to the previous value. If \arg Name is non-zero then
+ /// the first such named record is popped, otherwise the top record
+ /// is popped. Returns true if the pop succeeded.
+ bool pop(IdentifierInfo *Name, bool IsReset);
+ };
+} // end anonymous namespace.
+
+bool PragmaPackStack::pop(IdentifierInfo *Name, bool IsReset) {
+ // If name is empty just pop top.
+ if (!Name) {
+ // An empty stack is a special case...
+ if (Stack.empty()) {
+ // If this isn't a reset, it is always an error.
+ if (!IsReset)
+ return false;
+
+ // Otherwise, it is an error only if some alignment has been set.
+ if (!Alignment)
+ return false;
+
+ // Otherwise, reset to the default alignment.
+ Alignment = 0;
+ } else {
+ Alignment = Stack.back().Alignment;
+ Stack.pop_back();
+ }
+
+ return true;
+ }
+
+ // Otherwise, find the named record.
+ for (unsigned i = Stack.size(); i != 0; ) {
+ --i;
+ if (Stack[i].Name == Name) {
+ // Found it, pop up to and including this record.
+ Alignment = Stack[i].Alignment;
+ Stack.erase(Stack.begin() + i, Stack.end());
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+/// FreePackedContext - Deallocate and null out PackContext.
+void Sema::FreePackedContext() {
+ delete static_cast<PragmaPackStack*>(PackContext);
+ PackContext = 0;
+}
+
+void Sema::AddAlignmentAttributesForRecord(RecordDecl *RD) {
+ // If there is no pack context, we don't need any attributes.
+ if (!PackContext)
+ return;
+
+ PragmaPackStack *Stack = static_cast<PragmaPackStack*>(PackContext);
+
+ // Otherwise, check to see if we need a max field alignment attribute.
+ if (unsigned Alignment = Stack->getAlignment()) {
+ if (Alignment == PackStackEntry::kMac68kAlignmentSentinel)
+ RD->addAttr(::new (Context) AlignMac68kAttr(SourceLocation(), Context));
+ else
+ RD->addAttr(::new (Context) MaxFieldAlignmentAttr(SourceLocation(),
+ Context,
+ Alignment * 8));
+ }
+}
+
+void Sema::AddMsStructLayoutForRecord(RecordDecl *RD) {
+ if (!MSStructPragmaOn)
+ return;
+ RD->addAttr(::new (Context) MsStructAttr(SourceLocation(), Context));
+}
+
+void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
+ SourceLocation PragmaLoc,
+ SourceLocation KindLoc) {
+ if (PackContext == 0)
+ PackContext = new PragmaPackStack();
+
+ PragmaPackStack *Context = static_cast<PragmaPackStack*>(PackContext);
+
+ // Reset just pops the top of the stack, or resets the current alignment to
+ // default.
+ if (Kind == Sema::POAK_Reset) {
+ if (!Context->pop(0, /*IsReset=*/true)) {
+ Diag(PragmaLoc, diag::warn_pragma_options_align_reset_failed)
+ << "stack empty";
+ }
+ return;
+ }
+
+ switch (Kind) {
+ // For all targets we support native and natural are the same.
+ //
+ // FIXME: This is not true on Darwin/PPC.
+ case POAK_Native:
+ case POAK_Power:
+ case POAK_Natural:
+ Context->push(0);
+ Context->setAlignment(0);
+ break;
+
+ // Note that '#pragma options align=packed' is not equivalent to attribute
+ // packed, it has a different precedence relative to attribute aligned.
+ case POAK_Packed:
+ Context->push(0);
+ Context->setAlignment(1);
+ break;
+
+ case POAK_Mac68k:
+ // Check if the target supports this.
+ if (!PP.getTargetInfo().hasAlignMac68kSupport()) {
+ Diag(PragmaLoc, diag::err_pragma_options_align_mac68k_target_unsupported);
+ return;
+ }
+ Context->push(0);
+ Context->setAlignment(PackStackEntry::kMac68kAlignmentSentinel);
+ break;
+
+ default:
+ Diag(PragmaLoc, diag::warn_pragma_options_align_unsupported_option)
+ << KindLoc;
+ break;
+ }
+}
+
+void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
+ Expr *alignment, SourceLocation PragmaLoc,
+ SourceLocation LParenLoc, SourceLocation RParenLoc) {
+ Expr *Alignment = static_cast<Expr *>(alignment);
+
+ // If specified then alignment must be a "small" power of two.
+ unsigned AlignmentVal = 0;
+ if (Alignment) {
+ llvm::APSInt Val;
+
+ // pack(0) is like pack(), which just works out since that is what
+ // we use 0 for in PackAttr.
+ if (Alignment->isTypeDependent() ||
+ Alignment->isValueDependent() ||
+ !Alignment->isIntegerConstantExpr(Val, Context) ||
+ !(Val == 0 || Val.isPowerOf2()) ||
+ Val.getZExtValue() > 16) {
+ Diag(PragmaLoc, diag::warn_pragma_pack_invalid_alignment);
+ return; // Ignore
+ }
+
+ AlignmentVal = (unsigned) Val.getZExtValue();
+ }
+
+ if (PackContext == 0)
+ PackContext = new PragmaPackStack();
+
+ PragmaPackStack *Context = static_cast<PragmaPackStack*>(PackContext);
+
+ switch (Kind) {
+ case Sema::PPK_Default: // pack([n])
+ Context->setAlignment(AlignmentVal);
+ break;
+
+ case Sema::PPK_Show: // pack(show)
+ // Show the current alignment, making sure to show the right value
+ // for the default.
+ AlignmentVal = Context->getAlignment();
+ // FIXME: This should come from the target.
+ if (AlignmentVal == 0)
+ AlignmentVal = 8;
+ if (AlignmentVal == PackStackEntry::kMac68kAlignmentSentinel)
+ Diag(PragmaLoc, diag::warn_pragma_pack_show) << "mac68k";
+ else
+ Diag(PragmaLoc, diag::warn_pragma_pack_show) << AlignmentVal;
+ break;
+
+ case Sema::PPK_Push: // pack(push [, id] [, [n])
+ Context->push(Name);
+ // Set the new alignment if specified.
+ if (Alignment)
+ Context->setAlignment(AlignmentVal);
+ break;
+
+ case Sema::PPK_Pop: // pack(pop [, id] [, n])
+ // MSDN, C/C++ Preprocessor Reference > Pragma Directives > pack:
+ // "#pragma pack(pop, identifier, n) is undefined"
+ if (Alignment && Name)
+ Diag(PragmaLoc, diag::warn_pragma_pack_pop_identifer_and_alignment);
+
+ // Do the pop.
+ if (!Context->pop(Name, /*IsReset=*/false)) {
+ // If a name was specified then failure indicates the name
+ // wasn't found. Otherwise failure indicates the stack was
+ // empty.
+ Diag(PragmaLoc, diag::warn_pragma_pack_pop_failed)
+ << (Name ? "no record matching name" : "stack empty");
+
+ // FIXME: Warn about popping named records as MSVC does.
+ } else {
+ // Pop succeeded, set the new alignment if specified.
+ if (Alignment)
+ Context->setAlignment(AlignmentVal);
+ }
+ break;
+ }
+}
+
+void Sema::ActOnPragmaMSStruct(PragmaMSStructKind Kind) {
+ MSStructPragmaOn = (Kind == PMSST_ON);
+}
+
+void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
+ SourceLocation PragmaLoc) {
+
+ IdentifierInfo *Name = IdTok.getIdentifierInfo();
+ LookupResult Lookup(*this, Name, IdTok.getLocation(), LookupOrdinaryName);
+ LookupParsedName(Lookup, curScope, NULL, true);
+
+ if (Lookup.empty()) {
+ Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var)
+ << Name << SourceRange(IdTok.getLocation());
+ return;
+ }
+
+ VarDecl *VD = Lookup.getAsSingle<VarDecl>();
+ if (!VD) {
+ Diag(PragmaLoc, diag::warn_pragma_unused_expected_var_arg)
+ << Name << SourceRange(IdTok.getLocation());
+ return;
+ }
+
+ // Warn if this was used before being marked unused.
+ if (VD->isUsed())
+ Diag(PragmaLoc, diag::warn_used_but_marked_unused) << Name;
+
+ VD->addAttr(::new (Context) UnusedAttr(IdTok.getLocation(), Context));
+}
+
+void Sema::AddCFAuditedAttribute(Decl *D) {
+ SourceLocation Loc = PP.getPragmaARCCFCodeAuditedLoc();
+ if (!Loc.isValid()) return;
+
+ // Don't add a redundant or conflicting attribute.
+ if (D->hasAttr<CFAuditedTransferAttr>() ||
+ D->hasAttr<CFUnknownTransferAttr>())
+ return;
+
+ D->addAttr(::new (Context) CFAuditedTransferAttr(Loc, Context));
+}
+
+typedef std::vector<std::pair<unsigned, SourceLocation> > VisStack;
+enum { NoVisibility = (unsigned) -1 };
+
+void Sema::AddPushedVisibilityAttribute(Decl *D) {
+ if (!VisContext)
+ return;
+
+ if (isa<NamedDecl>(D) && cast<NamedDecl>(D)->getExplicitVisibility())
+ return;
+
+ VisStack *Stack = static_cast<VisStack*>(VisContext);
+ unsigned rawType = Stack->back().first;
+ if (rawType == NoVisibility) return;
+
+ VisibilityAttr::VisibilityType type
+ = (VisibilityAttr::VisibilityType) rawType;
+ SourceLocation loc = Stack->back().second;
+
+ D->addAttr(::new (Context) VisibilityAttr(loc, Context, type));
+}
+
+/// FreeVisContext - Deallocate and null out VisContext.
+void Sema::FreeVisContext() {
+ delete static_cast<VisStack*>(VisContext);
+ VisContext = 0;
+}
+
+static void PushPragmaVisibility(Sema &S, unsigned type, SourceLocation loc) {
+ // 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));
+}
+
+void Sema::ActOnPragmaVisibility(const IdentifierInfo* VisType,
+ SourceLocation PragmaLoc) {
+ if (VisType) {
+ // Compute visibility to use.
+ VisibilityAttr::VisibilityType type;
+ if (VisType->isStr("default"))
+ type = VisibilityAttr::Default;
+ else if (VisType->isStr("hidden"))
+ type = VisibilityAttr::Hidden;
+ else if (VisType->isStr("internal"))
+ type = VisibilityAttr::Hidden; // FIXME
+ else if (VisType->isStr("protected"))
+ type = VisibilityAttr::Protected;
+ else {
+ Diag(PragmaLoc, diag::warn_attribute_unknown_visibility) <<
+ VisType->getName();
+ return;
+ }
+ PushPragmaVisibility(*this, type, PragmaLoc);
+ } else {
+ PopPragmaVisibility(false, PragmaLoc);
+ }
+}
+
+void Sema::ActOnPragmaFPContract(tok::OnOffSwitch OOS) {
+ switch (OOS) {
+ case tok::OOS_ON:
+ FPFeatures.fp_contract = 1;
+ break;
+ case tok::OOS_OFF:
+ FPFeatures.fp_contract = 0;
+ break;
+ case tok::OOS_DEFAULT:
+ FPFeatures.fp_contract = getLangOpts().DefaultFPContract;
+ break;
+ }
+}
+
+void Sema::PushNamespaceVisibilityAttr(const VisibilityAttr *Attr,
+ SourceLocation Loc) {
+ // 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.
+ PushPragmaVisibility(*this, NoVisibility, Loc);
+}
+
+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);
+
+ 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;
+ }
+
+ Stack->pop_back();
+ // To simplify the implementation, never keep around an empty stack.
+ if (Stack->empty())
+ FreeVisContext();
+}