/// Parse - Analyze the specified string (e.g. "==&{eax}") and fill in the /// fields in this structure. If the constraint string is not understood, /// return true, otherwise return false. bool InlineAsm::ConstraintInfo::Parse(StringRef Str, InlineAsm::ConstraintInfoVector &ConstraintsSoFar) { StringRef::iterator I = Str.begin(), E = Str.end(); unsigned multipleAlternativeCount = Str.count('|') + 1; unsigned multipleAlternativeIndex = 0; ConstraintCodeVector *pCodes = &Codes; // Initialize isMultipleAlternative = multipleAlternativeCount > 1; if (isMultipleAlternative) { multipleAlternatives.resize(multipleAlternativeCount); pCodes = &multipleAlternatives[0].Codes; } Type = isInput; isEarlyClobber = false; MatchingInput = -1; isCommutative = false; isIndirect = false; currentAlternativeIndex = 0; // Parse prefixes. if (*I == '~') { Type = isClobber; ++I; // '{' must immediately follow '~'. if (I != E && *I != '{') return true; } else if (*I == '=') { ++I; Type = isOutput; } if (*I == '*') { isIndirect = true; ++I; } if (I == E) return true; // Just a prefix, like "==" or "~". // Parse the modifiers. bool DoneWithModifiers = false; while (!DoneWithModifiers) { switch (*I) { default: DoneWithModifiers = true; break; case '&': // Early clobber. if (Type != isOutput || // Cannot early clobber anything but output. isEarlyClobber) // Reject &&&&&& return true; isEarlyClobber = true; break; case '%': // Commutative. if (Type == isClobber || // Cannot commute clobbers. isCommutative) // Reject %%%%% return true; isCommutative = true; break; case '#': // Comment. case '*': // Register preferencing. return true; // Not supported. } if (!DoneWithModifiers) { ++I; if (I == E) return true; // Just prefixes and modifiers! } } // Parse the various constraints. while (I != E) { if (*I == '{') { // Physical register reference. // Find the end of the register name. StringRef::iterator ConstraintEnd = std::find(I+1, E, '}'); if (ConstraintEnd == E) return true; // "{foo" pCodes->push_back(StringRef(I, ConstraintEnd+1 - I)); I = ConstraintEnd+1; } else if (isdigit(static_cast<unsigned char>(*I))) { // Matching Constraint // Maximal munch numbers. StringRef::iterator NumStart = I; while (I != E && isdigit(static_cast<unsigned char>(*I))) ++I; pCodes->push_back(StringRef(NumStart, I - NumStart)); unsigned N = atoi(pCodes->back().c_str()); // Check that this is a valid matching constraint! if (N >= ConstraintsSoFar.size() || ConstraintsSoFar[N].Type != isOutput|| Type != isInput) return true; // Invalid constraint number. // If Operand N already has a matching input, reject this. An output // can't be constrained to the same value as multiple inputs. if (isMultipleAlternative) { if (multipleAlternativeIndex >= ConstraintsSoFar[N].multipleAlternatives.size()) return true; InlineAsm::SubConstraintInfo &scInfo = ConstraintsSoFar[N].multipleAlternatives[multipleAlternativeIndex]; if (scInfo.MatchingInput != -1) return true; // Note that operand #n has a matching input. scInfo.MatchingInput = ConstraintsSoFar.size(); } else { if (ConstraintsSoFar[N].hasMatchingInput() && (size_t)ConstraintsSoFar[N].MatchingInput != ConstraintsSoFar.size()) return true; // Note that operand #n has a matching input. ConstraintsSoFar[N].MatchingInput = ConstraintsSoFar.size(); } } else if (*I == '|') { multipleAlternativeIndex++; pCodes = &multipleAlternatives[multipleAlternativeIndex].Codes; ++I; } else if (*I == '^') { // Multi-letter constraint // FIXME: For now assuming these are 2-character constraints. pCodes->push_back(StringRef(I+1, 2)); I += 3; } else { // Single letter constraint. pCodes->push_back(StringRef(I, 1)); ++I; } } return false; }
void MCObjectStreamer::EmitBytes(StringRef Data) { MCLineEntry::Make(this, getCurrentSection().first); getOrCreateDataFragment()->getContents().append(Data.begin(), Data.end()); }
error_code MachOObjectFile::getRelocationTypeName(DataRefImpl Rel, SmallVectorImpl<char> &Result) const { StringRef res; uint64_t RType; getRelocationType(Rel, RType); unsigned Arch = this->getArch(); switch (Arch) { case Triple::x86: { static const char *const Table[] = { "GENERIC_RELOC_VANILLA", "GENERIC_RELOC_PAIR", "GENERIC_RELOC_SECTDIFF", "GENERIC_RELOC_PB_LA_PTR", "GENERIC_RELOC_LOCAL_SECTDIFF", "GENERIC_RELOC_TLV" }; if (RType > 5) res = "Unknown"; else res = Table[RType]; break; } case Triple::x86_64: { static const char *const Table[] = { "X86_64_RELOC_UNSIGNED", "X86_64_RELOC_SIGNED", "X86_64_RELOC_BRANCH", "X86_64_RELOC_GOT_LOAD", "X86_64_RELOC_GOT", "X86_64_RELOC_SUBTRACTOR", "X86_64_RELOC_SIGNED_1", "X86_64_RELOC_SIGNED_2", "X86_64_RELOC_SIGNED_4", "X86_64_RELOC_TLV" }; if (RType > 9) res = "Unknown"; else res = Table[RType]; break; } case Triple::arm: { static const char *const Table[] = { "ARM_RELOC_VANILLA", "ARM_RELOC_PAIR", "ARM_RELOC_SECTDIFF", "ARM_RELOC_LOCAL_SECTDIFF", "ARM_RELOC_PB_LA_PTR", "ARM_RELOC_BR24", "ARM_THUMB_RELOC_BR22", "ARM_THUMB_32BIT_BRANCH", "ARM_RELOC_HALF", "ARM_RELOC_HALF_SECTDIFF" }; if (RType > 9) res = "Unknown"; else res = Table[RType]; break; } case Triple::ppc: { static const char *const Table[] = { "PPC_RELOC_VANILLA", "PPC_RELOC_PAIR", "PPC_RELOC_BR14", "PPC_RELOC_BR24", "PPC_RELOC_HI16", "PPC_RELOC_LO16", "PPC_RELOC_HA16", "PPC_RELOC_LO14", "PPC_RELOC_SECTDIFF", "PPC_RELOC_PB_LA_PTR", "PPC_RELOC_HI16_SECTDIFF", "PPC_RELOC_LO16_SECTDIFF", "PPC_RELOC_HA16_SECTDIFF", "PPC_RELOC_JBSR", "PPC_RELOC_LO14_SECTDIFF", "PPC_RELOC_LOCAL_SECTDIFF" }; if (RType > 15) res = "Unknown"; else res = Table[RType]; break; } case Triple::UnknownArch: res = "Unknown"; break; } Result.append(res.begin(), res.end()); return object_error::success; }
void MCObjectStreamer::EmitBytes(StringRef Data) { MCLineEntry::Make(this, getCurrentSection().first); MCDataFragment *DF = getOrCreateDataFragment(); flushPendingLabels(DF, DF->getContents().size()); DF->getContents().append(Data.begin(), Data.end()); }
/// LookupFile - Lookup the specified file in this search path, returning it /// if it exists or returning null if not. const FileEntry *DirectoryLookup::LookupFile( StringRef &Filename, HeaderSearch &HS, SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, ModuleMap::KnownHeader *SuggestedModule, bool &InUserSpecifiedSystemFramework, bool &HasBeenMapped, SmallVectorImpl<char> &MappedName) const { InUserSpecifiedSystemFramework = false; HasBeenMapped = false; SmallString<1024> TmpDir; if (isNormalDir()) { // Concatenate the requested file onto the directory. TmpDir = getDir()->getName(); llvm::sys::path::append(TmpDir, Filename); if (SearchPath != NULL) { StringRef SearchPathRef(getDir()->getName()); SearchPath->clear(); SearchPath->append(SearchPathRef.begin(), SearchPathRef.end()); } if (RelativePath != NULL) { RelativePath->clear(); RelativePath->append(Filename.begin(), Filename.end()); } return getFileAndSuggestModule(HS, TmpDir.str(), getDir(), isSystemHeaderDirectory(), SuggestedModule); } if (isFramework()) return DoFrameworkLookup(Filename, HS, SearchPath, RelativePath, SuggestedModule, InUserSpecifiedSystemFramework); assert(isHeaderMap() && "Unknown directory lookup"); const HeaderMap *HM = getHeaderMap(); SmallString<1024> Path; StringRef Dest = HM->lookupFilename(Filename, Path); if (Dest.empty()) return 0; const FileEntry *Result; // Check if the headermap maps the filename to a framework include // ("Foo.h" -> "Foo/Foo.h"), in which case continue header lookup using the // framework include. if (llvm::sys::path::is_relative(Dest)) { MappedName.clear(); MappedName.append(Dest.begin(), Dest.end()); Filename = StringRef(MappedName.begin(), MappedName.size()); HasBeenMapped = true; Result = HM->LookupFile(Filename, HS.getFileMgr()); } else { Result = HS.getFileMgr().getFile(Dest); } if (Result) { if (SearchPath != NULL) { StringRef SearchPathRef(getName()); SearchPath->clear(); SearchPath->append(SearchPathRef.begin(), SearchPathRef.end()); } if (RelativePath != NULL) { RelativePath->clear(); RelativePath->append(Filename.begin(), Filename.end()); } } return Result; }
/// EvaluateValue - Evaluate the token PeekTok (and any others needed) and /// return the computed value in Result. Return true if there was an error /// parsing. This function also returns information about the form of the /// expression in DT. See above for information on what DT means. /// /// If ValueLive is false, then this value is being evaluated in a context where /// the result is not used. As such, avoid diagnostics that relate to /// evaluation. static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, bool ValueLive, Preprocessor &PP) { DT.State = DefinedTracker::Unknown; if (PeekTok.is(tok::code_completion)) { if (PP.getCodeCompletionHandler()) PP.getCodeCompletionHandler()->CodeCompletePreprocessorExpression(); PP.setCodeCompletionReached(); PP.LexNonComment(PeekTok); } // If this token's spelling is a pp-identifier, check to see if it is // 'defined' or if it is a macro. Note that we check here because many // keywords are pp-identifiers, so we can't check the kind. if (IdentifierInfo *II = PeekTok.getIdentifierInfo()) { // Handle "defined X" and "defined(X)". if (II->isStr("defined")) return(EvaluateDefined(Result, PeekTok, DT, ValueLive, PP)); // If this identifier isn't 'defined' or one of the special // preprocessor keywords and it wasn't macro expanded, it turns // into a simple 0, unless it is the C++ keyword "true", in which case it // turns into "1". if (ValueLive && II->getTokenID() != tok::kw_true && II->getTokenID() != tok::kw_false) PP.Diag(PeekTok, diag::warn_pp_undef_identifier) << II; Result.Val = II->getTokenID() == tok::kw_true; Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0. Result.setRange(PeekTok.getLocation()); PP.LexNonComment(PeekTok); return false; } switch (PeekTok.getKind()) { default: // Non-value token. PP.Diag(PeekTok, diag::err_pp_expr_bad_token_start_expr); return true; case tok::eod: case tok::r_paren: // If there is no expression, report and exit. PP.Diag(PeekTok, diag::err_pp_expected_value_in_expr); return true; case tok::numeric_constant: { SmallString<64> IntegerBuffer; bool NumberInvalid = false; StringRef Spelling = PP.getSpelling(PeekTok, IntegerBuffer, &NumberInvalid); if (NumberInvalid) return true; // a diagnostic was already reported NumericLiteralParser Literal(Spelling, PeekTok.getLocation(), PP); if (Literal.hadError) return true; // a diagnostic was already reported. if (Literal.isFloatingLiteral() || Literal.isImaginary) { PP.Diag(PeekTok, diag::err_pp_illegal_floating_literal); return true; } assert(Literal.isIntegerLiteral() && "Unknown ppnumber"); // Complain about, and drop, any ud-suffix. if (Literal.hasUDSuffix()) PP.Diag(PeekTok, diag::err_pp_invalid_udl) << /*integer*/1; // 'long long' is a C99 or C++11 feature. if (!PP.getLangOpts().C99 && Literal.isLongLong) { if (PP.getLangOpts().CPlusPlus) PP.Diag(PeekTok, PP.getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong); else PP.Diag(PeekTok, diag::ext_c99_longlong); } // Parse the integer literal into Result. if (Literal.GetIntegerValue(Result.Val)) { // Overflow parsing integer literal. if (ValueLive) PP.Diag(PeekTok, diag::warn_integer_too_large); Result.Val.setIsUnsigned(true); } else { // Set the signedness of the result to match whether there was a U suffix // or not. Result.Val.setIsUnsigned(Literal.isUnsigned); // Detect overflow based on whether the value is signed. If signed // and if the value is too large, emit a warning "integer constant is so // large that it is unsigned" e.g. on 12345678901234567890 where intmax_t // is 64-bits. if (!Literal.isUnsigned && Result.Val.isNegative()) { // Don't warn for a hex literal: 0x8000..0 shouldn't warn. if (ValueLive && Literal.getRadix() != 16) PP.Diag(PeekTok, diag::warn_integer_too_large_for_signed); Result.Val.setIsUnsigned(true); } } // Consume the token. Result.setRange(PeekTok.getLocation()); PP.LexNonComment(PeekTok); return false; } case tok::char_constant: // 'x' case tok::wide_char_constant: // L'x' case tok::utf16_char_constant: // u'x' case tok::utf32_char_constant: { // U'x' // Complain about, and drop, any ud-suffix. if (PeekTok.hasUDSuffix()) PP.Diag(PeekTok, diag::err_pp_invalid_udl) << /*character*/0; SmallString<32> CharBuffer; bool CharInvalid = false; StringRef ThisTok = PP.getSpelling(PeekTok, CharBuffer, &CharInvalid); if (CharInvalid) return true; CharLiteralParser Literal(ThisTok.begin(), ThisTok.end(), PeekTok.getLocation(), PP, PeekTok.getKind()); if (Literal.hadError()) return true; // A diagnostic was already emitted. // Character literals are always int or wchar_t, expand to intmax_t. const TargetInfo &TI = PP.getTargetInfo(); unsigned NumBits; if (Literal.isMultiChar()) NumBits = TI.getIntWidth(); else if (Literal.isWide()) NumBits = TI.getWCharWidth(); else if (Literal.isUTF16()) NumBits = TI.getChar16Width(); else if (Literal.isUTF32()) NumBits = TI.getChar32Width(); else NumBits = TI.getCharWidth(); // Set the width. llvm::APSInt Val(NumBits); // Set the value. Val = Literal.getValue(); // Set the signedness. UTF-16 and UTF-32 are always unsigned if (!Literal.isUTF16() && !Literal.isUTF32()) Val.setIsUnsigned(!PP.getLangOpts().CharIsSigned); if (Result.Val.getBitWidth() > Val.getBitWidth()) { Result.Val = Val.extend(Result.Val.getBitWidth()); } else { assert(Result.Val.getBitWidth() == Val.getBitWidth() && "intmax_t smaller than char/wchar_t?"); Result.Val = Val; } // Consume the token. Result.setRange(PeekTok.getLocation()); PP.LexNonComment(PeekTok); return false; } case tok::l_paren: { SourceLocation Start = PeekTok.getLocation(); PP.LexNonComment(PeekTok); // Eat the (. // Parse the value and if there are any binary operators involved, parse // them. if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true; // If this is a silly value like (X), which doesn't need parens, check for // !(defined X). if (PeekTok.is(tok::r_paren)) { // Just use DT unmodified as our result. } else { // Otherwise, we have something like (x+y), and we consumed '(x'. if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive, PP)) return true; if (PeekTok.isNot(tok::r_paren)) { PP.Diag(PeekTok.getLocation(), diag::err_pp_expected_rparen) << Result.getRange(); PP.Diag(Start, diag::note_matching) << "("; return true; } DT.State = DefinedTracker::Unknown; } Result.setRange(Start, PeekTok.getLocation()); PP.LexNonComment(PeekTok); // Eat the ). return false; } case tok::plus: { SourceLocation Start = PeekTok.getLocation(); // Unary plus doesn't modify the value. PP.LexNonComment(PeekTok); if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true; Result.setBegin(Start); return false; } case tok::minus: { SourceLocation Loc = PeekTok.getLocation(); PP.LexNonComment(PeekTok); if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true; Result.setBegin(Loc); // C99 6.5.3.3p3: The sign of the result matches the sign of the operand. Result.Val = -Result.Val; // -MININT is the only thing that overflows. Unsigned never overflows. bool Overflow = !Result.isUnsigned() && Result.Val.isMinSignedValue(); // If this operator is live and overflowed, report the issue. if (Overflow && ValueLive) PP.Diag(Loc, diag::warn_pp_expr_overflow) << Result.getRange(); DT.State = DefinedTracker::Unknown; return false; } case tok::tilde: { SourceLocation Start = PeekTok.getLocation(); PP.LexNonComment(PeekTok); if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true; Result.setBegin(Start); // C99 6.5.3.3p4: The sign of the result matches the sign of the operand. Result.Val = ~Result.Val; DT.State = DefinedTracker::Unknown; return false; } case tok::exclaim: { SourceLocation Start = PeekTok.getLocation(); PP.LexNonComment(PeekTok); if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true; Result.setBegin(Start); Result.Val = !Result.Val; // C99 6.5.3.3p5: The sign of the result is 'int', aka it is signed. Result.Val.setIsUnsigned(false); if (DT.State == DefinedTracker::DefinedMacro) DT.State = DefinedTracker::NotDefinedMacro; else if (DT.State == DefinedTracker::NotDefinedMacro) DT.State = DefinedTracker::DefinedMacro; return false; } // FIXME: Handle #assert } }
/// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing /// it into pieces. If the asm string is erroneous, emit errors and return /// true, otherwise return false. unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces, const ASTContext &C, unsigned &DiagOffs) const { StringRef Str = getAsmString()->getString(); const char *StrStart = Str.begin(); const char *StrEnd = Str.end(); const char *CurPtr = StrStart; // "Simple" inline asms have no constraints or operands, just convert the asm // string to escape $'s. if (isSimple()) { std::string Result; for (; CurPtr != StrEnd; ++CurPtr) { switch (*CurPtr) { case '$': Result += "$$"; break; default: Result += *CurPtr; break; } } Pieces.push_back(AsmStringPiece(Result)); return 0; } // CurStringPiece - The current string that we are building up as we scan the // asm string. std::string CurStringPiece; bool HasVariants = !C.getTargetInfo().hasNoAsmVariants(); unsigned LastAsmStringToken = 0; unsigned LastAsmStringOffset = 0; while (1) { // Done with the string? if (CurPtr == StrEnd) { if (!CurStringPiece.empty()) Pieces.push_back(AsmStringPiece(CurStringPiece)); return 0; } char CurChar = *CurPtr++; switch (CurChar) { case '$': CurStringPiece += "$$"; continue; case '{': CurStringPiece += (HasVariants ? "$(" : "{"); continue; case '|': CurStringPiece += (HasVariants ? "$|" : "|"); continue; case '}': CurStringPiece += (HasVariants ? "$)" : "}"); continue; case '%': break; default: CurStringPiece += CurChar; continue; } // Escaped "%" character in asm string. if (CurPtr == StrEnd) { // % at end of string is invalid (no escape). DiagOffs = CurPtr-StrStart-1; return diag::err_asm_invalid_escape; } // Handle escaped char and continue looping over the asm string. char EscapedChar = *CurPtr++; switch (EscapedChar) { default: break; case '%': // %% -> % case '{': // %{ -> { case '}': // %} -> } CurStringPiece += EscapedChar; continue; case '=': // %= -> Generate a unique ID. CurStringPiece += "${:uid}"; continue; } // Otherwise, we have an operand. If we have accumulated a string so far, // add it to the Pieces list. if (!CurStringPiece.empty()) { Pieces.push_back(AsmStringPiece(CurStringPiece)); CurStringPiece.clear(); } // Handle operands that have asmSymbolicName (e.g., %x[foo]) and those that // don't (e.g., %x4). 'x' following the '%' is the constraint modifier. const char *Begin = CurPtr - 1; // Points to the character following '%'. const char *Percent = Begin - 1; // Points to '%'. if (isLetter(EscapedChar)) { if (CurPtr == StrEnd) { // Premature end. DiagOffs = CurPtr-StrStart-1; return diag::err_asm_invalid_escape; } EscapedChar = *CurPtr++; } const TargetInfo &TI = C.getTargetInfo(); const SourceManager &SM = C.getSourceManager(); const LangOptions &LO = C.getLangOpts(); // Handle operands that don't have asmSymbolicName (e.g., %x4). if (isDigit(EscapedChar)) { // %n - Assembler operand n unsigned N = 0; --CurPtr; while (CurPtr != StrEnd && isDigit(*CurPtr)) N = N*10 + ((*CurPtr++)-'0'); unsigned NumOperands = getNumOutputs() + getNumPlusOperands() + getNumInputs(); if (N >= NumOperands) { DiagOffs = CurPtr-StrStart-1; return diag::err_asm_invalid_operand_number; } // Str contains "x4" (Operand without the leading %). std::string Str(Begin, CurPtr - Begin); // (BeginLoc, EndLoc) represents the range of the operand we are currently // processing. Unlike Str, the range includes the leading '%'. SourceLocation BeginLoc = getAsmString()->getLocationOfByte( Percent - StrStart, SM, LO, TI, &LastAsmStringToken, &LastAsmStringOffset); SourceLocation EndLoc = getAsmString()->getLocationOfByte( CurPtr - StrStart, SM, LO, TI, &LastAsmStringToken, &LastAsmStringOffset); Pieces.emplace_back(N, std::move(Str), BeginLoc, EndLoc); continue; } // Handle operands that have asmSymbolicName (e.g., %x[foo]). if (EscapedChar == '[') { DiagOffs = CurPtr-StrStart-1; // Find the ']'. const char *NameEnd = (const char*)memchr(CurPtr, ']', StrEnd-CurPtr); if (NameEnd == nullptr) return diag::err_asm_unterminated_symbolic_operand_name; if (NameEnd == CurPtr) return diag::err_asm_empty_symbolic_operand_name; StringRef SymbolicName(CurPtr, NameEnd - CurPtr); int N = getNamedOperand(SymbolicName); if (N == -1) { // Verify that an operand with that name exists. DiagOffs = CurPtr-StrStart; return diag::err_asm_unknown_symbolic_operand_name; } // Str contains "x[foo]" (Operand without the leading %). std::string Str(Begin, NameEnd + 1 - Begin); // (BeginLoc, EndLoc) represents the range of the operand we are currently // processing. Unlike Str, the range includes the leading '%'. SourceLocation BeginLoc = getAsmString()->getLocationOfByte( Percent - StrStart, SM, LO, TI, &LastAsmStringToken, &LastAsmStringOffset); SourceLocation EndLoc = getAsmString()->getLocationOfByte( NameEnd + 1 - StrStart, SM, LO, TI, &LastAsmStringToken, &LastAsmStringOffset); Pieces.emplace_back(N, std::move(Str), BeginLoc, EndLoc); CurPtr = NameEnd+1; continue; } DiagOffs = CurPtr-StrStart-1; return diag::err_asm_invalid_escape; } }
void MCPureStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into // MCObjectStreamer. getOrCreateDataFragment()->getContents().append(Data.begin(), Data.end()); }
/// Parse - Analyze the specified string (e.g. "==&{eax}") and fill in the /// fields in this structure. If the constraint string is not understood, /// return true, otherwise return false. bool InlineAsm::ConstraintInfo::Parse(const StringRef &Str, std::vector<InlineAsm::ConstraintInfo> &ConstraintsSoFar) { StringRef::iterator I = Str.begin(), E = Str.end(); // Initialize Type = isInput; isEarlyClobber = false; MatchingInput = -1; isCommutative = false; isIndirect = false; // Parse prefixes. if (*I == '~') { Type = isClobber; ++I; } else if (*I == '=') { ++I; Type = isOutput; } if (*I == '*') { isIndirect = true; ++I; } if (I == E) return true; // Just a prefix, like "==" or "~". // Parse the modifiers. bool DoneWithModifiers = false; while (!DoneWithModifiers) { switch (*I) { default: DoneWithModifiers = true; break; case '&': // Early clobber. if (Type != isOutput || // Cannot early clobber anything but output. isEarlyClobber) // Reject &&&&&& return true; isEarlyClobber = true; break; case '%': // Commutative. if (Type == isClobber || // Cannot commute clobbers. isCommutative) // Reject %%%%% return true; isCommutative = true; break; case '#': // Comment. case '*': // Register preferencing. return true; // Not supported. } if (!DoneWithModifiers) { ++I; if (I == E) return true; // Just prefixes and modifiers! } } // Parse the various constraints. while (I != E) { if (*I == '{') { // Physical register reference. // Find the end of the register name. StringRef::iterator ConstraintEnd = std::find(I+1, E, '}'); if (ConstraintEnd == E) return true; // "{foo" Codes.push_back(std::string(I, ConstraintEnd+1)); I = ConstraintEnd+1; } else if (isdigit(*I)) { // Matching Constraint // Maximal munch numbers. StringRef::iterator NumStart = I; while (I != E && isdigit(*I)) ++I; Codes.push_back(std::string(NumStart, I)); unsigned N = atoi(Codes.back().c_str()); // Check that this is a valid matching constraint! if (N >= ConstraintsSoFar.size() || ConstraintsSoFar[N].Type != isOutput|| Type != isInput) return true; // Invalid constraint number. // If Operand N already has a matching input, reject this. An output // can't be constrained to the same value as multiple inputs. if (ConstraintsSoFar[N].hasMatchingInput()) return true; // Note that operand #n has a matching input. ConstraintsSoFar[N].MatchingInput = ConstraintsSoFar.size(); } else { // Single letter constraint. Codes.push_back(std::string(I, I+1)); ++I; } } return false; }
/// \brief After the file has been processed, check to see if we got all of /// the expected diagnostics and check to see if there were any unexpected /// ones. bool DiagnosticVerifier::verifyFile(unsigned BufferID, bool shouldAutoApplyFixes) { using llvm::SMLoc; const SourceLoc BufferStartLoc = SM.getLocForBufferStart(BufferID); CharSourceRange EntireRange = SM.getRangeForBuffer(BufferID); StringRef InputFile = SM.extractText(EntireRange); StringRef BufferName = SM.getIdentifierForBuffer(BufferID); // Queue up all of the diagnostics, allowing us to sort them and emit them in // file order. std::vector<llvm::SMDiagnostic> Errors; unsigned PrevExpectedContinuationLine = 0; std::vector<ExpectedDiagnosticInfo> ExpectedDiagnostics; auto addError = [&](const char *Loc, std::string message, ArrayRef<llvm::SMFixIt> FixIts = {}) { auto loc = SourceLoc(SMLoc::getFromPointer(Loc)); auto diag = SM.GetMessage(loc, llvm::SourceMgr::DK_Error, message, {}, FixIts); Errors.push_back(diag); }; // Scan the memory buffer looking for expected-note/warning/error. for (size_t Match = InputFile.find("expected-"); Match != StringRef::npos; Match = InputFile.find("expected-", Match+1)) { // Process this potential match. If we fail to process it, just move on to // the next match. StringRef MatchStart = InputFile.substr(Match); const char *DiagnosticLoc = MatchStart.data(); llvm::SourceMgr::DiagKind ExpectedClassification; if (MatchStart.startswith("expected-note")) { ExpectedClassification = llvm::SourceMgr::DK_Note; MatchStart = MatchStart.substr(strlen("expected-note")); } else if (MatchStart.startswith("expected-warning")) { ExpectedClassification = llvm::SourceMgr::DK_Warning; MatchStart = MatchStart.substr(strlen("expected-warning")); } else if (MatchStart.startswith("expected-error")) { ExpectedClassification = llvm::SourceMgr::DK_Error; MatchStart = MatchStart.substr(strlen("expected-error")); } else continue; // Skip any whitespace before the {{. MatchStart = MatchStart.substr(MatchStart.find_first_not_of(" \t")); size_t TextStartIdx = MatchStart.find("{{"); if (TextStartIdx == StringRef::npos) { addError(MatchStart.data(), "expected {{ in expected-warning/note/error line"); continue; } int LineOffset = 0; if (TextStartIdx > 0 && MatchStart[0] == '@') { if (MatchStart[1] != '+' && MatchStart[1] != '-') { addError(MatchStart.data(), "expected '+'/'-' for line offset"); continue; } StringRef Offs; if (MatchStart[1] == '+') Offs = MatchStart.slice(2, TextStartIdx).rtrim(); else Offs = MatchStart.slice(1, TextStartIdx).rtrim(); size_t SpaceIndex = Offs.find(' '); if (SpaceIndex != StringRef::npos && SpaceIndex < TextStartIdx) { size_t Delta = Offs.size() - SpaceIndex; MatchStart = MatchStart.substr(TextStartIdx - Delta); TextStartIdx = Delta; Offs = Offs.slice(0, SpaceIndex); } else { MatchStart = MatchStart.substr(TextStartIdx); TextStartIdx = 0; } if (Offs.getAsInteger(10, LineOffset)) { addError(MatchStart.data(), "expected line offset before '{{'"); continue; } } ExpectedDiagnosticInfo Expected(DiagnosticLoc, ExpectedClassification); unsigned Count = 1; if (TextStartIdx > 0) { StringRef CountStr = MatchStart.substr(0, TextStartIdx).trim(); if (CountStr == "*") { Expected.mayAppear = true; } else { if (CountStr.getAsInteger(10, Count)) { addError(MatchStart.data(), "expected match count before '{{'"); continue; } if (Count == 0) { addError(MatchStart.data(), "expected positive match count before '{{'"); continue; } } // Resync up to the '{{'. MatchStart = MatchStart.substr(TextStartIdx); } size_t End = MatchStart.find("}}"); if (End == StringRef::npos) { addError(MatchStart.data(), "didn't find '}}' to match '{{' in expected-warning/note/error line"); continue; } llvm::SmallString<256> Buf; Expected.MessageRange = MatchStart.slice(2, End); Expected.MessageStr = Lexer::getEncodedStringSegment(Expected.MessageRange, Buf); if (PrevExpectedContinuationLine) Expected.LineNo = PrevExpectedContinuationLine; else Expected.LineNo = SM.getLineAndColumn( BufferStartLoc.getAdvancedLoc(MatchStart.data() - InputFile.data()), BufferID).first; Expected.LineNo += LineOffset; // Check if the next expected diagnostic should be in the same line. StringRef AfterEnd = MatchStart.substr(End + strlen("}}")); AfterEnd = AfterEnd.substr(AfterEnd.find_first_not_of(" \t")); if (AfterEnd.startswith("\\")) PrevExpectedContinuationLine = Expected.LineNo; else PrevExpectedContinuationLine = 0; // Scan for fix-its: {{10-14=replacement text}} StringRef ExtraChecks = MatchStart.substr(End+2).ltrim(" \t"); while (ExtraChecks.startswith("{{")) { // First make sure we have a closing "}}". size_t EndLoc = ExtraChecks.find("}}"); if (EndLoc == StringRef::npos) { addError(ExtraChecks.data(), "didn't find '}}' to match '{{' in fix-it verification"); break; } // Allow for close braces to appear in the replacement text. while (EndLoc+2 < ExtraChecks.size() && ExtraChecks[EndLoc+2] == '}') ++EndLoc; StringRef FixItStr = ExtraChecks.slice(2, EndLoc); // Check for matching a later "}}" on a different line. if (FixItStr.find_first_of("\r\n") != StringRef::npos) { addError(ExtraChecks.data(), "didn't find '}}' to match '{{' in " "fix-it verification"); break; } // Prepare for the next round of checks. ExtraChecks = ExtraChecks.substr(EndLoc+2).ltrim(); // Special case for specifying no fixits should appear. if (FixItStr == "none") { Expected.noFixitsMayAppear = true; continue; } // Parse the pieces of the fix-it. size_t MinusLoc = FixItStr.find('-'); if (MinusLoc == StringRef::npos) { addError(FixItStr.data(), "expected '-' in fix-it verification"); continue; } StringRef StartColStr = FixItStr.slice(0, MinusLoc); StringRef AfterMinus = FixItStr.substr(MinusLoc+1); size_t EqualLoc = AfterMinus.find('='); if (EqualLoc == StringRef::npos) { addError(AfterMinus.data(), "expected '=' after '-' in fix-it verification"); continue; } StringRef EndColStr = AfterMinus.slice(0, EqualLoc); StringRef AfterEqual = AfterMinus.substr(EqualLoc+1); ExpectedFixIt FixIt; FixIt.StartLoc = StartColStr.data()-2; FixIt.EndLoc = FixItStr.data()+EndLoc; if (StartColStr.getAsInteger(10, FixIt.StartCol)) { addError(StartColStr.data(), "invalid column number in fix-it verification"); continue; } if (EndColStr.getAsInteger(10, FixIt.EndCol)) { addError(EndColStr.data(), "invalid column number in fix-it verification"); continue; } // Translate literal "\\n" into '\n', inefficiently. StringRef fixItText = AfterEqual.slice(0, EndLoc); for (const char *current = fixItText.begin(), *end = fixItText.end(); current != end; /* in loop */) { if (*current == '\\' && current + 1 < end) { if (current[1] == 'n') { FixIt.Text += '\n'; current += 2; } else { // Handle \}, \\, etc. FixIt.Text += current[1]; current += 2; } } else { FixIt.Text += *current++; } } Expected.Fixits.push_back(FixIt); } Expected.ExpectedEnd = ExtraChecks.data(); // Don't include trailing whitespace in the expected-foo{{}} range. while (isspace(Expected.ExpectedEnd[-1])) --Expected.ExpectedEnd; // Add the diagnostic the expected number of times. for (; Count; --Count) ExpectedDiagnostics.push_back(Expected); } // Make sure all the expected diagnostics appeared. std::reverse(ExpectedDiagnostics.begin(), ExpectedDiagnostics.end()); for (unsigned i = ExpectedDiagnostics.size(); i != 0; ) { --i; auto &expected = ExpectedDiagnostics[i]; // Check to see if we had this expected diagnostic. auto FoundDiagnosticIter = findDiagnostic(expected, BufferName); if (FoundDiagnosticIter == CapturedDiagnostics.end()) { // Diagnostic didn't exist. If this is a 'mayAppear' diagnostic, then // we're ok. Otherwise, leave it in the list. if (expected.mayAppear) ExpectedDiagnostics.erase(ExpectedDiagnostics.begin()+i); continue; } auto &FoundDiagnostic = *FoundDiagnosticIter; const char *IncorrectFixit = nullptr; // Verify that any expected fix-its are present in the diagnostic. for (auto fixit : expected.Fixits) { // If we found it, we're ok. if (!checkForFixIt(fixit, FoundDiagnostic, InputFile)) IncorrectFixit = fixit.StartLoc; } // If we have any expected fixits that didn't get matched, then they are // wrong. Replace the failed fixit with what actually happened. if (IncorrectFixit) { if (FoundDiagnostic.getFixIts().empty()) { addError(IncorrectFixit, "expected fix-it not seen"); continue; } // If we had an incorrect expected fixit, render it and produce a fixit // of our own. auto actual = renderFixits(FoundDiagnostic.getFixIts(), InputFile); auto replStartLoc = SMLoc::getFromPointer(expected.Fixits[0].StartLoc); auto replEndLoc = SMLoc::getFromPointer(expected.Fixits.back().EndLoc); llvm::SMFixIt fix(llvm::SMRange(replStartLoc, replEndLoc), actual); addError(IncorrectFixit, "expected fix-it not seen; actual fix-its: " + actual, fix); } else if (expected.noFixitsMayAppear && !FoundDiagnostic.getFixIts().empty() && !expected.mayAppear) { // If there was no fixit specification, but some were produced, add a // fixit to add them in. auto actual = renderFixits(FoundDiagnostic.getFixIts(), InputFile); auto replStartLoc = SMLoc::getFromPointer(expected.ExpectedEnd - 8); // {{none}} length auto replEndLoc = SMLoc::getFromPointer(expected.ExpectedEnd - 1); llvm::SMFixIt fix(llvm::SMRange(replStartLoc, replEndLoc), actual); addError(replStartLoc.getPointer(), "expected no fix-its; actual fix-it seen: " + actual, fix); } // Actually remove the diagnostic from the list, so we don't match it // again. We do have to do this after checking fix-its, though, because // the diagnostic owns its fix-its. CapturedDiagnostics.erase(FoundDiagnosticIter); // We found the diagnostic, so remove it... unless we allow an arbitrary // number of diagnostics, in which case we want to reprocess this. if (expected.mayAppear) ++i; else ExpectedDiagnostics.erase(ExpectedDiagnostics.begin()+i); } // Check to see if we have any incorrect diagnostics. If so, diagnose them as // such. for (unsigned i = ExpectedDiagnostics.size(); i != 0; ) { --i; auto &expected = ExpectedDiagnostics[i]; // Check to see if any found diagnostics have the right line and // classification, but the wrong text. auto I = CapturedDiagnostics.begin(); for (auto E = CapturedDiagnostics.end(); I != E; ++I) { // Verify the file and line of the diagnostic. if (I->getLineNo() != (int)expected.LineNo || I->getFilename() != BufferName || I->getKind() != expected.Classification) continue; // Otherwise, we found it, break out. break; } if (I == CapturedDiagnostics.end()) continue; auto StartLoc = SMLoc::getFromPointer(expected.MessageRange.begin()); auto EndLoc = SMLoc::getFromPointer(expected.MessageRange.end()); llvm::SMFixIt fixIt(llvm::SMRange{ StartLoc, EndLoc }, I->getMessage()); addError(expected.MessageRange.begin(), "incorrect message found", fixIt); CapturedDiagnostics.erase(I); ExpectedDiagnostics.erase(ExpectedDiagnostics.begin()+i); } // Diagnose expected diagnostics that didn't appear. std::reverse(ExpectedDiagnostics.begin(), ExpectedDiagnostics.end()); for (auto const &expected : ExpectedDiagnostics) { std::string message = "expected "+getDiagKindString(expected.Classification) + " not produced"; // Get the range of the expected-foo{{}} diagnostic specifier. auto StartLoc = expected.ExpectedStart; auto EndLoc = expected.ExpectedEnd; // A very common case if for the specifier to be the last thing on the line. // In this case, eat any trailing whitespace. while (isspace(*EndLoc) && *EndLoc != '\n' && *EndLoc != '\r') ++EndLoc; // If we found the end of the line, we can do great things. Otherwise, // avoid nuking whitespace that might be zapped through other means. if (*EndLoc != '\n' && *EndLoc != '\r') { EndLoc = expected.ExpectedEnd; } else { // If we hit the end of line, then zap whitespace leading up to it. auto FileStart = InputFile.data(); while (StartLoc-1 != FileStart && isspace(StartLoc[-1]) && StartLoc[-1] != '\n' && StartLoc[-1] != '\r') --StartLoc; // If we got to the end of the line, and the thing before this diagnostic // is a "//" then we can remove it too. if (StartLoc-2 >= FileStart && StartLoc[-1] == '/' && StartLoc[-2] == '/') StartLoc -= 2; // Perform another round of general whitespace nuking to cleanup // whitespace before the //. while (StartLoc-1 != FileStart && isspace(StartLoc[-1]) && StartLoc[-1] != '\n' && StartLoc[-1] != '\r') --StartLoc; // If we found a \n, then we can nuke the entire line. if (StartLoc-1 != FileStart && (StartLoc[-1] == '\n' || StartLoc[-1] == '\r')) --StartLoc; } // Remove the expected-foo{{}} as a fixit. llvm::SMFixIt fixIt(llvm::SMRange{ SMLoc::getFromPointer(StartLoc), SMLoc::getFromPointer(EndLoc) }, ""); addError(expected.ExpectedStart, message, fixIt); } // Verify that there are no diagnostics (in MemoryBuffer) left in the list. for (unsigned i = 0, e = CapturedDiagnostics.size(); i != e; ++i) { if (CapturedDiagnostics[i].getFilename() != BufferName) continue; std::string Message = "unexpected "+getDiagKindString(CapturedDiagnostics[i].getKind())+ " produced: "+CapturedDiagnostics[i].getMessage().str(); addError(CapturedDiagnostics[i].getLoc().getPointer(), Message); } // Sort the diagnostics by their address in the memory buffer as the primary // key. This ensures that an "unexpected diagnostic" and // "expected diagnostic" in the same place are emitted next to each other. std::sort(Errors.begin(), Errors.end(), [&](const llvm::SMDiagnostic &lhs, const llvm::SMDiagnostic &rhs) -> bool { return lhs.getLoc().getPointer() < rhs.getLoc().getPointer(); }); // Emit all of the queue'd up errors. for (auto Err : Errors) SM.getLLVMSourceMgr().PrintMessage(llvm::errs(), Err); // If auto-apply fixits is on, rewrite the original source file. if (shouldAutoApplyFixes) autoApplyFixes(BufferID, Errors); return !Errors.empty(); }
OptTable::OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos) : OptionInfos(_OptionInfos), NumOptionInfos(_NumOptionInfos), TheInputOptionID(0), TheUnknownOptionID(0), FirstSearchableIndex(0) { // Explicitly zero initialize the error to work around a bug in array // value-initialization on MinGW with gcc 4.3.5. // Find start of normal options. for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { unsigned Kind = getInfo(i + 1).Kind; if (Kind == Option::InputClass) { assert(!TheInputOptionID && "Cannot have multiple input options!"); TheInputOptionID = getInfo(i + 1).ID; } else if (Kind == Option::UnknownClass) { assert(!TheUnknownOptionID && "Cannot have multiple unknown options!"); TheUnknownOptionID = getInfo(i + 1).ID; } else if (Kind != Option::GroupClass) { FirstSearchableIndex = i; break; } } assert(FirstSearchableIndex != 0 && "No searchable options?"); #ifndef NDEBUG // Check that everything after the first searchable option is a // regular option class. for (unsigned i = FirstSearchableIndex, e = getNumOptions(); i != e; ++i) { Option::OptionClass Kind = (Option::OptionClass) getInfo(i + 1).Kind; assert((Kind != Option::InputClass && Kind != Option::UnknownClass && Kind != Option::GroupClass) && "Special options should be defined first!"); } // Check that options are in order. for (unsigned i = FirstSearchableIndex+1, e = getNumOptions(); i != e; ++i) { if (!(getInfo(i) < getInfo(i + 1))) { getOption(i).dump(); getOption(i + 1).dump(); llvm_unreachable("Options are not in order!"); } } #endif // Build prefixes. for (unsigned i = FirstSearchableIndex+1, e = getNumOptions(); i != e; ++i) { if (const char *const *P = getInfo(i).Prefixes) { for (; *P != 0; ++P) { PrefixesUnion.insert(*P); } } } // Build prefix chars. for (llvm::StringSet<>::const_iterator I = PrefixesUnion.begin(), E = PrefixesUnion.end(); I != E; ++I) { StringRef Prefix = I->getKey(); for (StringRef::const_iterator C = Prefix.begin(), CE = Prefix.end(); C != CE; ++C) if (std::find(PrefixChars.begin(), PrefixChars.end(), *C) == PrefixChars.end()) PrefixChars.push_back(*C); } }
/// parseDirectiveSection: /// ::= .section identifier (',' identifier)* bool DarwinAsmParser::parseDirectiveSection(StringRef, SMLoc) { SMLoc Loc = getLexer().getLoc(); StringRef SectionName; if (getParser().parseIdentifier(SectionName)) return Error(Loc, "expected identifier after '.section' directive"); // Verify there is a following comma. if (!getLexer().is(AsmToken::Comma)) return TokError("unexpected token in '.section' directive"); std::string SectionSpec = SectionName; SectionSpec += ","; // Add all the tokens until the end of the line, ParseSectionSpecifier will // handle this. StringRef EOL = getLexer().LexUntilEndOfStatement(); SectionSpec.append(EOL.begin(), EOL.end()); Lex(); if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.section' directive"); Lex(); StringRef Segment, Section; unsigned StubSize; unsigned TAA; bool TAAParsed; std::string ErrorStr = MCSectionMachO::ParseSectionSpecifier(SectionSpec, Segment, Section, TAA, TAAParsed, StubSize); if (!ErrorStr.empty()) return Error(Loc, ErrorStr); // Issue a warning if the target is not powerpc and Section is a *coal* section. Triple TT = getParser().getContext().getObjectFileInfo()->getTargetTriple(); Triple::ArchType ArchTy = TT.getArch(); if (ArchTy != Triple::ppc && ArchTy != Triple::ppc64) { StringRef NonCoalSection = StringSwitch<StringRef>(Section) .Case("__textcoal_nt", "__text") .Case("__const_coal", "__const") .Case("__datacoal_nt", "__data") .Default(Section); if (!Section.equals(NonCoalSection)) { StringRef SectionVal(Loc.getPointer()); size_t B = SectionVal.find(',') + 1, E = SectionVal.find(',', B); SMLoc BLoc = SMLoc::getFromPointer(SectionVal.data() + B); SMLoc ELoc = SMLoc::getFromPointer(SectionVal.data() + E); getParser().Warning(Loc, "section \"" + Section + "\" is deprecated", SMRange(BLoc, ELoc)); getParser().Note(Loc, "change section name to \"" + NonCoalSection + "\"", SMRange(BLoc, ELoc)); } } // FIXME: Arch specific. bool isText = Segment == "__TEXT"; // FIXME: Hack. getStreamer().SwitchSection(getContext().getMachOSection( Segment, Section, TAA, StubSize, isText ? SectionKind::getText() : SectionKind::getData())); return false; }
/// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing /// it into pieces. If the asm string is erroneous, emit errors and return /// true, otherwise return false. unsigned AsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces, ASTContext &C, unsigned &DiagOffs) const { StringRef Str = getAsmString()->getString(); const char *StrStart = Str.begin(); const char *StrEnd = Str.end(); const char *CurPtr = StrStart; // "Simple" inline asms have no constraints or operands, just convert the asm // string to escape $'s. if (isSimple()) { std::string Result; for (; CurPtr != StrEnd; ++CurPtr) { switch (*CurPtr) { case '$': Result += "$$"; break; default: Result += *CurPtr; break; } } Pieces.push_back(AsmStringPiece(Result)); return 0; } // CurStringPiece - The current string that we are building up as we scan the // asm string. std::string CurStringPiece; bool HasVariants = !C.getTargetInfo().hasNoAsmVariants(); while (1) { // Done with the string? if (CurPtr == StrEnd) { if (!CurStringPiece.empty()) Pieces.push_back(AsmStringPiece(CurStringPiece)); return 0; } char CurChar = *CurPtr++; switch (CurChar) { case '$': CurStringPiece += "$$"; continue; case '{': CurStringPiece += (HasVariants ? "$(" : "{"); continue; case '|': CurStringPiece += (HasVariants ? "$|" : "|"); continue; case '}': CurStringPiece += (HasVariants ? "$)" : "}"); continue; case '%': break; default: CurStringPiece += CurChar; continue; } // Escaped "%" character in asm string. if (CurPtr == StrEnd) { // % at end of string is invalid (no escape). DiagOffs = CurPtr-StrStart-1; return diag::err_asm_invalid_escape; } char EscapedChar = *CurPtr++; if (EscapedChar == '%') { // %% -> % // Escaped percentage sign. CurStringPiece += '%'; continue; } if (EscapedChar == '=') { // %= -> Generate an unique ID. CurStringPiece += "${:uid}"; continue; } // Otherwise, we have an operand. If we have accumulated a string so far, // add it to the Pieces list. if (!CurStringPiece.empty()) { Pieces.push_back(AsmStringPiece(CurStringPiece)); CurStringPiece.clear(); } // Handle %x4 and %x[foo] by capturing x as the modifier character. char Modifier = '\0'; if (isalpha(EscapedChar)) { if (CurPtr == StrEnd) { // Premature end. DiagOffs = CurPtr-StrStart-1; return diag::err_asm_invalid_escape; } Modifier = EscapedChar; EscapedChar = *CurPtr++; } if (isdigit(EscapedChar)) { // %n - Assembler operand n unsigned N = 0; --CurPtr; while (CurPtr != StrEnd && isdigit(*CurPtr)) N = N*10 + ((*CurPtr++)-'0'); unsigned NumOperands = getNumOutputs() + getNumPlusOperands() + getNumInputs(); if (N >= NumOperands) { DiagOffs = CurPtr-StrStart-1; return diag::err_asm_invalid_operand_number; } Pieces.push_back(AsmStringPiece(N, Modifier)); continue; } // Handle %[foo], a symbolic operand reference. if (EscapedChar == '[') { DiagOffs = CurPtr-StrStart-1; // Find the ']'. const char *NameEnd = (const char*)memchr(CurPtr, ']', StrEnd-CurPtr); if (NameEnd == 0) return diag::err_asm_unterminated_symbolic_operand_name; if (NameEnd == CurPtr) return diag::err_asm_empty_symbolic_operand_name; StringRef SymbolicName(CurPtr, NameEnd - CurPtr); int N = getNamedOperand(SymbolicName); if (N == -1) { // Verify that an operand with that name exists. DiagOffs = CurPtr-StrStart; return diag::err_asm_unknown_symbolic_operand_name; } Pieces.push_back(AsmStringPiece(N, Modifier)); CurPtr = NameEnd+1; continue; } DiagOffs = CurPtr-StrStart-1; return diag::err_asm_invalid_escape; } }
// Returns true if S is valid as a C language identifier. bool elf::isValidCIdentifier(StringRef S) { return !S.empty() && isAlpha(S[0]) && std::all_of(S.begin() + 1, S.end(), isAlnum); }
void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, const PathDiagnosticPiece& P, unsigned num, unsigned max) { // For now, just draw a box above the line in question, and emit the // warning. FullSourceLoc Pos = P.getLocation().asLocation(); if (!Pos.isValid()) return; SourceManager &SM = R.getSourceMgr(); assert(&Pos.getManager() == &SM && "SourceManagers are different!"); std::pair<FileID, unsigned> LPosInfo = SM.getDecomposedExpansionLoc(Pos); if (LPosInfo.first != BugFileID) return; const llvm::MemoryBuffer *Buf = SM.getBuffer(LPosInfo.first); const char* FileStart = Buf->getBufferStart(); // Compute the column number. Rewind from the current position to the start // of the line. unsigned ColNo = SM.getColumnNumber(LPosInfo.first, LPosInfo.second); const char *TokInstantiationPtr =Pos.getExpansionLoc().getCharacterData(); const char *LineStart = TokInstantiationPtr-ColNo; // Compute LineEnd. const char *LineEnd = TokInstantiationPtr; const char* FileEnd = Buf->getBufferEnd(); while (*LineEnd != '\n' && LineEnd != FileEnd) ++LineEnd; // Compute the margin offset by counting tabs and non-tabs. unsigned PosNo = 0; for (const char* c = LineStart; c != TokInstantiationPtr; ++c) PosNo += *c == '\t' ? 8 : 1; // Create the html for the message. const char *Kind = nullptr; switch (P.getKind()) { case PathDiagnosticPiece::Call: llvm_unreachable("Calls should already be handled"); case PathDiagnosticPiece::Event: Kind = "Event"; break; case PathDiagnosticPiece::ControlFlow: Kind = "Control"; break; // Setting Kind to "Control" is intentional. case PathDiagnosticPiece::Macro: Kind = "Control"; break; } std::string sbuf; llvm::raw_string_ostream os(sbuf); os << "\n<tr><td class=\"num\"></td><td class=\"line\"><div id=\""; if (num == max) os << "EndPath"; else os << "Path" << num; os << "\" class=\"msg"; if (Kind) os << " msg" << Kind; os << "\" style=\"margin-left:" << PosNo << "ex"; // Output a maximum size. if (!isa<PathDiagnosticMacroPiece>(P)) { // Get the string and determining its maximum substring. const std::string& Msg = P.getString(); unsigned max_token = 0; unsigned cnt = 0; unsigned len = Msg.size(); for (std::string::const_iterator I=Msg.begin(), E=Msg.end(); I!=E; ++I) switch (*I) { default: ++cnt; continue; case ' ': case '\t': case '\n': if (cnt > max_token) max_token = cnt; cnt = 0; } if (cnt > max_token) max_token = cnt; // Determine the approximate size of the message bubble in em. unsigned em; const unsigned max_line = 120; if (max_token >= max_line) em = max_token / 2; else { unsigned characters = max_line; unsigned lines = len / max_line; if (lines > 0) { for (; characters > max_token; --characters) if (len / characters > lines) { ++characters; break; } } em = characters / 2; } if (em < max_line/2) os << "; max-width:" << em << "em"; } else os << "; max-width:100em"; os << "\">"; if (max > 1) { os << "<table class=\"msgT\"><tr><td valign=\"top\">"; os << "<div class=\"PathIndex"; if (Kind) os << " PathIndex" << Kind; os << "\">" << num << "</div>"; if (num > 1) { os << "</td><td><div class=\"PathNav\"><a href=\"#Path" << (num - 1) << "\" title=\"Previous event (" << (num - 1) << ")\">←</a></div></td>"; } os << "</td><td>"; } if (const PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(&P)) { os << "Within the expansion of the macro '"; // Get the name of the macro by relexing it. { FullSourceLoc L = MP->getLocation().asLocation().getExpansionLoc(); assert(L.isFileID()); StringRef BufferInfo = L.getBufferData(); std::pair<FileID, unsigned> LocInfo = L.getDecomposedLoc(); const char* MacroName = LocInfo.second + BufferInfo.data(); Lexer rawLexer(SM.getLocForStartOfFile(LocInfo.first), PP.getLangOpts(), BufferInfo.begin(), MacroName, BufferInfo.end()); Token TheTok; rawLexer.LexFromRawLexer(TheTok); for (unsigned i = 0, n = TheTok.getLength(); i < n; ++i) os << MacroName[i]; } os << "':\n"; if (max > 1) { os << "</td>"; if (num < max) { os << "<td><div class=\"PathNav\"><a href=\"#"; if (num == max - 1) os << "EndPath"; else os << "Path" << (num + 1); os << "\" title=\"Next event (" << (num + 1) << ")\">→</a></div></td>"; } os << "</tr></table>"; } // Within a macro piece. Write out each event. ProcessMacroPiece(os, *MP, 0); } else { os << html::EscapeText(P.getString()); if (max > 1) { os << "</td>"; if (num < max) { os << "<td><div class=\"PathNav\"><a href=\"#"; if (num == max - 1) os << "EndPath"; else os << "Path" << (num + 1); os << "\" title=\"Next event (" << (num + 1) << ")\">→</a></div></td>"; } os << "</tr></table>"; } } os << "</div></td></tr>"; // Insert the new html. unsigned DisplayPos = LineEnd - FileStart; SourceLocation Loc = SM.getLocForStartOfFile(LPosInfo.first).getLocWithOffset(DisplayPos); R.InsertTextBefore(Loc, os.str()); // Now highlight the ranges. ArrayRef<SourceRange> Ranges = P.getRanges(); for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { HighlightRange(R, LPosInfo.first, *I); } }
static StringRef copyString(llvm::BumpPtrAllocator &Allocator, StringRef Str) { char *Mem = Allocator.Allocate<char>(Str.size()); std::copy(Str.begin(), Str.end(), Mem); return StringRef(Mem, Str.size()); }
hex_pair_iterator(StringRef C) : Current(C.begin()), End(C.end()), IsDone(false) { // Initalize Pair. ++*this; }
ParsedTypeIdentity ParsedTypeIdentity::parse(const TypeContextDescriptor *type) { ParsedTypeIdentity result; // The first component is the user-facing name and (unless overridden) // the ABI name. StringRef component = type->Name.get(); result.UserFacingName = component; // If we don't have import info, we're done. if (!type->getTypeContextDescriptorFlags().hasImportInfo()) { result.FullIdentity = result.UserFacingName; return result; } // Otherwise, start parsing the import information. result.ImportInfo.emplace(); // The identity starts with the user-facing name. const char *startOfIdentity = component.begin(); const char *endOfIdentity = component.end(); #ifndef NDEBUG enum { AfterName, AfterABIName, AfterSymbolNamespace, AfterRelatedEntityName, AfterIdentity, } stage = AfterName; #endif while (true) { // Parse the next component. If it's empty, we're done. component = StringRef(component.end() + 1); if (component.empty()) break; // Update the identity bounds and assert that the identity // components are in the right order. auto kind = TypeImportComponent(component[0]); if (kind == TypeImportComponent::ABIName) { #ifndef NDEBUG assert(stage < AfterABIName); stage = AfterABIName; assert(result.UserFacingName != component.drop_front(1) && "user-facing name was same as the ABI name"); #endif startOfIdentity = component.begin() + 1; endOfIdentity = component.end(); } else if (kind == TypeImportComponent::SymbolNamespace) { #ifndef NDEBUG assert(stage < AfterSymbolNamespace); stage = AfterSymbolNamespace; #endif endOfIdentity = component.end(); } else if (kind == TypeImportComponent::RelatedEntityName) { #ifndef NDEBUG assert(stage < AfterRelatedEntityName); stage = AfterRelatedEntityName; #endif endOfIdentity = component.end(); } else { #ifndef NDEBUG // Anything else is assumed to not be part of the identity. stage = AfterIdentity; #endif } // Collect the component, whatever it is. result.ImportInfo->collect</*asserting*/true>(component); } assert(stage != AfterName && "no components?"); // Record the full identity. result.FullIdentity = StringRef(startOfIdentity, endOfIdentity - startOfIdentity); return result; }
// Implementation of StringRef hashing. hash_code llvm::hash_value(StringRef S) { return hash_combine_range(S.begin(), S.end()); }
bool MigrationContext::rewritePropertyAttribute(StringRef fromAttr, StringRef toAttr, SourceLocation atLoc) { if (atLoc.isMacroID()) return false; SourceManager &SM = Pass.Ctx.getSourceManager(); // Break down the source location. std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc); // Try to load the file buffer. bool invalidTemp = false; StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); if (invalidTemp) return false; const char *tokenBegin = file.data() + locInfo.second; // Lex from the start of the given location. Lexer lexer(SM.getLocForStartOfFile(locInfo.first), Pass.Ctx.getLangOpts(), file.begin(), tokenBegin, file.end()); Token tok; lexer.LexFromRawLexer(tok); if (tok.isNot(tok::at)) return false; lexer.LexFromRawLexer(tok); if (tok.isNot(tok::raw_identifier)) return false; if (StringRef(tok.getRawIdentifierData(), tok.getLength()) != "property") return false; lexer.LexFromRawLexer(tok); if (tok.isNot(tok::l_paren)) return false; Token BeforeTok = tok; Token AfterTok; AfterTok.startToken(); SourceLocation AttrLoc; lexer.LexFromRawLexer(tok); if (tok.is(tok::r_paren)) return false; while (1) { if (tok.isNot(tok::raw_identifier)) return false; StringRef ident(tok.getRawIdentifierData(), tok.getLength()); if (ident == fromAttr) { if (!toAttr.empty()) { Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr); return true; } // We want to remove the attribute. AttrLoc = tok.getLocation(); } do { lexer.LexFromRawLexer(tok); if (AttrLoc.isValid() && AfterTok.is(tok::unknown)) AfterTok = tok; } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren)); if (tok.is(tok::r_paren)) break; if (AttrLoc.isInvalid()) BeforeTok = tok; lexer.LexFromRawLexer(tok); } if (toAttr.empty() && AttrLoc.isValid() && AfterTok.isNot(tok::unknown)) { // We want to remove the attribute. if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::r_paren)) { Pass.TA.remove(SourceRange(BeforeTok.getLocation(), AfterTok.getLocation())); } else if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::comma)) { Pass.TA.remove(SourceRange(AttrLoc, AfterTok.getLocation())); } else { Pass.TA.remove(SourceRange(BeforeTok.getLocation(), AttrLoc)); } return true; } return false; }
void WinCOFFStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { // TODO: This is copied exactly from the MachOStreamer. Consider merging into // MCObjectStreamer? getOrCreateDataFragment()->getContents().append(Data.begin(), Data.end()); }
static int doDumpReflectionSections(std::string binaryFilename, StringRef arch) { // Note: binaryOrError and objectOrError own the memory for our ObjectFile; // once they go out of scope, we can no longer do anything. OwningBinary<Binary> binaryOwner; std::unique_ptr<llvm::object::ObjectFile> objectOwner; binaryOwner = unwrap(llvm::object::createBinary(binaryFilename)); const llvm::object::Binary *binaryFile = binaryOwner.getBinary(); // The object file we are doing lookups in -- either the binary itself, or // a particular slice of a universal binary. const ObjectFile *objectFile; if (auto o = dyn_cast<ObjectFile>(binaryFile)) { objectFile = o; } else { auto universal = cast<MachOUniversalBinary>(binaryFile); objectOwner = unwrap(universal->getObjectForArch(arch)); objectFile = objectOwner.get(); } // Field descriptor section auto fieldSectionRef = getSectionRef(objectFile, { "__swift3_fieldmd", ".swift3_fieldmd" }); if (fieldSectionRef.getObject() == nullptr) { std::cerr << binaryFilename; std::cerr << " doesn't have a field reflection section!\n"; return EXIT_FAILURE; } StringRef fieldSectionContents; fieldSectionRef.getContents(fieldSectionContents); const FieldSection fieldSection { reinterpret_cast<const void *>(fieldSectionContents.begin()), reinterpret_cast<const void *>(fieldSectionContents.end()) }; // Associated type section - optional AssociatedTypeSection associatedTypeSection {nullptr, nullptr}; auto associatedTypeSectionRef = getSectionRef(objectFile, { "__swift3_assocty", ".swift3_assocty" }); if (associatedTypeSectionRef.getObject() != nullptr) { StringRef associatedTypeSectionContents; associatedTypeSectionRef.getContents(associatedTypeSectionContents); associatedTypeSection = { reinterpret_cast<const void *>(associatedTypeSectionContents.begin()), reinterpret_cast<const void *>(associatedTypeSectionContents.end()), }; } // Builtin types section BuiltinTypeSection builtinTypeSection {nullptr, nullptr}; auto builtinTypeSectionRef = getSectionRef(objectFile, { "__swift3_builtin", ".swift3_builtin" }); if (builtinTypeSectionRef.getObject() != nullptr) { StringRef builtinTypeSectionContents; builtinTypeSectionRef.getContents(builtinTypeSectionContents); builtinTypeSection = { reinterpret_cast<const void *>(builtinTypeSectionContents.begin()), reinterpret_cast<const void *>(builtinTypeSectionContents.end()) }; } // Typeref section auto typeRefSectionRef = getSectionRef(objectFile, { "__swift3_typeref", ".swift3_typeref" }); if (typeRefSectionRef.getObject() == nullptr) { std::cerr << binaryFilename; std::cerr << " doesn't have an associated typeref section!\n"; return EXIT_FAILURE; } StringRef typeRefSectionContents; typeRefSectionRef.getContents(typeRefSectionContents); const GenericSection typeRefSection { reinterpret_cast<const void *>(typeRefSectionContents.begin()), reinterpret_cast<const void *>(typeRefSectionContents.end()) }; // Reflection strings section auto reflectionStringsSectionRef = getSectionRef(objectFile, { "__swift3_reflstr", ".swift3_reflstr" }); if (reflectionStringsSectionRef.getObject() == nullptr) { std::cerr << binaryFilename; std::cerr << " doesn't have an associated reflection strings section!\n"; return EXIT_FAILURE; } StringRef reflectionStringsSectionContents; reflectionStringsSectionRef.getContents(reflectionStringsSectionContents); const GenericSection reflectionStringsSection { reinterpret_cast<const void *>(reflectionStringsSectionContents.begin()), reinterpret_cast<const void *>(reflectionStringsSectionContents.end()) }; // Construct the reflection context auto reader = std::make_shared<InProcessMemoryReader>(); ReflectionContext<External<RuntimeTarget<8>>> RC(reader); RC.addReflectionInfo({ binaryFilename, fieldSection, associatedTypeSection, builtinTypeSection, typeRefSection, reflectionStringsSection, }); // Dump everything RC.dumpAllSections(std::cout); return EXIT_SUCCESS; }