summaryrefslogtreecommitdiffstats
path: root/lib/Sema/Sema.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/Sema.cpp')
-rw-r--r--lib/Sema/Sema.cpp280
1 files changed, 28 insertions, 252 deletions
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 171101b..38c842e 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -15,260 +15,18 @@
#include "Sema.h"
#include "TargetAttributesSema.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/APFloat.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
using namespace clang;
-
-/// Determines whether we should have an a.k.a. clause when
-/// pretty-printing a type. There are three main criteria:
-///
-/// 1) Some types provide very minimal sugar that doesn't impede the
-/// user's understanding --- for example, elaborated type
-/// specifiers. If this is all the sugar we see, we don't want an
-/// a.k.a. clause.
-/// 2) Some types are technically sugared but are much more familiar
-/// when seen in their sugared form --- for example, va_list,
-/// vector types, and the magic Objective C types. We don't
-/// want to desugar these, even if we do produce an a.k.a. clause.
-/// 3) Some types may have already been desugared previously in this diagnostic.
-/// if this is the case, doing another "aka" would just be clutter.
-///
-static bool ShouldAKA(ASTContext &Context, QualType QT,
- const Diagnostic::ArgumentValue *PrevArgs,
- unsigned NumPrevArgs,
- QualType &DesugaredQT) {
- QualType InputTy = QT;
-
- bool AKA = false;
- QualifierCollector Qc;
-
- while (true) {
- const Type *Ty = Qc.strip(QT);
-
- // Don't aka just because we saw an elaborated type...
- if (isa<ElaboratedType>(Ty)) {
- QT = cast<ElaboratedType>(Ty)->desugar();
- continue;
- }
-
- // ...or a qualified name type...
- if (isa<QualifiedNameType>(Ty)) {
- QT = cast<QualifiedNameType>(Ty)->desugar();
- continue;
- }
-
- // ...or a substituted template type parameter.
- if (isa<SubstTemplateTypeParmType>(Ty)) {
- QT = cast<SubstTemplateTypeParmType>(Ty)->desugar();
- continue;
- }
-
- // Don't desugar template specializations.
- if (isa<TemplateSpecializationType>(Ty))
- break;
-
- // Don't desugar magic Objective-C types.
- if (QualType(Ty,0) == Context.getObjCIdType() ||
- QualType(Ty,0) == Context.getObjCClassType() ||
- QualType(Ty,0) == Context.getObjCSelType() ||
- QualType(Ty,0) == Context.getObjCProtoType())
- break;
-
- // Don't desugar va_list.
- if (QualType(Ty,0) == Context.getBuiltinVaListType())
- break;
-
- // Otherwise, do a single-step desugar.
- QualType Underlying;
- bool IsSugar = false;
- switch (Ty->getTypeClass()) {
-#define ABSTRACT_TYPE(Class, Base)
-#define TYPE(Class, Base) \
- case Type::Class: { \
- const Class##Type *CTy = cast<Class##Type>(Ty); \
- if (CTy->isSugared()) { \
- IsSugar = true; \
- Underlying = CTy->desugar(); \
- } \
- break; \
- }
-#include "clang/AST/TypeNodes.def"
- }
-
- // If it wasn't sugared, we're done.
- if (!IsSugar)
- break;
-
- // If the desugared type is a vector type, we don't want to expand
- // it, it will turn into an attribute mess. People want their "vec4".
- if (isa<VectorType>(Underlying))
- break;
-
- // Don't desugar through the primary typedef of an anonymous type.
- if (isa<TagType>(Underlying) && isa<TypedefType>(QT))
- if (cast<TagType>(Underlying)->getDecl()->getTypedefForAnonDecl() ==
- cast<TypedefType>(QT)->getDecl())
- break;
-
- // Otherwise, we're tearing through something opaque; note that
- // we'll eventually need an a.k.a. clause and keep going.
- AKA = true;
- QT = Underlying;
- continue;
- }
-
- // If we never tore through opaque sugar, don't print aka.
- if (!AKA) return false;
-
- // If we did, check to see if we already desugared this type in this
- // diagnostic. If so, don't do it again.
- for (unsigned i = 0; i != NumPrevArgs; ++i) {
- // TODO: Handle ak_declcontext case.
- if (PrevArgs[i].first == Diagnostic::ak_qualtype) {
- void *Ptr = (void*)PrevArgs[i].second;
- QualType PrevTy(QualType::getFromOpaquePtr(Ptr));
- if (PrevTy == InputTy)
- return false;
- }
- }
-
- DesugaredQT = Qc.apply(QT);
- return true;
-}
-
-/// \brief Convert the given type to a string suitable for printing as part of
-/// a diagnostic.
-///
-/// \param Context the context in which the type was allocated
-/// \param Ty the type to print
-static std::string
-ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
- const Diagnostic::ArgumentValue *PrevArgs,
- unsigned NumPrevArgs) {
- // FIXME: Playing with std::string is really slow.
- std::string S = Ty.getAsString(Context.PrintingPolicy);
-
- // Consider producing an a.k.a. clause if removing all the direct
- // sugar gives us something "significantly different".
-
- QualType DesugaredTy;
- if (ShouldAKA(Context, Ty, PrevArgs, NumPrevArgs, DesugaredTy)) {
- S = "'"+S+"' (aka '";
- S += DesugaredTy.getAsString(Context.PrintingPolicy);
- S += "')";
- return S;
- }
-
- S = "'" + S + "'";
- return S;
-}
-/// ConvertQualTypeToStringFn - This function is used to pretty print the
-/// specified QualType as a string in diagnostics.
-static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val,
- const char *Modifier, unsigned ModLen,
- const char *Argument, unsigned ArgLen,
- const Diagnostic::ArgumentValue *PrevArgs,
- unsigned NumPrevArgs,
- llvm::SmallVectorImpl<char> &Output,
- void *Cookie) {
- ASTContext &Context = *static_cast<ASTContext*>(Cookie);
-
- std::string S;
- bool NeedQuotes = true;
-
- switch (Kind) {
- default: assert(0 && "unknown ArgumentKind");
- case Diagnostic::ak_qualtype: {
- assert(ModLen == 0 && ArgLen == 0 &&
- "Invalid modifier for QualType argument");
-
- QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val)));
- S = ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs);
- NeedQuotes = false;
- break;
- }
- case Diagnostic::ak_declarationname: {
- DeclarationName N = DeclarationName::getFromOpaqueInteger(Val);
- S = N.getAsString();
-
- if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0)
- S = '+' + S;
- else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12) && ArgLen==0)
- S = '-' + S;
- else
- assert(ModLen == 0 && ArgLen == 0 &&
- "Invalid modifier for DeclarationName argument");
- break;
- }
- case Diagnostic::ak_nameddecl: {
- bool Qualified;
- if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0)
- Qualified = true;
- else {
- assert(ModLen == 0 && ArgLen == 0 &&
- "Invalid modifier for NamedDecl* argument");
- Qualified = false;
- }
- reinterpret_cast<NamedDecl*>(Val)->
- getNameForDiagnostic(S, Context.PrintingPolicy, Qualified);
- break;
- }
- case Diagnostic::ak_nestednamespec: {
- llvm::raw_string_ostream OS(S);
- reinterpret_cast<NestedNameSpecifier*>(Val)->print(OS,
- Context.PrintingPolicy);
- NeedQuotes = false;
- break;
- }
- case Diagnostic::ak_declcontext: {
- DeclContext *DC = reinterpret_cast<DeclContext *> (Val);
- assert(DC && "Should never have a null declaration context");
-
- if (DC->isTranslationUnit()) {
- // FIXME: Get these strings from some localized place
- if (Context.getLangOptions().CPlusPlus)
- S = "the global namespace";
- else
- S = "the global scope";
- } else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) {
- S = ConvertTypeToDiagnosticString(Context, Context.getTypeDeclType(Type),
- PrevArgs, NumPrevArgs);
- } else {
- // FIXME: Get these strings from some localized place
- NamedDecl *ND = cast<NamedDecl>(DC);
- if (isa<NamespaceDecl>(ND))
- S += "namespace ";
- else if (isa<ObjCMethodDecl>(ND))
- S += "method ";
- else if (isa<FunctionDecl>(ND))
- S += "function ";
-
- S += "'";
- ND->getNameForDiagnostic(S, Context.PrintingPolicy, true);
- S += "'";
- }
- NeedQuotes = false;
- break;
- }
- }
-
- if (NeedQuotes)
- Output.push_back('\'');
-
- Output.append(S.begin(), S.end());
-
- if (NeedQuotes)
- Output.push_back('\'');
-}
-
-
static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) {
if (C.getLangOptions().CPlusPlus)
return CXXRecordDecl::Create(C, TagDecl::TK_struct,
@@ -363,14 +121,15 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
GlobalNewDeleteDeclared(false),
CompleteTranslationUnit(CompleteTranslationUnit),
NumSFINAEErrors(0), NonInstantiationEntries(0),
- CurrentInstantiationScope(0)
+ CurrentInstantiationScope(0), TyposCorrected(0)
{
TUScope = 0;
if (getLangOptions().CPlusPlus)
FieldCollector.reset(new CXXFieldCollector());
// Tell diagnostics how to render things from the AST library.
- PP.getDiagnostics().SetArgToStringFn(ConvertArgToStringFn, &Context);
+ PP.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument,
+ &Context);
ExprEvalContexts.push_back(
ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0));
@@ -426,6 +185,12 @@ void Sema::DeleteStmt(StmtTy *S) {
/// popped.
void Sema::ActOnEndOfTranslationUnit() {
+ // Remove functions that turned out to be used.
+ UnusedStaticFuncs.erase(std::remove_if(UnusedStaticFuncs.begin(),
+ UnusedStaticFuncs.end(),
+ std::mem_fun(&FunctionDecl::isUsed)),
+ UnusedStaticFuncs.end());
+
while (1) {
// C++: Perform implicit template instantiations.
//
@@ -472,12 +237,14 @@ void Sema::ActOnEndOfTranslationUnit() {
// translation unit contains a file scope declaration of that
// identifier, with the composite type as of the end of the
// translation unit, with an initializer equal to 0.
- for (unsigned i = 0, e = TentativeDefinitionList.size(); i != e; ++i) {
- VarDecl *VD = TentativeDefinitions.lookup(TentativeDefinitionList[i]);
-
- // If the tentative definition was completed, it will be in the list, but
- // not the map.
- if (VD == 0 || VD->isInvalidDecl() || !VD->isTentativeDefinition(Context))
+ llvm::SmallSet<VarDecl *, 32> Seen;
+ for (unsigned i = 0, e = TentativeDefinitions.size(); i != e; ++i) {
+ VarDecl *VD = TentativeDefinitions[i]->getActingDefinition();
+
+ // If the tentative definition was completed, getActingDefinition() returns
+ // null. If we've already seen this variable before, insert()'s second
+ // return value is false.
+ if (VD == 0 || VD->isInvalidDecl() || !Seen.insert(VD))
continue;
if (const IncompleteArrayType *ArrayT
@@ -504,6 +271,15 @@ void Sema::ActOnEndOfTranslationUnit() {
Consumer.CompleteTentativeDefinition(VD);
}
+
+ // Output warning for unused functions.
+ for (std::vector<FunctionDecl*>::iterator
+ F = UnusedStaticFuncs.begin(),
+ FEnd = UnusedStaticFuncs.end();
+ F != FEnd;
+ ++F)
+ Diag((*F)->getLocation(), diag::warn_unused_function) << (*F)->getDeclName();
+
}
OpenPOWER on IntegriCloud